Upstream version 11.40.277.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::Name;
67 using ::v8::Message;
68 using ::v8::MessageCallback;
69 using ::v8::Object;
70 using ::v8::ObjectTemplate;
71 using ::v8::Persistent;
72 using ::v8::Script;
73 using ::v8::StackTrace;
74 using ::v8::String;
75 using ::v8::Symbol;
76 using ::v8::TryCatch;
77 using ::v8::Undefined;
78 using ::v8::UniqueId;
79 using ::v8::V8;
80 using ::v8::Value;
81
82
83 #define THREADED_PROFILED_TEST(Name)                                 \
84   static void Test##Name();                                          \
85   TEST(Name##WithProfiler) {                                         \
86     RunWithProfiler(&Test##Name);                                    \
87   }                                                                  \
88   THREADED_TEST(Name)
89
90
91 void RunWithProfiler(void (*test)()) {
92   LocalContext env;
93   v8::HandleScope scope(env->GetIsolate());
94   v8::Local<v8::String> profile_name =
95       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
96   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
97
98   cpu_profiler->StartProfiling(profile_name);
99   (*test)();
100   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
101 }
102
103
104 static int signature_callback_count;
105 static Local<Value> signature_expected_receiver;
106 static void IncrementingSignatureCallback(
107     const v8::FunctionCallbackInfo<v8::Value>& args) {
108   ApiTestFuzzer::Fuzz();
109   signature_callback_count++;
110   CHECK_EQ(signature_expected_receiver, args.Holder());
111   CHECK_EQ(signature_expected_receiver, args.This());
112   v8::Handle<v8::Array> result =
113       v8::Array::New(args.GetIsolate(), args.Length());
114   for (int i = 0; i < args.Length(); i++)
115     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
116   args.GetReturnValue().Set(result);
117 }
118
119
120 static void SignatureCallback(
121     const v8::FunctionCallbackInfo<v8::Value>& args) {
122   ApiTestFuzzer::Fuzz();
123   v8::Handle<v8::Array> result =
124       v8::Array::New(args.GetIsolate(), args.Length());
125   for (int i = 0; i < args.Length(); i++) {
126     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
127   }
128   args.GetReturnValue().Set(result);
129 }
130
131
132 // Tests that call v8::V8::Dispose() cannot be threaded.
133 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
134   CHECK(v8::V8::Initialize());
135   CHECK(v8::V8::Dispose());
136 }
137
138
139 // Tests that call v8::V8::Dispose() cannot be threaded.
140 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
141   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
142   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
143   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
144   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
145   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
146 }
147
148
149 THREADED_TEST(Handles) {
150   v8::HandleScope scope(CcTest::isolate());
151   Local<Context> local_env;
152   {
153     LocalContext env;
154     local_env = env.local();
155   }
156
157   // Local context should still be live.
158   CHECK(!local_env.IsEmpty());
159   local_env->Enter();
160
161   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
162   CHECK(!undef.IsEmpty());
163   CHECK(undef->IsUndefined());
164
165   const char* source = "1 + 2 + 3";
166   Local<Script> script = v8_compile(source);
167   CHECK_EQ(6, script->Run()->Int32Value());
168
169   local_env->Exit();
170 }
171
172
173 THREADED_TEST(IsolateOfContext) {
174   v8::HandleScope scope(CcTest::isolate());
175   v8::Handle<Context> env = Context::New(CcTest::isolate());
176
177   CHECK(!env->GetIsolate()->InContext());
178   CHECK(env->GetIsolate() == CcTest::isolate());
179   env->Enter();
180   CHECK(env->GetIsolate()->InContext());
181   CHECK(env->GetIsolate() == CcTest::isolate());
182   env->Exit();
183   CHECK(!env->GetIsolate()->InContext());
184   CHECK(env->GetIsolate() == CcTest::isolate());
185 }
186
187
188 static void TestSignature(const char* loop_js, Local<Value> receiver) {
189   i::ScopedVector<char> source(200);
190   i::SNPrintF(source,
191               "for (var i = 0; i < 10; i++) {"
192               "  %s"
193               "}",
194               loop_js);
195   signature_callback_count = 0;
196   signature_expected_receiver = receiver;
197   bool expected_to_throw = receiver.IsEmpty();
198   v8::TryCatch try_catch;
199   CompileRun(source.start());
200   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
201   if (!expected_to_throw) {
202     CHECK_EQ(10, signature_callback_count);
203   } else {
204     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
205              try_catch.Exception()->ToString());
206   }
207 }
208
209
210 THREADED_TEST(ReceiverSignature) {
211   LocalContext env;
212   v8::Isolate* isolate = env->GetIsolate();
213   v8::HandleScope scope(isolate);
214   // Setup templates.
215   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
216   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
217   v8::Handle<v8::FunctionTemplate> callback_sig =
218       v8::FunctionTemplate::New(
219           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
220   v8::Handle<v8::FunctionTemplate> callback =
221       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
222   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
223   sub_fun->Inherit(fun);
224   v8::Handle<v8::FunctionTemplate> unrel_fun =
225       v8::FunctionTemplate::New(isolate);
226   // Install properties.
227   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
228   fun_proto->Set(v8_str("prop_sig"), callback_sig);
229   fun_proto->Set(v8_str("prop"), callback);
230   fun_proto->SetAccessorProperty(
231       v8_str("accessor_sig"), callback_sig, callback_sig);
232   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
233   // Instantiate templates.
234   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
235   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
236   // Setup global variables.
237   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
238   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
239   env->Global()->Set(v8_str("fun_instance"), fun_instance);
240   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
241   CompileRun(
242       "var accessor_sig_key = 'accessor_sig';"
243       "var accessor_key = 'accessor';"
244       "var prop_sig_key = 'prop_sig';"
245       "var prop_key = 'prop';"
246       ""
247       "function copy_props(obj) {"
248       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
249       "  var source = Fun.prototype;"
250       "  for (var i in keys) {"
251       "    var key = keys[i];"
252       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
253       "    Object.defineProperty(obj, key, desc);"
254       "  }"
255       "}"
256       ""
257       "var obj = {};"
258       "copy_props(obj);"
259       "var unrel = new UnrelFun();"
260       "copy_props(unrel);");
261   // Test with and without ICs
262   const char* test_objects[] = {
263       "fun_instance", "sub_fun_instance", "obj", "unrel" };
264   unsigned bad_signature_start_offset = 2;
265   for (unsigned i = 0; i < arraysize(test_objects); i++) {
266     i::ScopedVector<char> source(200);
267     i::SNPrintF(
268         source, "var test_object = %s; test_object", test_objects[i]);
269     Local<Value> test_object = CompileRun(source.start());
270     TestSignature("test_object.prop();", test_object);
271     TestSignature("test_object.accessor;", test_object);
272     TestSignature("test_object[accessor_key];", test_object);
273     TestSignature("test_object.accessor = 1;", test_object);
274     TestSignature("test_object[accessor_key] = 1;", test_object);
275     if (i >= bad_signature_start_offset) test_object = Local<Value>();
276     TestSignature("test_object.prop_sig();", test_object);
277     TestSignature("test_object.accessor_sig;", test_object);
278     TestSignature("test_object[accessor_sig_key];", test_object);
279     TestSignature("test_object.accessor_sig = 1;", test_object);
280     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
281   }
282 }
283
284
285 THREADED_TEST(ArgumentSignature) {
286   LocalContext env;
287   v8::Isolate* isolate = env->GetIsolate();
288   v8::HandleScope scope(isolate);
289   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
290   cons->SetClassName(v8_str("Cons"));
291   v8::Handle<v8::Signature> sig = v8::Signature::New(
292       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
293   v8::Handle<v8::FunctionTemplate> fun =
294       v8::FunctionTemplate::New(isolate,
295                                 SignatureCallback,
296                                 v8::Handle<Value>(),
297                                 sig);
298   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
299   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
300
301   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
302   CHECK(value1->IsTrue());
303
304   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
305   CHECK(value2->IsTrue());
306
307   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
308   CHECK(value3->IsTrue());
309
310   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
311   cons1->SetClassName(v8_str("Cons1"));
312   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
313   cons2->SetClassName(v8_str("Cons2"));
314   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
315   cons3->SetClassName(v8_str("Cons3"));
316
317   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
318   v8::Handle<v8::Signature> wsig = v8::Signature::New(
319       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
320   v8::Handle<v8::FunctionTemplate> fun2 =
321       v8::FunctionTemplate::New(isolate,
322                                 SignatureCallback,
323                                 v8::Handle<Value>(),
324                                 wsig);
325
326   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
327   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
328   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
329   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
330   v8::Handle<Value> value4 = CompileRun(
331       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
332       "'[object Cons1],[object Cons2],[object Cons3]'");
333   CHECK(value4->IsTrue());
334
335   v8::Handle<Value> value5 = CompileRun(
336       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
337   CHECK(value5->IsTrue());
338
339   v8::Handle<Value> value6 = CompileRun(
340       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
341   CHECK(value6->IsTrue());
342
343   v8::Handle<Value> value7 = CompileRun(
344       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
345       "'[object Cons1],[object Cons2],[object Cons3],d';");
346   CHECK(value7->IsTrue());
347
348   v8::Handle<Value> value8 = CompileRun(
349       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
350   CHECK(value8->IsTrue());
351 }
352
353
354 THREADED_TEST(HulIgennem) {
355   LocalContext env;
356   v8::Isolate* isolate = env->GetIsolate();
357   v8::HandleScope scope(isolate);
358   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
359   Local<String> undef_str = undef->ToString();
360   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
361   undef_str->WriteUtf8(value);
362   CHECK_EQ(0, strcmp(value, "undefined"));
363   i::DeleteArray(value);
364 }
365
366
367 THREADED_TEST(Access) {
368   LocalContext env;
369   v8::Isolate* isolate = env->GetIsolate();
370   v8::HandleScope scope(isolate);
371   Local<v8::Object> obj = v8::Object::New(isolate);
372   Local<Value> foo_before = obj->Get(v8_str("foo"));
373   CHECK(foo_before->IsUndefined());
374   Local<String> bar_str = v8_str("bar");
375   obj->Set(v8_str("foo"), bar_str);
376   Local<Value> foo_after = obj->Get(v8_str("foo"));
377   CHECK(!foo_after->IsUndefined());
378   CHECK(foo_after->IsString());
379   CHECK_EQ(bar_str, foo_after);
380 }
381
382
383 THREADED_TEST(AccessElement) {
384   LocalContext env;
385   v8::HandleScope scope(env->GetIsolate());
386   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
387   Local<Value> before = obj->Get(1);
388   CHECK(before->IsUndefined());
389   Local<String> bar_str = v8_str("bar");
390   obj->Set(1, bar_str);
391   Local<Value> after = obj->Get(1);
392   CHECK(!after->IsUndefined());
393   CHECK(after->IsString());
394   CHECK_EQ(bar_str, after);
395
396   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
397   CHECK_EQ(v8_str("a"), value->Get(0));
398   CHECK_EQ(v8_str("b"), value->Get(1));
399 }
400
401
402 THREADED_TEST(Script) {
403   LocalContext env;
404   v8::HandleScope scope(env->GetIsolate());
405   const char* source = "1 + 2 + 3";
406   Local<Script> script = v8_compile(source);
407   CHECK_EQ(6, script->Run()->Int32Value());
408 }
409
410
411 class TestResource: public String::ExternalStringResource {
412  public:
413   explicit TestResource(uint16_t* data, int* counter = NULL,
414                         bool owning_data = true)
415       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
416     while (data[length_]) ++length_;
417   }
418
419   ~TestResource() {
420     if (owning_data_) i::DeleteArray(data_);
421     if (counter_ != NULL) ++*counter_;
422   }
423
424   const uint16_t* data() const {
425     return data_;
426   }
427
428   size_t length() const {
429     return length_;
430   }
431
432  private:
433   uint16_t* data_;
434   size_t length_;
435   int* counter_;
436   bool owning_data_;
437 };
438
439
440 class TestOneByteResource : public String::ExternalOneByteStringResource {
441  public:
442   explicit TestOneByteResource(const char* data, int* counter = NULL,
443                                size_t offset = 0)
444       : orig_data_(data),
445         data_(data + offset),
446         length_(strlen(data) - offset),
447         counter_(counter) {}
448
449   ~TestOneByteResource() {
450     i::DeleteArray(orig_data_);
451     if (counter_ != NULL) ++*counter_;
452   }
453
454   const char* data() const {
455     return data_;
456   }
457
458   size_t length() const {
459     return length_;
460   }
461
462  private:
463   const char* orig_data_;
464   const char* data_;
465   size_t length_;
466   int* counter_;
467 };
468
469
470 THREADED_TEST(ScriptUsingStringResource) {
471   int dispose_count = 0;
472   const char* c_source = "1 + 2 * 3";
473   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
474   {
475     LocalContext env;
476     v8::HandleScope scope(env->GetIsolate());
477     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
478     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
479     Local<Script> script = v8_compile(source);
480     Local<Value> value = script->Run();
481     CHECK(value->IsNumber());
482     CHECK_EQ(7, value->Int32Value());
483     CHECK(source->IsExternal());
484     CHECK_EQ(resource,
485              static_cast<TestResource*>(source->GetExternalStringResource()));
486     String::Encoding encoding = String::UNKNOWN_ENCODING;
487     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
488              source->GetExternalStringResourceBase(&encoding));
489     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
490     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
491     CHECK_EQ(0, dispose_count);
492   }
493   CcTest::i_isolate()->compilation_cache()->Clear();
494   CcTest::heap()->CollectAllAvailableGarbage();
495   CHECK_EQ(1, dispose_count);
496 }
497
498
499 THREADED_TEST(ScriptUsingOneByteStringResource) {
500   int dispose_count = 0;
501   const char* c_source = "1 + 2 * 3";
502   {
503     LocalContext env;
504     v8::HandleScope scope(env->GetIsolate());
505     TestOneByteResource* resource =
506         new TestOneByteResource(i::StrDup(c_source), &dispose_count);
507     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
508     CHECK(source->IsExternalOneByte());
509     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
510              source->GetExternalOneByteStringResource());
511     String::Encoding encoding = String::UNKNOWN_ENCODING;
512     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
513              source->GetExternalStringResourceBase(&encoding));
514     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
515     Local<Script> script = v8_compile(source);
516     Local<Value> value = script->Run();
517     CHECK(value->IsNumber());
518     CHECK_EQ(7, value->Int32Value());
519     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
520     CHECK_EQ(0, dispose_count);
521   }
522   CcTest::i_isolate()->compilation_cache()->Clear();
523   CcTest::heap()->CollectAllAvailableGarbage();
524   CHECK_EQ(1, dispose_count);
525 }
526
527
528 THREADED_TEST(ScriptMakingExternalString) {
529   int dispose_count = 0;
530   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
531   {
532     LocalContext env;
533     v8::HandleScope scope(env->GetIsolate());
534     Local<String> source =
535         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
536     // Trigger GCs so that the newly allocated string moves to old gen.
537     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
538     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
539     CHECK_EQ(source->IsExternal(), false);
540     CHECK_EQ(source->IsExternalOneByte(), false);
541     String::Encoding encoding = String::UNKNOWN_ENCODING;
542     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
543     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
544     bool success = source->MakeExternal(new TestResource(two_byte_source,
545                                                          &dispose_count));
546     CHECK(success);
547     Local<Script> script = v8_compile(source);
548     Local<Value> value = script->Run();
549     CHECK(value->IsNumber());
550     CHECK_EQ(7, value->Int32Value());
551     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
552     CHECK_EQ(0, dispose_count);
553   }
554   CcTest::i_isolate()->compilation_cache()->Clear();
555   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
556   CHECK_EQ(1, dispose_count);
557 }
558
559
560 THREADED_TEST(ScriptMakingExternalOneByteString) {
561   int dispose_count = 0;
562   const char* c_source = "1 + 2 * 3";
563   {
564     LocalContext env;
565     v8::HandleScope scope(env->GetIsolate());
566     Local<String> source = v8_str(c_source);
567     // Trigger GCs so that the newly allocated string moves to old gen.
568     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
569     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
570     bool success = source->MakeExternal(
571         new TestOneByteResource(i::StrDup(c_source), &dispose_count));
572     CHECK(success);
573     Local<Script> script = v8_compile(source);
574     Local<Value> value = script->Run();
575     CHECK(value->IsNumber());
576     CHECK_EQ(7, value->Int32Value());
577     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
578     CHECK_EQ(0, dispose_count);
579   }
580   CcTest::i_isolate()->compilation_cache()->Clear();
581   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
582   CHECK_EQ(1, dispose_count);
583 }
584
585
586 TEST(MakingExternalStringConditions) {
587   LocalContext env;
588   v8::HandleScope scope(env->GetIsolate());
589
590   // Free some space in the new space so that we can check freshness.
591   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
592   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
593
594   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
595   Local<String> small_string =
596       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
597   i::DeleteArray(two_byte_string);
598
599   // We should refuse to externalize newly created small string.
600   CHECK(!small_string->CanMakeExternal());
601   // Trigger GCs so that the newly allocated string moves to old gen.
602   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
603   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
604   // Old space strings should be accepted.
605   CHECK(small_string->CanMakeExternal());
606
607   two_byte_string = AsciiToTwoByteString("small string 2");
608   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
609   i::DeleteArray(two_byte_string);
610
611   // We should refuse externalizing newly created small string.
612   CHECK(!small_string->CanMakeExternal());
613   for (int i = 0; i < 100; i++) {
614     String::Value value(small_string);
615   }
616   // Frequently used strings should be accepted.
617   CHECK(small_string->CanMakeExternal());
618
619   const int buf_size = 10 * 1024;
620   char* buf = i::NewArray<char>(buf_size);
621   memset(buf, 'a', buf_size);
622   buf[buf_size - 1] = '\0';
623
624   two_byte_string = AsciiToTwoByteString(buf);
625   Local<String> large_string =
626       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
627   i::DeleteArray(buf);
628   i::DeleteArray(two_byte_string);
629   // Large strings should be immediately accepted.
630   CHECK(large_string->CanMakeExternal());
631 }
632
633
634 TEST(MakingExternalOneByteStringConditions) {
635   LocalContext env;
636   v8::HandleScope scope(env->GetIsolate());
637
638   // Free some space in the new space so that we can check freshness.
639   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
640   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641
642   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
643   // We should refuse to externalize newly created small string.
644   CHECK(!small_string->CanMakeExternal());
645   // Trigger GCs so that the newly allocated string moves to old gen.
646   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
647   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
648   // Old space strings should be accepted.
649   CHECK(small_string->CanMakeExternal());
650
651   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
652   // We should refuse externalizing newly created small string.
653   CHECK(!small_string->CanMakeExternal());
654   for (int i = 0; i < 100; i++) {
655     String::Value value(small_string);
656   }
657   // Frequently used strings should be accepted.
658   CHECK(small_string->CanMakeExternal());
659
660   const int buf_size = 10 * 1024;
661   char* buf = i::NewArray<char>(buf_size);
662   memset(buf, 'a', buf_size);
663   buf[buf_size - 1] = '\0';
664   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
665   i::DeleteArray(buf);
666   // Large strings should be immediately accepted.
667   CHECK(large_string->CanMakeExternal());
668 }
669
670
671 TEST(MakingExternalUnalignedOneByteString) {
672   LocalContext env;
673   v8::HandleScope scope(env->GetIsolate());
674
675   CompileRun("function cons(a, b) { return a + b; }"
676              "function slice(a) { return a.substring(1); }");
677   // Create a cons string that will land in old pointer space.
678   Local<String> cons = Local<String>::Cast(CompileRun(
679       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
680   // Create a sliced string that will land in old pointer space.
681   Local<String> slice = Local<String>::Cast(CompileRun(
682       "slice('abcdefghijklmnopqrstuvwxyz');"));
683
684   // Trigger GCs so that the newly allocated string moves to old gen.
685   SimulateFullSpace(CcTest::heap()->old_pointer_space());
686   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
687   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
688
689   // Turn into external string with unaligned resource data.
690   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
691   bool success =
692       cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
693   CHECK(success);
694   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
695   success =
696       slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
697   CHECK(success);
698
699   // Trigger GCs and force evacuation.
700   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
701   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
702 }
703
704
705 THREADED_TEST(UsingExternalString) {
706   i::Factory* factory = CcTest::i_isolate()->factory();
707   {
708     v8::HandleScope scope(CcTest::isolate());
709     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
710     Local<String> string = String::NewExternal(
711         CcTest::isolate(), new TestResource(two_byte_string));
712     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
713     // Trigger GCs so that the newly allocated string moves to old gen.
714     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
715     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
716     i::Handle<i::String> isymbol =
717         factory->InternalizeString(istring);
718     CHECK(isymbol->IsInternalizedString());
719   }
720   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
721   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
722 }
723
724
725 THREADED_TEST(UsingExternalOneByteString) {
726   i::Factory* factory = CcTest::i_isolate()->factory();
727   {
728     v8::HandleScope scope(CcTest::isolate());
729     const char* one_byte_string = "test string";
730     Local<String> string = String::NewExternal(
731         CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
732     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
733     // Trigger GCs so that the newly allocated string moves to old gen.
734     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
735     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
736     i::Handle<i::String> isymbol =
737         factory->InternalizeString(istring);
738     CHECK(isymbol->IsInternalizedString());
739   }
740   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
741   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
742 }
743
744
745 class DummyResource : public v8::String::ExternalStringResource {
746  public:
747   virtual const uint16_t* data() const { return string_; }
748   virtual size_t length() const { return 1 << 30; }
749
750  private:
751   uint16_t string_[10];
752 };
753
754
755 class DummyOneByteResource : public v8::String::ExternalOneByteStringResource {
756  public:
757   virtual const char* data() const { return string_; }
758   virtual size_t length() const { return 1 << 30; }
759
760  private:
761   char string_[10];
762 };
763
764
765 THREADED_TEST(NewExternalForVeryLongString) {
766   {
767     LocalContext env;
768     v8::HandleScope scope(env->GetIsolate());
769     v8::TryCatch try_catch;
770     DummyOneByteResource r;
771     v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
772     CHECK(str.IsEmpty());
773     CHECK(try_catch.HasCaught());
774     String::Utf8Value exception_value(try_catch.Exception());
775     CHECK_EQ("RangeError: Invalid string length", *exception_value);
776   }
777
778   {
779     LocalContext env;
780     v8::HandleScope scope(env->GetIsolate());
781     v8::TryCatch try_catch;
782     DummyResource r;
783     v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
784     CHECK(str.IsEmpty());
785     CHECK(try_catch.HasCaught());
786     String::Utf8Value exception_value(try_catch.Exception());
787     CHECK_EQ("RangeError: Invalid string length", *exception_value);
788   }
789 }
790
791
792 THREADED_TEST(ScavengeExternalString) {
793   i::FLAG_stress_compaction = false;
794   i::FLAG_gc_global = false;
795   int dispose_count = 0;
796   bool in_new_space = false;
797   {
798     v8::HandleScope scope(CcTest::isolate());
799     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
800     Local<String> string = String::NewExternal(
801         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
802     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
803     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
804     in_new_space = CcTest::heap()->InNewSpace(*istring);
805     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
806     CHECK_EQ(0, dispose_count);
807   }
808   CcTest::heap()->CollectGarbage(
809       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
810   CHECK_EQ(1, dispose_count);
811 }
812
813
814 THREADED_TEST(ScavengeExternalOneByteString) {
815   i::FLAG_stress_compaction = false;
816   i::FLAG_gc_global = false;
817   int dispose_count = 0;
818   bool in_new_space = false;
819   {
820     v8::HandleScope scope(CcTest::isolate());
821     const char* one_byte_string = "test string";
822     Local<String> string = String::NewExternal(
823         CcTest::isolate(),
824         new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
825     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
826     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
827     in_new_space = CcTest::heap()->InNewSpace(*istring);
828     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
829     CHECK_EQ(0, dispose_count);
830   }
831   CcTest::heap()->CollectGarbage(
832       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
833   CHECK_EQ(1, dispose_count);
834 }
835
836
837 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
838  public:
839   // Only used by non-threaded tests, so it can use static fields.
840   static int dispose_calls;
841   static int dispose_count;
842
843   TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
844       : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
845
846   void Dispose() {
847     ++dispose_calls;
848     if (dispose_) delete this;
849   }
850  private:
851   bool dispose_;
852 };
853
854
855 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
856 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
857
858
859 TEST(ExternalStringWithDisposeHandling) {
860   const char* c_source = "1 + 2 * 3";
861
862   // Use a stack allocated external string resource allocated object.
863   TestOneByteResourceWithDisposeControl::dispose_count = 0;
864   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
865   TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
866   {
867     LocalContext env;
868     v8::HandleScope scope(env->GetIsolate());
869     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
870     Local<Script> script = v8_compile(source);
871     Local<Value> value = script->Run();
872     CHECK(value->IsNumber());
873     CHECK_EQ(7, value->Int32Value());
874     CcTest::heap()->CollectAllAvailableGarbage();
875     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
876   }
877   CcTest::i_isolate()->compilation_cache()->Clear();
878   CcTest::heap()->CollectAllAvailableGarbage();
879   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
880   CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
881
882   // Use a heap allocated external string resource allocated object.
883   TestOneByteResourceWithDisposeControl::dispose_count = 0;
884   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
885   TestOneByteResource* res_heap =
886       new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
887   {
888     LocalContext env;
889     v8::HandleScope scope(env->GetIsolate());
890     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
891     Local<Script> script = v8_compile(source);
892     Local<Value> value = script->Run();
893     CHECK(value->IsNumber());
894     CHECK_EQ(7, value->Int32Value());
895     CcTest::heap()->CollectAllAvailableGarbage();
896     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
897   }
898   CcTest::i_isolate()->compilation_cache()->Clear();
899   CcTest::heap()->CollectAllAvailableGarbage();
900   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
901   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
902 }
903
904
905 THREADED_TEST(StringConcat) {
906   {
907     LocalContext env;
908     v8::HandleScope scope(env->GetIsolate());
909     const char* one_byte_string_1 = "function a_times_t";
910     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
911     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
912     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
913     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
914     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
915     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
916     Local<String> left = v8_str(one_byte_string_1);
917
918     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
919     Local<String> right =
920         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
921     i::DeleteArray(two_byte_source);
922
923     Local<String> source = String::Concat(left, right);
924     right = String::NewExternal(
925         env->GetIsolate(),
926         new TestOneByteResource(i::StrDup(one_byte_extern_1)));
927     source = String::Concat(source, right);
928     right = String::NewExternal(
929         env->GetIsolate(),
930         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
931     source = String::Concat(source, right);
932     right = v8_str(one_byte_string_2);
933     source = String::Concat(source, right);
934
935     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
936     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
937     i::DeleteArray(two_byte_source);
938
939     source = String::Concat(source, right);
940     right = String::NewExternal(
941         env->GetIsolate(),
942         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
943     source = String::Concat(source, right);
944     Local<Script> script = v8_compile(source);
945     Local<Value> value = script->Run();
946     CHECK(value->IsNumber());
947     CHECK_EQ(68, value->Int32Value());
948   }
949   CcTest::i_isolate()->compilation_cache()->Clear();
950   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
951   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
952 }
953
954
955 THREADED_TEST(GlobalProperties) {
956   LocalContext env;
957   v8::HandleScope scope(env->GetIsolate());
958   v8::Handle<v8::Object> global = env->Global();
959   global->Set(v8_str("pi"), v8_num(3.1415926));
960   Local<Value> pi = global->Get(v8_str("pi"));
961   CHECK_EQ(3.1415926, pi->NumberValue());
962 }
963
964
965 template<typename T>
966 static void CheckReturnValue(const T& t, i::Address callback) {
967   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
968   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
969   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
970   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
971   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
972   // Verify reset
973   bool is_runtime = (*o)->IsTheHole();
974   rv.Set(true);
975   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
976   rv.Set(v8::Handle<v8::Object>());
977   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
978   CHECK_EQ(is_runtime, (*o)->IsTheHole());
979
980   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
981   // If CPU profiler is active check that when API callback is invoked
982   // VMState is set to EXTERNAL.
983   if (isolate->cpu_profiler()->is_profiling()) {
984     CHECK_EQ(v8::EXTERNAL, isolate->current_vm_state());
985     CHECK(isolate->external_callback_scope());
986     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
987   }
988 }
989
990
991 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
992                                  i::Address callback) {
993   ApiTestFuzzer::Fuzz();
994   CheckReturnValue(info, callback);
995   info.GetReturnValue().Set(v8_str("bad value"));
996   info.GetReturnValue().Set(v8_num(102));
997 }
998
999
1000 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1001   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1002 }
1003
1004
1005 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1006   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1007 }
1008
1009 static void construct_callback(
1010     const v8::FunctionCallbackInfo<Value>& info) {
1011   ApiTestFuzzer::Fuzz();
1012   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1013   info.This()->Set(v8_str("x"), v8_num(1));
1014   info.This()->Set(v8_str("y"), v8_num(2));
1015   info.GetReturnValue().Set(v8_str("bad value"));
1016   info.GetReturnValue().Set(info.This());
1017 }
1018
1019
1020 static void Return239Callback(
1021     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1022   ApiTestFuzzer::Fuzz();
1023   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1024   info.GetReturnValue().Set(v8_str("bad value"));
1025   info.GetReturnValue().Set(v8_num(239));
1026 }
1027
1028
1029 template<typename Handler>
1030 static void TestFunctionTemplateInitializer(Handler handler,
1031                                             Handler handler_2) {
1032   // Test constructor calls.
1033   {
1034     LocalContext env;
1035     v8::Isolate* isolate = env->GetIsolate();
1036     v8::HandleScope scope(isolate);
1037
1038     Local<v8::FunctionTemplate> fun_templ =
1039         v8::FunctionTemplate::New(isolate, handler);
1040     Local<Function> fun = fun_templ->GetFunction();
1041     env->Global()->Set(v8_str("obj"), fun);
1042     Local<Script> script = v8_compile("obj()");
1043     for (int i = 0; i < 30; i++) {
1044       CHECK_EQ(102, script->Run()->Int32Value());
1045     }
1046   }
1047   // Use SetCallHandler to initialize a function template, should work like
1048   // the previous one.
1049   {
1050     LocalContext env;
1051     v8::Isolate* isolate = env->GetIsolate();
1052     v8::HandleScope scope(isolate);
1053
1054     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1055     fun_templ->SetCallHandler(handler_2);
1056     Local<Function> fun = fun_templ->GetFunction();
1057     env->Global()->Set(v8_str("obj"), fun);
1058     Local<Script> script = v8_compile("obj()");
1059     for (int i = 0; i < 30; i++) {
1060       CHECK_EQ(102, script->Run()->Int32Value());
1061     }
1062   }
1063 }
1064
1065
1066 template<typename Constructor, typename Accessor>
1067 static void TestFunctionTemplateAccessor(Constructor constructor,
1068                                          Accessor accessor) {
1069   LocalContext env;
1070   v8::HandleScope scope(env->GetIsolate());
1071
1072   Local<v8::FunctionTemplate> fun_templ =
1073       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1074   fun_templ->SetClassName(v8_str("funky"));
1075   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1076   Local<Function> fun = fun_templ->GetFunction();
1077   env->Global()->Set(v8_str("obj"), fun);
1078   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1079   CHECK_EQ(v8_str("[object funky]"), result);
1080   CompileRun("var obj_instance = new obj();");
1081   Local<Script> script;
1082   script = v8_compile("obj_instance.x");
1083   for (int i = 0; i < 30; i++) {
1084     CHECK_EQ(1, script->Run()->Int32Value());
1085   }
1086   script = v8_compile("obj_instance.m");
1087   for (int i = 0; i < 30; i++) {
1088     CHECK_EQ(239, script->Run()->Int32Value());
1089   }
1090 }
1091
1092
1093 THREADED_PROFILED_TEST(FunctionTemplate) {
1094   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1095   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1096 }
1097
1098
1099 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1100   ApiTestFuzzer::Fuzz();
1101   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1102   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1103 }
1104
1105
1106 template<typename Callback>
1107 static void TestSimpleCallback(Callback callback) {
1108   LocalContext env;
1109   v8::Isolate* isolate = env->GetIsolate();
1110   v8::HandleScope scope(isolate);
1111
1112   v8::Handle<v8::ObjectTemplate> object_template =
1113       v8::ObjectTemplate::New(isolate);
1114   object_template->Set(isolate, "callback",
1115                        v8::FunctionTemplate::New(isolate, callback));
1116   v8::Local<v8::Object> object = object_template->NewInstance();
1117   (*env)->Global()->Set(v8_str("callback_object"), object);
1118   v8::Handle<v8::Script> script;
1119   script = v8_compile("callback_object.callback(17)");
1120   for (int i = 0; i < 30; i++) {
1121     CHECK_EQ(51424, script->Run()->Int32Value());
1122   }
1123   script = v8_compile("callback_object.callback(17, 24)");
1124   for (int i = 0; i < 30; i++) {
1125     CHECK_EQ(51425, script->Run()->Int32Value());
1126   }
1127 }
1128
1129
1130 THREADED_PROFILED_TEST(SimpleCallback) {
1131   TestSimpleCallback(SimpleCallback);
1132 }
1133
1134
1135 template<typename T>
1136 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1137
1138 // constant return values
1139 static int32_t fast_return_value_int32 = 471;
1140 static uint32_t fast_return_value_uint32 = 571;
1141 static const double kFastReturnValueDouble = 2.7;
1142 // variable return values
1143 static bool fast_return_value_bool = false;
1144 enum ReturnValueOddball {
1145   kNullReturnValue,
1146   kUndefinedReturnValue,
1147   kEmptyStringReturnValue
1148 };
1149 static ReturnValueOddball fast_return_value_void;
1150 static bool fast_return_value_object_is_empty = false;
1151
1152 // Helper function to avoid compiler error: insufficient contextual information
1153 // to determine type when applying FUNCTION_ADDR to a template function.
1154 static i::Address address_of(v8::FunctionCallback callback) {
1155   return FUNCTION_ADDR(callback);
1156 }
1157
1158 template<>
1159 void FastReturnValueCallback<int32_t>(
1160     const v8::FunctionCallbackInfo<v8::Value>& info) {
1161   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1162   info.GetReturnValue().Set(fast_return_value_int32);
1163 }
1164
1165 template<>
1166 void FastReturnValueCallback<uint32_t>(
1167     const v8::FunctionCallbackInfo<v8::Value>& info) {
1168   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1169   info.GetReturnValue().Set(fast_return_value_uint32);
1170 }
1171
1172 template<>
1173 void FastReturnValueCallback<double>(
1174     const v8::FunctionCallbackInfo<v8::Value>& info) {
1175   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1176   info.GetReturnValue().Set(kFastReturnValueDouble);
1177 }
1178
1179 template<>
1180 void FastReturnValueCallback<bool>(
1181     const v8::FunctionCallbackInfo<v8::Value>& info) {
1182   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1183   info.GetReturnValue().Set(fast_return_value_bool);
1184 }
1185
1186 template<>
1187 void FastReturnValueCallback<void>(
1188     const v8::FunctionCallbackInfo<v8::Value>& info) {
1189   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1190   switch (fast_return_value_void) {
1191     case kNullReturnValue:
1192       info.GetReturnValue().SetNull();
1193       break;
1194     case kUndefinedReturnValue:
1195       info.GetReturnValue().SetUndefined();
1196       break;
1197     case kEmptyStringReturnValue:
1198       info.GetReturnValue().SetEmptyString();
1199       break;
1200   }
1201 }
1202
1203 template<>
1204 void FastReturnValueCallback<Object>(
1205     const v8::FunctionCallbackInfo<v8::Value>& info) {
1206   v8::Handle<v8::Object> object;
1207   if (!fast_return_value_object_is_empty) {
1208     object = Object::New(info.GetIsolate());
1209   }
1210   info.GetReturnValue().Set(object);
1211 }
1212
1213 template<typename T>
1214 Handle<Value> TestFastReturnValues() {
1215   LocalContext env;
1216   v8::Isolate* isolate = env->GetIsolate();
1217   v8::EscapableHandleScope scope(isolate);
1218   v8::Handle<v8::ObjectTemplate> object_template =
1219       v8::ObjectTemplate::New(isolate);
1220   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1221   object_template->Set(isolate, "callback",
1222                        v8::FunctionTemplate::New(isolate, callback));
1223   v8::Local<v8::Object> object = object_template->NewInstance();
1224   (*env)->Global()->Set(v8_str("callback_object"), object);
1225   return scope.Escape(CompileRun("callback_object.callback()"));
1226 }
1227
1228
1229 THREADED_PROFILED_TEST(FastReturnValues) {
1230   LocalContext env;
1231   v8::HandleScope scope(CcTest::isolate());
1232   v8::Handle<v8::Value> value;
1233   // check int32_t and uint32_t
1234   int32_t int_values[] = {
1235       0, 234, -723,
1236       i::Smi::kMinValue, i::Smi::kMaxValue
1237   };
1238   for (size_t i = 0; i < arraysize(int_values); i++) {
1239     for (int modifier = -1; modifier <= 1; modifier++) {
1240       int int_value = int_values[i] + modifier;
1241       // check int32_t
1242       fast_return_value_int32 = int_value;
1243       value = TestFastReturnValues<int32_t>();
1244       CHECK(value->IsInt32());
1245       CHECK(fast_return_value_int32 == value->Int32Value());
1246       // check uint32_t
1247       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1248       value = TestFastReturnValues<uint32_t>();
1249       CHECK(value->IsUint32());
1250       CHECK(fast_return_value_uint32 == value->Uint32Value());
1251     }
1252   }
1253   // check double
1254   value = TestFastReturnValues<double>();
1255   CHECK(value->IsNumber());
1256   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1257   // check bool values
1258   for (int i = 0; i < 2; i++) {
1259     fast_return_value_bool = i == 0;
1260     value = TestFastReturnValues<bool>();
1261     CHECK(value->IsBoolean());
1262     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1263   }
1264   // check oddballs
1265   ReturnValueOddball oddballs[] = {
1266       kNullReturnValue,
1267       kUndefinedReturnValue,
1268       kEmptyStringReturnValue
1269   };
1270   for (size_t i = 0; i < arraysize(oddballs); i++) {
1271     fast_return_value_void = oddballs[i];
1272     value = TestFastReturnValues<void>();
1273     switch (fast_return_value_void) {
1274       case kNullReturnValue:
1275         CHECK(value->IsNull());
1276         break;
1277       case kUndefinedReturnValue:
1278         CHECK(value->IsUndefined());
1279         break;
1280       case kEmptyStringReturnValue:
1281         CHECK(value->IsString());
1282         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1283         break;
1284     }
1285   }
1286   // check handles
1287   fast_return_value_object_is_empty = false;
1288   value = TestFastReturnValues<Object>();
1289   CHECK(value->IsObject());
1290   fast_return_value_object_is_empty = true;
1291   value = TestFastReturnValues<Object>();
1292   CHECK(value->IsUndefined());
1293 }
1294
1295
1296 THREADED_TEST(FunctionTemplateSetLength) {
1297   LocalContext env;
1298   v8::Isolate* isolate = env->GetIsolate();
1299   v8::HandleScope scope(isolate);
1300   {
1301     Local<v8::FunctionTemplate> fun_templ =
1302         v8::FunctionTemplate::New(isolate,
1303                                   handle_callback,
1304                                   Handle<v8::Value>(),
1305                                   Handle<v8::Signature>(),
1306                                   23);
1307     Local<Function> fun = fun_templ->GetFunction();
1308     env->Global()->Set(v8_str("obj"), fun);
1309     Local<Script> script = v8_compile("obj.length");
1310     CHECK_EQ(23, script->Run()->Int32Value());
1311   }
1312   {
1313     Local<v8::FunctionTemplate> fun_templ =
1314         v8::FunctionTemplate::New(isolate, handle_callback);
1315     fun_templ->SetLength(22);
1316     Local<Function> fun = fun_templ->GetFunction();
1317     env->Global()->Set(v8_str("obj"), fun);
1318     Local<Script> script = v8_compile("obj.length");
1319     CHECK_EQ(22, script->Run()->Int32Value());
1320   }
1321   {
1322     // Without setting length it defaults to 0.
1323     Local<v8::FunctionTemplate> fun_templ =
1324         v8::FunctionTemplate::New(isolate, handle_callback);
1325     Local<Function> fun = fun_templ->GetFunction();
1326     env->Global()->Set(v8_str("obj"), fun);
1327     Local<Script> script = v8_compile("obj.length");
1328     CHECK_EQ(0, script->Run()->Int32Value());
1329   }
1330 }
1331
1332
1333 static void* expected_ptr;
1334 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1335   void* ptr = v8::External::Cast(*args.Data())->Value();
1336   CHECK_EQ(expected_ptr, ptr);
1337   args.GetReturnValue().Set(true);
1338 }
1339
1340
1341 static void TestExternalPointerWrapping() {
1342   LocalContext env;
1343   v8::Isolate* isolate = env->GetIsolate();
1344   v8::HandleScope scope(isolate);
1345
1346   v8::Handle<v8::Value> data =
1347       v8::External::New(isolate, expected_ptr);
1348
1349   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1350   obj->Set(v8_str("func"),
1351            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1352   env->Global()->Set(v8_str("obj"), obj);
1353
1354   CHECK(CompileRun(
1355         "function foo() {\n"
1356         "  for (var i = 0; i < 13; i++) obj.func();\n"
1357         "}\n"
1358         "foo(), true")->BooleanValue());
1359 }
1360
1361
1362 THREADED_TEST(ExternalWrap) {
1363   // Check heap allocated object.
1364   int* ptr = new int;
1365   expected_ptr = ptr;
1366   TestExternalPointerWrapping();
1367   delete ptr;
1368
1369   // Check stack allocated object.
1370   int foo;
1371   expected_ptr = &foo;
1372   TestExternalPointerWrapping();
1373
1374   // Check not aligned addresses.
1375   const int n = 100;
1376   char* s = new char[n];
1377   for (int i = 0; i < n; i++) {
1378     expected_ptr = s + i;
1379     TestExternalPointerWrapping();
1380   }
1381
1382   delete[] s;
1383
1384   // Check several invalid addresses.
1385   expected_ptr = reinterpret_cast<void*>(1);
1386   TestExternalPointerWrapping();
1387
1388   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1389   TestExternalPointerWrapping();
1390
1391   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1392   TestExternalPointerWrapping();
1393
1394 #if defined(V8_HOST_ARCH_X64)
1395   // Check a value with a leading 1 bit in x64 Smi encoding.
1396   expected_ptr = reinterpret_cast<void*>(0x400000000);
1397   TestExternalPointerWrapping();
1398
1399   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1400   TestExternalPointerWrapping();
1401
1402   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1403   TestExternalPointerWrapping();
1404 #endif
1405 }
1406
1407
1408 THREADED_TEST(FindInstanceInPrototypeChain) {
1409   LocalContext env;
1410   v8::Isolate* isolate = env->GetIsolate();
1411   v8::HandleScope scope(isolate);
1412
1413   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1414   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1415   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1416   derived->Inherit(base);
1417
1418   Local<v8::Function> base_function = base->GetFunction();
1419   Local<v8::Function> derived_function = derived->GetFunction();
1420   Local<v8::Function> other_function = other->GetFunction();
1421
1422   Local<v8::Object> base_instance = base_function->NewInstance();
1423   Local<v8::Object> derived_instance = derived_function->NewInstance();
1424   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1425   Local<v8::Object> other_instance = other_function->NewInstance();
1426   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1427   other_instance->Set(v8_str("__proto__"), derived_instance2);
1428
1429   // base_instance is only an instance of base.
1430   CHECK_EQ(base_instance,
1431            base_instance->FindInstanceInPrototypeChain(base));
1432   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1433   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1434
1435   // derived_instance is an instance of base and derived.
1436   CHECK_EQ(derived_instance,
1437            derived_instance->FindInstanceInPrototypeChain(base));
1438   CHECK_EQ(derived_instance,
1439            derived_instance->FindInstanceInPrototypeChain(derived));
1440   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1441
1442   // other_instance is an instance of other and its immediate
1443   // prototype derived_instance2 is an instance of base and derived.
1444   // Note, derived_instance is an instance of base and derived too,
1445   // but it comes after derived_instance2 in the prototype chain of
1446   // other_instance.
1447   CHECK_EQ(derived_instance2,
1448            other_instance->FindInstanceInPrototypeChain(base));
1449   CHECK_EQ(derived_instance2,
1450            other_instance->FindInstanceInPrototypeChain(derived));
1451   CHECK_EQ(other_instance,
1452            other_instance->FindInstanceInPrototypeChain(other));
1453 }
1454
1455
1456 THREADED_TEST(TinyInteger) {
1457   LocalContext env;
1458   v8::Isolate* isolate = env->GetIsolate();
1459   v8::HandleScope scope(isolate);
1460
1461   int32_t value = 239;
1462   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1463   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1464
1465   value_obj = v8::Integer::New(isolate, value);
1466   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1467 }
1468
1469
1470 THREADED_TEST(BigSmiInteger) {
1471   LocalContext env;
1472   v8::HandleScope scope(env->GetIsolate());
1473   v8::Isolate* isolate = CcTest::isolate();
1474
1475   int32_t value = i::Smi::kMaxValue;
1476   // We cannot add one to a Smi::kMaxValue without wrapping.
1477   if (i::SmiValuesAre31Bits()) {
1478     CHECK(i::Smi::IsValid(value));
1479     CHECK(!i::Smi::IsValid(value + 1));
1480
1481     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1482     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1483
1484     value_obj = v8::Integer::New(isolate, value);
1485     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1486   }
1487 }
1488
1489
1490 THREADED_TEST(BigInteger) {
1491   LocalContext env;
1492   v8::HandleScope scope(env->GetIsolate());
1493   v8::Isolate* isolate = CcTest::isolate();
1494
1495   // We cannot add one to a Smi::kMaxValue without wrapping.
1496   if (i::SmiValuesAre31Bits()) {
1497     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1498     // The code will not be run in that case, due to the "if" guard.
1499     int32_t value =
1500         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1501     CHECK(value > i::Smi::kMaxValue);
1502     CHECK(!i::Smi::IsValid(value));
1503
1504     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1505     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1506
1507     value_obj = v8::Integer::New(isolate, value);
1508     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1509   }
1510 }
1511
1512
1513 THREADED_TEST(TinyUnsignedInteger) {
1514   LocalContext env;
1515   v8::HandleScope scope(env->GetIsolate());
1516   v8::Isolate* isolate = CcTest::isolate();
1517
1518   uint32_t value = 239;
1519
1520   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1521   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1522
1523   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1524   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1525 }
1526
1527
1528 THREADED_TEST(BigUnsignedSmiInteger) {
1529   LocalContext env;
1530   v8::HandleScope scope(env->GetIsolate());
1531   v8::Isolate* isolate = CcTest::isolate();
1532
1533   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1534   CHECK(i::Smi::IsValid(value));
1535   CHECK(!i::Smi::IsValid(value + 1));
1536
1537   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1538   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1539
1540   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1541   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1542 }
1543
1544
1545 THREADED_TEST(BigUnsignedInteger) {
1546   LocalContext env;
1547   v8::HandleScope scope(env->GetIsolate());
1548   v8::Isolate* isolate = CcTest::isolate();
1549
1550   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1551   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1552   CHECK(!i::Smi::IsValid(value));
1553
1554   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1555   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1556
1557   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1558   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1559 }
1560
1561
1562 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1563   LocalContext env;
1564   v8::HandleScope scope(env->GetIsolate());
1565   v8::Isolate* isolate = CcTest::isolate();
1566
1567   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1568   uint32_t value = INT32_MAX_AS_UINT + 1;
1569   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1570
1571   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1572   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1573
1574   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1575   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1576 }
1577
1578
1579 THREADED_TEST(IsNativeError) {
1580   LocalContext env;
1581   v8::HandleScope scope(env->GetIsolate());
1582   v8::Handle<Value> syntax_error = CompileRun(
1583       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1584   CHECK(syntax_error->IsNativeError());
1585   v8::Handle<Value> not_error = CompileRun("{a:42}");
1586   CHECK(!not_error->IsNativeError());
1587   v8::Handle<Value> not_object = CompileRun("42");
1588   CHECK(!not_object->IsNativeError());
1589 }
1590
1591
1592 THREADED_TEST(IsGeneratorFunctionOrObject) {
1593   LocalContext env;
1594   v8::HandleScope scope(env->GetIsolate());
1595
1596   CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1597   v8::Handle<Value> gen = CompileRun("gen");
1598   v8::Handle<Value> genObj = CompileRun("gen()");
1599   v8::Handle<Value> object = CompileRun("{a:42}");
1600   v8::Handle<Value> func = CompileRun("func");
1601
1602   CHECK(gen->IsGeneratorFunction());
1603   CHECK(gen->IsFunction());
1604   CHECK(!gen->IsGeneratorObject());
1605
1606   CHECK(!genObj->IsGeneratorFunction());
1607   CHECK(!genObj->IsFunction());
1608   CHECK(genObj->IsGeneratorObject());
1609
1610   CHECK(!object->IsGeneratorFunction());
1611   CHECK(!object->IsFunction());
1612   CHECK(!object->IsGeneratorObject());
1613
1614   CHECK(!func->IsGeneratorFunction());
1615   CHECK(func->IsFunction());
1616   CHECK(!func->IsGeneratorObject());
1617 }
1618
1619
1620 THREADED_TEST(ArgumentsObject) {
1621   LocalContext env;
1622   v8::HandleScope scope(env->GetIsolate());
1623   v8::Handle<Value> arguments_object =
1624       CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1625   CHECK(arguments_object->IsArgumentsObject());
1626   v8::Handle<Value> array = CompileRun("[1,2,3]");
1627   CHECK(!array->IsArgumentsObject());
1628   v8::Handle<Value> object = CompileRun("{a:42}");
1629   CHECK(!object->IsArgumentsObject());
1630 }
1631
1632
1633 THREADED_TEST(IsMapOrSet) {
1634   LocalContext env;
1635   v8::HandleScope scope(env->GetIsolate());
1636   v8::Handle<Value> map = CompileRun("new Map()");
1637   v8::Handle<Value> set = CompileRun("new Set()");
1638   v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1639   v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1640   CHECK(map->IsMap());
1641   CHECK(set->IsSet());
1642   CHECK(weak_map->IsWeakMap());
1643   CHECK(weak_set->IsWeakSet());
1644
1645   CHECK(!map->IsSet());
1646   CHECK(!map->IsWeakMap());
1647   CHECK(!map->IsWeakSet());
1648
1649   CHECK(!set->IsMap());
1650   CHECK(!set->IsWeakMap());
1651   CHECK(!set->IsWeakSet());
1652
1653   CHECK(!weak_map->IsMap());
1654   CHECK(!weak_map->IsSet());
1655   CHECK(!weak_map->IsWeakSet());
1656
1657   CHECK(!weak_set->IsMap());
1658   CHECK(!weak_set->IsSet());
1659   CHECK(!weak_set->IsWeakMap());
1660
1661   v8::Handle<Value> object = CompileRun("{a:42}");
1662   CHECK(!object->IsMap());
1663   CHECK(!object->IsSet());
1664   CHECK(!object->IsWeakMap());
1665   CHECK(!object->IsWeakSet());
1666 }
1667
1668
1669 THREADED_TEST(StringObject) {
1670   LocalContext env;
1671   v8::HandleScope scope(env->GetIsolate());
1672   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1673   CHECK(boxed_string->IsStringObject());
1674   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1675   CHECK(!unboxed_string->IsStringObject());
1676   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1677   CHECK(!boxed_not_string->IsStringObject());
1678   v8::Handle<Value> not_object = CompileRun("0");
1679   CHECK(!not_object->IsStringObject());
1680   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1681   CHECK(!as_boxed.IsEmpty());
1682   Local<v8::String> the_string = as_boxed->ValueOf();
1683   CHECK(!the_string.IsEmpty());
1684   ExpectObject("\"test\"", the_string);
1685   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1686   CHECK(new_boxed_string->IsStringObject());
1687   as_boxed = new_boxed_string.As<v8::StringObject>();
1688   the_string = as_boxed->ValueOf();
1689   CHECK(!the_string.IsEmpty());
1690   ExpectObject("\"test\"", the_string);
1691 }
1692
1693
1694 THREADED_TEST(NumberObject) {
1695   LocalContext env;
1696   v8::HandleScope scope(env->GetIsolate());
1697   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1698   CHECK(boxed_number->IsNumberObject());
1699   v8::Handle<Value> unboxed_number = CompileRun("42");
1700   CHECK(!unboxed_number->IsNumberObject());
1701   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1702   CHECK(!boxed_not_number->IsNumberObject());
1703   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1704   CHECK(!as_boxed.IsEmpty());
1705   double the_number = as_boxed->ValueOf();
1706   CHECK_EQ(42.0, the_number);
1707   v8::Handle<v8::Value> new_boxed_number =
1708       v8::NumberObject::New(env->GetIsolate(), 43);
1709   CHECK(new_boxed_number->IsNumberObject());
1710   as_boxed = new_boxed_number.As<v8::NumberObject>();
1711   the_number = as_boxed->ValueOf();
1712   CHECK_EQ(43.0, the_number);
1713 }
1714
1715
1716 THREADED_TEST(BooleanObject) {
1717   LocalContext env;
1718   v8::HandleScope scope(env->GetIsolate());
1719   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1720   CHECK(boxed_boolean->IsBooleanObject());
1721   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1722   CHECK(!unboxed_boolean->IsBooleanObject());
1723   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1724   CHECK(!boxed_not_boolean->IsBooleanObject());
1725   v8::Handle<v8::BooleanObject> as_boxed =
1726       boxed_boolean.As<v8::BooleanObject>();
1727   CHECK(!as_boxed.IsEmpty());
1728   bool the_boolean = as_boxed->ValueOf();
1729   CHECK_EQ(true, the_boolean);
1730   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1731   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1732   CHECK(boxed_true->IsBooleanObject());
1733   CHECK(boxed_false->IsBooleanObject());
1734   as_boxed = boxed_true.As<v8::BooleanObject>();
1735   CHECK_EQ(true, as_boxed->ValueOf());
1736   as_boxed = boxed_false.As<v8::BooleanObject>();
1737   CHECK_EQ(false, as_boxed->ValueOf());
1738 }
1739
1740
1741 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1742   LocalContext env;
1743   v8::HandleScope scope(env->GetIsolate());
1744
1745   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1746   CHECK(primitive_false->IsBoolean());
1747   CHECK(!primitive_false->IsBooleanObject());
1748   CHECK(!primitive_false->BooleanValue());
1749   CHECK(!primitive_false->IsTrue());
1750   CHECK(primitive_false->IsFalse());
1751
1752   Local<Value> false_value = BooleanObject::New(false);
1753   CHECK(!false_value->IsBoolean());
1754   CHECK(false_value->IsBooleanObject());
1755   CHECK(false_value->BooleanValue());
1756   CHECK(!false_value->IsTrue());
1757   CHECK(!false_value->IsFalse());
1758
1759   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1760   CHECK(!false_boolean_object->IsBoolean());
1761   CHECK(false_boolean_object->IsBooleanObject());
1762   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1763   // CHECK(false_boolean_object->BooleanValue());
1764   CHECK(!false_boolean_object->ValueOf());
1765   CHECK(!false_boolean_object->IsTrue());
1766   CHECK(!false_boolean_object->IsFalse());
1767
1768   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1769   CHECK(primitive_true->IsBoolean());
1770   CHECK(!primitive_true->IsBooleanObject());
1771   CHECK(primitive_true->BooleanValue());
1772   CHECK(primitive_true->IsTrue());
1773   CHECK(!primitive_true->IsFalse());
1774
1775   Local<Value> true_value = BooleanObject::New(true);
1776   CHECK(!true_value->IsBoolean());
1777   CHECK(true_value->IsBooleanObject());
1778   CHECK(true_value->BooleanValue());
1779   CHECK(!true_value->IsTrue());
1780   CHECK(!true_value->IsFalse());
1781
1782   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1783   CHECK(!true_boolean_object->IsBoolean());
1784   CHECK(true_boolean_object->IsBooleanObject());
1785   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1786   // CHECK(true_boolean_object->BooleanValue());
1787   CHECK(true_boolean_object->ValueOf());
1788   CHECK(!true_boolean_object->IsTrue());
1789   CHECK(!true_boolean_object->IsFalse());
1790 }
1791
1792
1793 THREADED_TEST(Number) {
1794   LocalContext env;
1795   v8::HandleScope scope(env->GetIsolate());
1796   double PI = 3.1415926;
1797   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1798   CHECK_EQ(PI, pi_obj->NumberValue());
1799 }
1800
1801
1802 THREADED_TEST(ToNumber) {
1803   LocalContext env;
1804   v8::Isolate* isolate = CcTest::isolate();
1805   v8::HandleScope scope(isolate);
1806   Local<String> str = v8_str("3.1415926");
1807   CHECK_EQ(3.1415926, str->NumberValue());
1808   v8::Handle<v8::Boolean> t = v8::True(isolate);
1809   CHECK_EQ(1.0, t->NumberValue());
1810   v8::Handle<v8::Boolean> f = v8::False(isolate);
1811   CHECK_EQ(0.0, f->NumberValue());
1812 }
1813
1814
1815 THREADED_TEST(Date) {
1816   LocalContext env;
1817   v8::HandleScope scope(env->GetIsolate());
1818   double PI = 3.1415926;
1819   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1820   CHECK_EQ(3.0, date->NumberValue());
1821   date.As<v8::Date>()->Set(v8_str("property"),
1822                            v8::Integer::New(env->GetIsolate(), 42));
1823   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1824 }
1825
1826
1827 THREADED_TEST(Boolean) {
1828   LocalContext env;
1829   v8::Isolate* isolate = env->GetIsolate();
1830   v8::HandleScope scope(isolate);
1831   v8::Handle<v8::Boolean> t = v8::True(isolate);
1832   CHECK(t->Value());
1833   v8::Handle<v8::Boolean> f = v8::False(isolate);
1834   CHECK(!f->Value());
1835   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1836   CHECK(!u->BooleanValue());
1837   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1838   CHECK(!n->BooleanValue());
1839   v8::Handle<String> str1 = v8_str("");
1840   CHECK(!str1->BooleanValue());
1841   v8::Handle<String> str2 = v8_str("x");
1842   CHECK(str2->BooleanValue());
1843   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1844   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1845   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1846   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1847   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1848 }
1849
1850
1851 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1852   ApiTestFuzzer::Fuzz();
1853   args.GetReturnValue().Set(v8_num(13.4));
1854 }
1855
1856
1857 static void GetM(Local<String> name,
1858                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1859   ApiTestFuzzer::Fuzz();
1860   info.GetReturnValue().Set(v8_num(876));
1861 }
1862
1863
1864 THREADED_TEST(GlobalPrototype) {
1865   v8::Isolate* isolate = CcTest::isolate();
1866   v8::HandleScope scope(isolate);
1867   v8::Handle<v8::FunctionTemplate> func_templ =
1868       v8::FunctionTemplate::New(isolate);
1869   func_templ->PrototypeTemplate()->Set(
1870       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1871   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1872   templ->Set(isolate, "x", v8_num(200));
1873   templ->SetAccessor(v8_str("m"), GetM);
1874   LocalContext env(0, templ);
1875   v8::Handle<Script> script(v8_compile("dummy()"));
1876   v8::Handle<Value> result(script->Run());
1877   CHECK_EQ(13.4, result->NumberValue());
1878   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1879   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1880 }
1881
1882
1883 THREADED_TEST(ObjectTemplate) {
1884   v8::Isolate* isolate = CcTest::isolate();
1885   v8::HandleScope scope(isolate);
1886   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1887   templ1->Set(isolate, "x", v8_num(10));
1888   templ1->Set(isolate, "y", v8_num(13));
1889   LocalContext env;
1890   Local<v8::Object> instance1 = templ1->NewInstance();
1891   env->Global()->Set(v8_str("p"), instance1);
1892   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1893   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1894   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1895   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1896   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1897   templ2->Set(isolate, "a", v8_num(12));
1898   templ2->Set(isolate, "b", templ1);
1899   Local<v8::Object> instance2 = templ2->NewInstance();
1900   env->Global()->Set(v8_str("q"), instance2);
1901   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1902   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1903   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1904   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1905 }
1906
1907
1908 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1909   ApiTestFuzzer::Fuzz();
1910   args.GetReturnValue().Set(v8_num(17.2));
1911 }
1912
1913
1914 static void GetKnurd(Local<String> property,
1915                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1916   ApiTestFuzzer::Fuzz();
1917   info.GetReturnValue().Set(v8_num(15.2));
1918 }
1919
1920
1921 THREADED_TEST(DescriptorInheritance) {
1922   v8::Isolate* isolate = CcTest::isolate();
1923   v8::HandleScope scope(isolate);
1924   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1925   super->PrototypeTemplate()->Set(isolate, "flabby",
1926                                   v8::FunctionTemplate::New(isolate,
1927                                                             GetFlabby));
1928   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1929
1930   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1931
1932   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1933   base1->Inherit(super);
1934   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1935
1936   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1937   base2->Inherit(super);
1938   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1939
1940   LocalContext env;
1941
1942   env->Global()->Set(v8_str("s"), super->GetFunction());
1943   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1944   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1945
1946   // Checks right __proto__ chain.
1947   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1948   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1949
1950   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1951
1952   // Instance accessor should not be visible on function object or its prototype
1953   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1954   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1955   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1956
1957   env->Global()->Set(v8_str("obj"),
1958                      base1->GetFunction()->NewInstance());
1959   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1960   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1961   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1962   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1963   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1964
1965   env->Global()->Set(v8_str("obj2"),
1966                      base2->GetFunction()->NewInstance());
1967   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1968   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1969   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1970   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1971   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1972
1973   // base1 and base2 cannot cross reference to each's prototype
1974   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1975   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1976 }
1977
1978
1979 int echo_named_call_count;
1980
1981
1982 static void EchoNamedProperty(Local<String> name,
1983                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1984   ApiTestFuzzer::Fuzz();
1985   CHECK_EQ(v8_str("data"), info.Data());
1986   echo_named_call_count++;
1987   info.GetReturnValue().Set(name);
1988 }
1989
1990
1991 // Helper functions for Interceptor/Accessor interaction tests
1992
1993 void SimpleAccessorGetter(Local<String> name,
1994                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1995   Handle<Object> self = Handle<Object>::Cast(info.This());
1996   info.GetReturnValue().Set(
1997       self->Get(String::Concat(v8_str("accessor_"), name)));
1998 }
1999
2000 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
2001                           const v8::PropertyCallbackInfo<void>& info) {
2002   Handle<Object> self = Handle<Object>::Cast(info.This());
2003   self->Set(String::Concat(v8_str("accessor_"), name), value);
2004 }
2005
2006 void SymbolAccessorGetter(Local<Name> name,
2007                           const v8::PropertyCallbackInfo<v8::Value>& info) {
2008   CHECK(name->IsSymbol());
2009   Local<Symbol> sym = Local<Symbol>::Cast(name);
2010   if (sym->Name()->IsUndefined())
2011     return;
2012   SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
2013 }
2014
2015 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2016                           const v8::PropertyCallbackInfo<void>& info) {
2017   CHECK(name->IsSymbol());
2018   Local<Symbol> sym = Local<Symbol>::Cast(name);
2019   if (sym->Name()->IsUndefined())
2020     return;
2021   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
2022 }
2023
2024 void SymbolAccessorGetterReturnsDefault(
2025     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2026   CHECK(name->IsSymbol());
2027   Local<Symbol> sym = Local<Symbol>::Cast(name);
2028   if (sym->Name()->IsUndefined()) return;
2029   info.GetReturnValue().Set(info.Data());
2030 }
2031
2032 static void ThrowingSymbolAccessorGetter(
2033     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2034   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
2035 }
2036
2037 void EmptyInterceptorGetter(Local<String> name,
2038                             const v8::PropertyCallbackInfo<v8::Value>& info) {
2039 }
2040
2041 void EmptyInterceptorSetter(Local<String> name,
2042                             Local<Value> value,
2043                             const v8::PropertyCallbackInfo<v8::Value>& info) {
2044 }
2045
2046 void InterceptorGetter(Local<String> name,
2047                        const v8::PropertyCallbackInfo<v8::Value>& info) {
2048   // Intercept names that start with 'interceptor_'.
2049   String::Utf8Value utf8(name);
2050   char* name_str = *utf8;
2051   char prefix[] = "interceptor_";
2052   int i;
2053   for (i = 0; name_str[i] && prefix[i]; ++i) {
2054     if (name_str[i] != prefix[i]) return;
2055   }
2056   Handle<Object> self = Handle<Object>::Cast(info.This());
2057   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
2058 }
2059
2060 void InterceptorSetter(Local<String> name,
2061                        Local<Value> value,
2062                        const v8::PropertyCallbackInfo<v8::Value>& info) {
2063   // Intercept accesses that set certain integer values, for which the name does
2064   // not start with 'accessor_'.
2065   String::Utf8Value utf8(name);
2066   char* name_str = *utf8;
2067   char prefix[] = "accessor_";
2068   int i;
2069   for (i = 0; name_str[i] && prefix[i]; ++i) {
2070     if (name_str[i] != prefix[i]) break;
2071   }
2072   if (!prefix[i]) return;
2073
2074   if (value->IsInt32() && value->Int32Value() < 10000) {
2075     Handle<Object> self = Handle<Object>::Cast(info.This());
2076     self->SetHiddenValue(name, value);
2077     info.GetReturnValue().Set(value);
2078   }
2079 }
2080
2081 void AddAccessor(Handle<FunctionTemplate> templ,
2082                  Handle<String> name,
2083                  v8::AccessorGetterCallback getter,
2084                  v8::AccessorSetterCallback setter) {
2085   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2086 }
2087
2088 void AddInterceptor(Handle<FunctionTemplate> templ,
2089                     v8::NamedPropertyGetterCallback getter,
2090                     v8::NamedPropertySetterCallback setter) {
2091   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
2092 }
2093
2094
2095 void AddAccessor(Handle<FunctionTemplate> templ,
2096                  Handle<Name> name,
2097                  v8::AccessorNameGetterCallback getter,
2098                  v8::AccessorNameSetterCallback setter) {
2099   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2100 }
2101
2102
2103 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
2104   v8::HandleScope scope(CcTest::isolate());
2105   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2106   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2107   child->Inherit(parent);
2108   AddAccessor(parent, v8_str("age"),
2109               SimpleAccessorGetter, SimpleAccessorSetter);
2110   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2111   LocalContext env;
2112   env->Global()->Set(v8_str("Child"), child->GetFunction());
2113   CompileRun("var child = new Child;"
2114              "child.age = 10;");
2115   ExpectBoolean("child.hasOwnProperty('age')", false);
2116   ExpectInt32("child.age", 10);
2117   ExpectInt32("child.accessor_age", 10);
2118 }
2119
2120
2121 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
2122   v8::Isolate* isolate = CcTest::isolate();
2123   v8::HandleScope scope(isolate);
2124   LocalContext env;
2125   v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2126   i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2127   CHECK(a->map()->instance_descriptors()->IsFixedArray());
2128   CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2129   CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2130   CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2131   // But we should still have an ExecutableAccessorInfo.
2132   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2133   i::LookupResult lookup(i_isolate);
2134   i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2135   i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2136   CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2137   CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
2138 }
2139
2140
2141 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2142   v8::HandleScope scope(CcTest::isolate());
2143   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2144   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2145   LocalContext env;
2146   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2147   CompileRun("var o1 = new Constructor;"
2148              "o1.a = 1;"  // Ensure a and x share the descriptor array.
2149              "Object.defineProperty(o1, 'x', {value: 10});");
2150   CompileRun("var o2 = new Constructor;"
2151              "o2.a = 1;"
2152              "Object.defineProperty(o2, 'x', {value: 10});");
2153 }
2154
2155
2156 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2157   v8::Isolate* isolate = CcTest::isolate();
2158   v8::HandleScope scope(isolate);
2159   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2160   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2161   child->Inherit(parent);
2162   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2163   LocalContext env;
2164   env->Global()->Set(v8_str("Child"), child->GetFunction());
2165   CompileRun("var child = new Child;"
2166              "var parent = child.__proto__;"
2167              "Object.defineProperty(parent, 'age', "
2168              "  {get: function(){ return this.accessor_age; }, "
2169              "   set: function(v){ this.accessor_age = v; }, "
2170              "   enumerable: true, configurable: true});"
2171              "child.age = 10;");
2172   ExpectBoolean("child.hasOwnProperty('age')", false);
2173   ExpectInt32("child.age", 10);
2174   ExpectInt32("child.accessor_age", 10);
2175 }
2176
2177
2178 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2179   v8::Isolate* isolate = CcTest::isolate();
2180   v8::HandleScope scope(isolate);
2181   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2182   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2183   child->Inherit(parent);
2184   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2185   LocalContext env;
2186   env->Global()->Set(v8_str("Child"), child->GetFunction());
2187   CompileRun("var child = new Child;"
2188              "var parent = child.__proto__;"
2189              "parent.name = 'Alice';");
2190   ExpectBoolean("child.hasOwnProperty('name')", false);
2191   ExpectString("child.name", "Alice");
2192   CompileRun("child.name = 'Bob';");
2193   ExpectString("child.name", "Bob");
2194   ExpectBoolean("child.hasOwnProperty('name')", true);
2195   ExpectString("parent.name", "Alice");
2196 }
2197
2198
2199 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2200   v8::HandleScope scope(CcTest::isolate());
2201   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2202   AddAccessor(templ, v8_str("age"),
2203               SimpleAccessorGetter, SimpleAccessorSetter);
2204   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2205   LocalContext env;
2206   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2207   CompileRun("var obj = new Obj;"
2208              "function setAge(i){ obj.age = i; };"
2209              "for(var i = 0; i <= 10000; i++) setAge(i);");
2210   // All i < 10000 go to the interceptor.
2211   ExpectInt32("obj.interceptor_age", 9999);
2212   // The last i goes to the accessor.
2213   ExpectInt32("obj.accessor_age", 10000);
2214 }
2215
2216
2217 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2218   v8::HandleScope scope(CcTest::isolate());
2219   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2220   AddAccessor(templ, v8_str("age"),
2221               SimpleAccessorGetter, SimpleAccessorSetter);
2222   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2223   LocalContext env;
2224   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2225   CompileRun("var obj = new Obj;"
2226              "function setAge(i){ obj.age = i; };"
2227              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2228   // All i >= 10000 go to the accessor.
2229   ExpectInt32("obj.accessor_age", 10000);
2230   // The last i goes to the interceptor.
2231   ExpectInt32("obj.interceptor_age", 9999);
2232 }
2233
2234
2235 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2236   v8::HandleScope scope(CcTest::isolate());
2237   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2238   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2239   child->Inherit(parent);
2240   AddAccessor(parent, v8_str("age"),
2241               SimpleAccessorGetter, SimpleAccessorSetter);
2242   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2243   LocalContext env;
2244   env->Global()->Set(v8_str("Child"), child->GetFunction());
2245   CompileRun("var child = new Child;"
2246              "function setAge(i){ child.age = i; };"
2247              "for(var i = 0; i <= 10000; i++) setAge(i);");
2248   // All i < 10000 go to the interceptor.
2249   ExpectInt32("child.interceptor_age", 9999);
2250   // The last i goes to the accessor.
2251   ExpectInt32("child.accessor_age", 10000);
2252 }
2253
2254
2255 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2256   v8::HandleScope scope(CcTest::isolate());
2257   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2258   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2259   child->Inherit(parent);
2260   AddAccessor(parent, v8_str("age"),
2261               SimpleAccessorGetter, SimpleAccessorSetter);
2262   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2263   LocalContext env;
2264   env->Global()->Set(v8_str("Child"), child->GetFunction());
2265   CompileRun("var child = new Child;"
2266              "function setAge(i){ child.age = i; };"
2267              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2268   // All i >= 10000 go to the accessor.
2269   ExpectInt32("child.accessor_age", 10000);
2270   // The last i goes to the interceptor.
2271   ExpectInt32("child.interceptor_age", 9999);
2272 }
2273
2274
2275 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2276   v8::HandleScope scope(CcTest::isolate());
2277   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2278   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2279   LocalContext env;
2280   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2281   CompileRun("var obj = new Obj;"
2282              "function setter(i) { this.accessor_age = i; };"
2283              "function getter() { return this.accessor_age; };"
2284              "function setAge(i) { obj.age = i; };"
2285              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2286              "for(var i = 0; i <= 10000; i++) setAge(i);");
2287   // All i < 10000 go to the interceptor.
2288   ExpectInt32("obj.interceptor_age", 9999);
2289   // The last i goes to the JavaScript accessor.
2290   ExpectInt32("obj.accessor_age", 10000);
2291   // The installed JavaScript getter is still intact.
2292   // This last part is a regression test for issue 1651 and relies on the fact
2293   // that both interceptor and accessor are being installed on the same object.
2294   ExpectInt32("obj.age", 10000);
2295   ExpectBoolean("obj.hasOwnProperty('age')", true);
2296   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2297 }
2298
2299
2300 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2301   v8::HandleScope scope(CcTest::isolate());
2302   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2303   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2304   LocalContext env;
2305   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2306   CompileRun("var obj = new Obj;"
2307              "function setter(i) { this.accessor_age = i; };"
2308              "function getter() { return this.accessor_age; };"
2309              "function setAge(i) { obj.age = i; };"
2310              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2311              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2312   // All i >= 10000 go to the accessor.
2313   ExpectInt32("obj.accessor_age", 10000);
2314   // The last i goes to the interceptor.
2315   ExpectInt32("obj.interceptor_age", 9999);
2316   // The installed JavaScript getter is still intact.
2317   // This last part is a regression test for issue 1651 and relies on the fact
2318   // that both interceptor and accessor are being installed on the same object.
2319   ExpectInt32("obj.age", 10000);
2320   ExpectBoolean("obj.hasOwnProperty('age')", true);
2321   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2322 }
2323
2324
2325 THREADED_TEST(SwitchFromInterceptorToProperty) {
2326   v8::HandleScope scope(CcTest::isolate());
2327   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2328   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2329   child->Inherit(parent);
2330   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2331   LocalContext env;
2332   env->Global()->Set(v8_str("Child"), child->GetFunction());
2333   CompileRun("var child = new Child;"
2334              "function setAge(i){ child.age = i; };"
2335              "for(var i = 0; i <= 10000; i++) setAge(i);");
2336   // All i < 10000 go to the interceptor.
2337   ExpectInt32("child.interceptor_age", 9999);
2338   // The last i goes to child's own property.
2339   ExpectInt32("child.age", 10000);
2340 }
2341
2342
2343 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2344   v8::HandleScope scope(CcTest::isolate());
2345   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2346   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2347   child->Inherit(parent);
2348   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2349   LocalContext env;
2350   env->Global()->Set(v8_str("Child"), child->GetFunction());
2351   CompileRun("var child = new Child;"
2352              "function setAge(i){ child.age = i; };"
2353              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2354   // All i >= 10000 go to child's own property.
2355   ExpectInt32("child.age", 10000);
2356   // The last i goes to the interceptor.
2357   ExpectInt32("child.interceptor_age", 9999);
2358 }
2359
2360
2361 THREADED_TEST(NamedPropertyHandlerGetter) {
2362   echo_named_call_count = 0;
2363   v8::HandleScope scope(CcTest::isolate());
2364   v8::Handle<v8::FunctionTemplate> templ =
2365       v8::FunctionTemplate::New(CcTest::isolate());
2366   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2367                                                      0, 0, 0, 0,
2368                                                      v8_str("data"));
2369   LocalContext env;
2370   env->Global()->Set(v8_str("obj"),
2371                      templ->GetFunction()->NewInstance());
2372   CHECK_EQ(echo_named_call_count, 0);
2373   v8_compile("obj.x")->Run();
2374   CHECK_EQ(echo_named_call_count, 1);
2375   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2376   v8::Handle<Value> str = CompileRun(code);
2377   String::Utf8Value value(str);
2378   CHECK_EQ(*value, "oddlepoddle");
2379   // Check default behavior
2380   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2381   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2382   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2383 }
2384
2385
2386 int echo_indexed_call_count = 0;
2387
2388
2389 static void EchoIndexedProperty(
2390     uint32_t index,
2391     const v8::PropertyCallbackInfo<v8::Value>& info) {
2392   ApiTestFuzzer::Fuzz();
2393   CHECK_EQ(v8_num(637), info.Data());
2394   echo_indexed_call_count++;
2395   info.GetReturnValue().Set(v8_num(index));
2396 }
2397
2398
2399 THREADED_TEST(IndexedPropertyHandlerGetter) {
2400   v8::Isolate* isolate = CcTest::isolate();
2401   v8::HandleScope scope(isolate);
2402   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2403   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2404                                                        0, 0, 0, 0,
2405                                                        v8_num(637));
2406   LocalContext env;
2407   env->Global()->Set(v8_str("obj"),
2408                      templ->GetFunction()->NewInstance());
2409   Local<Script> script = v8_compile("obj[900]");
2410   CHECK_EQ(script->Run()->Int32Value(), 900);
2411 }
2412
2413
2414 v8::Handle<v8::Object> bottom;
2415
2416 static void CheckThisIndexedPropertyHandler(
2417     uint32_t index,
2418     const v8::PropertyCallbackInfo<v8::Value>& info) {
2419   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2420   ApiTestFuzzer::Fuzz();
2421   CHECK(info.This()->Equals(bottom));
2422 }
2423
2424 static void CheckThisNamedPropertyHandler(
2425     Local<String> name,
2426     const v8::PropertyCallbackInfo<v8::Value>& info) {
2427   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2428   ApiTestFuzzer::Fuzz();
2429   CHECK(info.This()->Equals(bottom));
2430 }
2431
2432 void CheckThisIndexedPropertySetter(
2433     uint32_t index,
2434     Local<Value> value,
2435     const v8::PropertyCallbackInfo<v8::Value>& info) {
2436   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2437   ApiTestFuzzer::Fuzz();
2438   CHECK(info.This()->Equals(bottom));
2439 }
2440
2441
2442 void CheckThisNamedPropertySetter(
2443     Local<String> property,
2444     Local<Value> value,
2445     const v8::PropertyCallbackInfo<v8::Value>& info) {
2446   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2447   ApiTestFuzzer::Fuzz();
2448   CHECK(info.This()->Equals(bottom));
2449 }
2450
2451 void CheckThisIndexedPropertyQuery(
2452     uint32_t index,
2453     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2454   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2455   ApiTestFuzzer::Fuzz();
2456   CHECK(info.This()->Equals(bottom));
2457 }
2458
2459
2460 void CheckThisNamedPropertyQuery(
2461     Local<String> property,
2462     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2463   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2464   ApiTestFuzzer::Fuzz();
2465   CHECK(info.This()->Equals(bottom));
2466 }
2467
2468
2469 void CheckThisIndexedPropertyDeleter(
2470     uint32_t index,
2471     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2472   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2473   ApiTestFuzzer::Fuzz();
2474   CHECK(info.This()->Equals(bottom));
2475 }
2476
2477
2478 void CheckThisNamedPropertyDeleter(
2479     Local<String> property,
2480     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2481   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2482   ApiTestFuzzer::Fuzz();
2483   CHECK(info.This()->Equals(bottom));
2484 }
2485
2486
2487 void CheckThisIndexedPropertyEnumerator(
2488     const v8::PropertyCallbackInfo<v8::Array>& info) {
2489   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2490   ApiTestFuzzer::Fuzz();
2491   CHECK(info.This()->Equals(bottom));
2492 }
2493
2494
2495 void CheckThisNamedPropertyEnumerator(
2496     const v8::PropertyCallbackInfo<v8::Array>& info) {
2497   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2498   ApiTestFuzzer::Fuzz();
2499   CHECK(info.This()->Equals(bottom));
2500 }
2501
2502
2503 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2504   LocalContext env;
2505   v8::Isolate* isolate = env->GetIsolate();
2506   v8::HandleScope scope(isolate);
2507
2508   // Set up a prototype chain with three interceptors.
2509   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2510   templ->InstanceTemplate()->SetIndexedPropertyHandler(
2511       CheckThisIndexedPropertyHandler,
2512       CheckThisIndexedPropertySetter,
2513       CheckThisIndexedPropertyQuery,
2514       CheckThisIndexedPropertyDeleter,
2515       CheckThisIndexedPropertyEnumerator);
2516
2517   templ->InstanceTemplate()->SetNamedPropertyHandler(
2518       CheckThisNamedPropertyHandler,
2519       CheckThisNamedPropertySetter,
2520       CheckThisNamedPropertyQuery,
2521       CheckThisNamedPropertyDeleter,
2522       CheckThisNamedPropertyEnumerator);
2523
2524   bottom = templ->GetFunction()->NewInstance();
2525   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2526   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2527
2528   bottom->SetPrototype(middle);
2529   middle->SetPrototype(top);
2530   env->Global()->Set(v8_str("obj"), bottom);
2531
2532   // Indexed and named get.
2533   CompileRun("obj[0]");
2534   CompileRun("obj.x");
2535
2536   // Indexed and named set.
2537   CompileRun("obj[1] = 42");
2538   CompileRun("obj.y = 42");
2539
2540   // Indexed and named query.
2541   CompileRun("0 in obj");
2542   CompileRun("'x' in obj");
2543
2544   // Indexed and named deleter.
2545   CompileRun("delete obj[0]");
2546   CompileRun("delete obj.x");
2547
2548   // Enumerators.
2549   CompileRun("for (var p in obj) ;");
2550 }
2551
2552
2553 static void PrePropertyHandlerGet(
2554     Local<String> key,
2555     const v8::PropertyCallbackInfo<v8::Value>& info) {
2556   ApiTestFuzzer::Fuzz();
2557   if (v8_str("pre")->Equals(key)) {
2558     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2559   }
2560 }
2561
2562
2563 static void PrePropertyHandlerQuery(
2564     Local<String> key,
2565     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2566   if (v8_str("pre")->Equals(key)) {
2567     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2568   }
2569 }
2570
2571
2572 THREADED_TEST(PrePropertyHandler) {
2573   v8::Isolate* isolate = CcTest::isolate();
2574   v8::HandleScope scope(isolate);
2575   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2576   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2577                                                     0,
2578                                                     PrePropertyHandlerQuery);
2579   LocalContext env(NULL, desc->InstanceTemplate());
2580   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2581   v8::Handle<Value> result_pre = CompileRun("pre");
2582   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2583   v8::Handle<Value> result_on = CompileRun("on");
2584   CHECK_EQ(v8_str("Object: on"), result_on);
2585   v8::Handle<Value> result_post = CompileRun("post");
2586   CHECK(result_post.IsEmpty());
2587 }
2588
2589
2590 THREADED_TEST(UndefinedIsNotEnumerable) {
2591   LocalContext env;
2592   v8::HandleScope scope(env->GetIsolate());
2593   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2594   CHECK(result->IsFalse());
2595 }
2596
2597
2598 v8::Handle<Script> call_recursively_script;
2599 static const int kTargetRecursionDepth = 200;  // near maximum
2600
2601
2602 static void CallScriptRecursivelyCall(
2603     const v8::FunctionCallbackInfo<v8::Value>& args) {
2604   ApiTestFuzzer::Fuzz();
2605   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2606   if (depth == kTargetRecursionDepth) return;
2607   args.This()->Set(v8_str("depth"),
2608                    v8::Integer::New(args.GetIsolate(), depth + 1));
2609   args.GetReturnValue().Set(call_recursively_script->Run());
2610 }
2611
2612
2613 static void CallFunctionRecursivelyCall(
2614     const v8::FunctionCallbackInfo<v8::Value>& args) {
2615   ApiTestFuzzer::Fuzz();
2616   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2617   if (depth == kTargetRecursionDepth) {
2618     printf("[depth = %d]\n", depth);
2619     return;
2620   }
2621   args.This()->Set(v8_str("depth"),
2622                    v8::Integer::New(args.GetIsolate(), depth + 1));
2623   v8::Handle<Value> function =
2624       args.This()->Get(v8_str("callFunctionRecursively"));
2625   args.GetReturnValue().Set(
2626       function.As<Function>()->Call(args.This(), 0, NULL));
2627 }
2628
2629
2630 THREADED_TEST(DeepCrossLanguageRecursion) {
2631   v8::Isolate* isolate = CcTest::isolate();
2632   v8::HandleScope scope(isolate);
2633   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2634   global->Set(v8_str("callScriptRecursively"),
2635               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2636   global->Set(v8_str("callFunctionRecursively"),
2637               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2638   LocalContext env(NULL, global);
2639
2640   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2641   call_recursively_script = v8_compile("callScriptRecursively()");
2642   call_recursively_script->Run();
2643   call_recursively_script = v8::Handle<Script>();
2644
2645   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2646   CompileRun("callFunctionRecursively()");
2647 }
2648
2649
2650 static void ThrowingPropertyHandlerGet(
2651     Local<String> key,
2652     const v8::PropertyCallbackInfo<v8::Value>& info) {
2653   ApiTestFuzzer::Fuzz();
2654   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2655 }
2656
2657
2658 static void ThrowingPropertyHandlerSet(
2659     Local<String> key,
2660     Local<Value>,
2661     const v8::PropertyCallbackInfo<v8::Value>& info) {
2662   info.GetIsolate()->ThrowException(key);
2663   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2664 }
2665
2666
2667 THREADED_TEST(CallbackExceptionRegression) {
2668   v8::Isolate* isolate = CcTest::isolate();
2669   v8::HandleScope scope(isolate);
2670   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2671   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2672                                ThrowingPropertyHandlerSet);
2673   LocalContext env;
2674   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2675   v8::Handle<Value> otto = CompileRun(
2676       "try { with (obj) { otto; } } catch (e) { e; }");
2677   CHECK_EQ(v8_str("otto"), otto);
2678   v8::Handle<Value> netto = CompileRun(
2679       "try { with (obj) { netto = 4; } } catch (e) { e; }");
2680   CHECK_EQ(v8_str("netto"), netto);
2681 }
2682
2683
2684 THREADED_TEST(FunctionPrototype) {
2685   v8::Isolate* isolate = CcTest::isolate();
2686   v8::HandleScope scope(isolate);
2687   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2688   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2689   LocalContext env;
2690   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2691   Local<Script> script = v8_compile("Foo.prototype.plak");
2692   CHECK_EQ(script->Run()->Int32Value(), 321);
2693 }
2694
2695
2696 THREADED_TEST(InternalFields) {
2697   LocalContext env;
2698   v8::Isolate* isolate = env->GetIsolate();
2699   v8::HandleScope scope(isolate);
2700
2701   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2702   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2703   instance_templ->SetInternalFieldCount(1);
2704   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2705   CHECK_EQ(1, obj->InternalFieldCount());
2706   CHECK(obj->GetInternalField(0)->IsUndefined());
2707   obj->SetInternalField(0, v8_num(17));
2708   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2709 }
2710
2711
2712 THREADED_TEST(GlobalObjectInternalFields) {
2713   v8::Isolate* isolate = CcTest::isolate();
2714   v8::HandleScope scope(isolate);
2715   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2716   global_template->SetInternalFieldCount(1);
2717   LocalContext env(NULL, global_template);
2718   v8::Handle<v8::Object> global_proxy = env->Global();
2719   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2720   CHECK_EQ(1, global->InternalFieldCount());
2721   CHECK(global->GetInternalField(0)->IsUndefined());
2722   global->SetInternalField(0, v8_num(17));
2723   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2724 }
2725
2726
2727 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2728   LocalContext env;
2729   v8::HandleScope scope(CcTest::isolate());
2730
2731   v8::Local<v8::Object> global = env->Global();
2732   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2733   CHECK(global->HasRealIndexedProperty(0));
2734 }
2735
2736
2737 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2738                                                void* value) {
2739   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2740   obj->SetAlignedPointerInInternalField(0, value);
2741   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2742   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2743 }
2744
2745
2746 THREADED_TEST(InternalFieldsAlignedPointers) {
2747   LocalContext env;
2748   v8::Isolate* isolate = env->GetIsolate();
2749   v8::HandleScope scope(isolate);
2750
2751   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2752   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2753   instance_templ->SetInternalFieldCount(1);
2754   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2755   CHECK_EQ(1, obj->InternalFieldCount());
2756
2757   CheckAlignedPointerInInternalField(obj, NULL);
2758
2759   int* heap_allocated = new int[100];
2760   CheckAlignedPointerInInternalField(obj, heap_allocated);
2761   delete[] heap_allocated;
2762
2763   int stack_allocated[100];
2764   CheckAlignedPointerInInternalField(obj, stack_allocated);
2765
2766   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2767   CheckAlignedPointerInInternalField(obj, huge);
2768
2769   v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2770   CHECK_EQ(1, Object::InternalFieldCount(persistent));
2771   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2772 }
2773
2774
2775 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2776                                               int index,
2777                                               void* value) {
2778   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2779   (*env)->SetAlignedPointerInEmbedderData(index, value);
2780   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2781   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2782 }
2783
2784
2785 static void* AlignedTestPointer(int i) {
2786   return reinterpret_cast<void*>(i * 1234);
2787 }
2788
2789
2790 THREADED_TEST(EmbedderDataAlignedPointers) {
2791   LocalContext env;
2792   v8::HandleScope scope(env->GetIsolate());
2793
2794   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2795
2796   int* heap_allocated = new int[100];
2797   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2798   delete[] heap_allocated;
2799
2800   int stack_allocated[100];
2801   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2802
2803   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2804   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2805
2806   // Test growing of the embedder data's backing store.
2807   for (int i = 0; i < 100; i++) {
2808     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2809   }
2810   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2811   for (int i = 0; i < 100; i++) {
2812     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2813   }
2814 }
2815
2816
2817 static void CheckEmbedderData(LocalContext* env,
2818                               int index,
2819                               v8::Handle<Value> data) {
2820   (*env)->SetEmbedderData(index, data);
2821   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2822 }
2823
2824
2825 THREADED_TEST(EmbedderData) {
2826   LocalContext env;
2827   v8::Isolate* isolate = env->GetIsolate();
2828   v8::HandleScope scope(isolate);
2829
2830   CheckEmbedderData(
2831       &env, 3,
2832       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2833   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2834                                                      "over the lazy dog."));
2835   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2836   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2837 }
2838
2839
2840 THREADED_TEST(GetIsolate) {
2841   LocalContext env;
2842   v8::Isolate* isolate = env->GetIsolate();
2843   v8::HandleScope scope(isolate);
2844   Local<v8::Object> obj = v8::Object::New(isolate);
2845   CHECK_EQ(isolate, obj->GetIsolate());
2846   CHECK_EQ(isolate, CcTest::global()->GetIsolate());
2847 }
2848
2849
2850 THREADED_TEST(IdentityHash) {
2851   LocalContext env;
2852   v8::Isolate* isolate = env->GetIsolate();
2853   v8::HandleScope scope(isolate);
2854
2855   // Ensure that the test starts with an fresh heap to test whether the hash
2856   // code is based on the address.
2857   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2858   Local<v8::Object> obj = v8::Object::New(isolate);
2859   int hash = obj->GetIdentityHash();
2860   int hash1 = obj->GetIdentityHash();
2861   CHECK_EQ(hash, hash1);
2862   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2863   // Since the identity hash is essentially a random number two consecutive
2864   // objects should not be assigned the same hash code. If the test below fails
2865   // the random number generator should be evaluated.
2866   CHECK_NE(hash, hash2);
2867   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2868   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2869   // Make sure that the identity hash is not based on the initial address of
2870   // the object alone. If the test below fails the random number generator
2871   // should be evaluated.
2872   CHECK_NE(hash, hash3);
2873   int hash4 = obj->GetIdentityHash();
2874   CHECK_EQ(hash, hash4);
2875
2876   // Check identity hashes behaviour in the presence of JS accessors.
2877   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2878   {
2879     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2880     Local<v8::Object> o1 = v8::Object::New(isolate);
2881     Local<v8::Object> o2 = v8::Object::New(isolate);
2882     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2883   }
2884   {
2885     CompileRun(
2886         "function cnst() { return 42; };\n"
2887         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2888     Local<v8::Object> o1 = v8::Object::New(isolate);
2889     Local<v8::Object> o2 = v8::Object::New(isolate);
2890     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2891   }
2892 }
2893
2894
2895 THREADED_TEST(GlobalProxyIdentityHash) {
2896   LocalContext env;
2897   v8::Isolate* isolate = env->GetIsolate();
2898   v8::HandleScope scope(isolate);
2899   Handle<Object> global_proxy = env->Global();
2900   int hash1 = global_proxy->GetIdentityHash();
2901   // Hash should be retained after being detached.
2902   env->DetachGlobal();
2903   int hash2 = global_proxy->GetIdentityHash();
2904   CHECK_EQ(hash1, hash2);
2905   {
2906     // Re-attach global proxy to a new context, hash should stay the same.
2907     LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2908     int hash3 = global_proxy->GetIdentityHash();
2909     CHECK_EQ(hash1, hash3);
2910   }
2911 }
2912
2913
2914 THREADED_TEST(SymbolProperties) {
2915   LocalContext env;
2916   v8::Isolate* isolate = env->GetIsolate();
2917   v8::HandleScope scope(isolate);
2918
2919   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2920   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2921   v8::Local<v8::Symbol> sym2 =
2922       v8::Symbol::New(isolate, v8_str("my-symbol"));
2923   v8::Local<v8::Symbol> sym3 =
2924       v8::Symbol::New(isolate, v8_str("sym3"));
2925
2926   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2927
2928   // Check basic symbol functionality.
2929   CHECK(sym1->IsSymbol());
2930   CHECK(sym2->IsSymbol());
2931   CHECK(!obj->IsSymbol());
2932
2933   CHECK(sym1->Equals(sym1));
2934   CHECK(sym2->Equals(sym2));
2935   CHECK(!sym1->Equals(sym2));
2936   CHECK(!sym2->Equals(sym1));
2937   CHECK(sym1->StrictEquals(sym1));
2938   CHECK(sym2->StrictEquals(sym2));
2939   CHECK(!sym1->StrictEquals(sym2));
2940   CHECK(!sym2->StrictEquals(sym1));
2941
2942   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2943
2944   v8::Local<v8::Value> sym_val = sym2;
2945   CHECK(sym_val->IsSymbol());
2946   CHECK(sym_val->Equals(sym2));
2947   CHECK(sym_val->StrictEquals(sym2));
2948   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2949
2950   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2951   CHECK(sym_obj->IsSymbolObject());
2952   CHECK(!sym2->IsSymbolObject());
2953   CHECK(!obj->IsSymbolObject());
2954   CHECK(!sym_obj->Equals(sym2));
2955   CHECK(!sym_obj->StrictEquals(sym2));
2956   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2957   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2958
2959   // Make sure delete of a non-existent symbol property works.
2960   CHECK(obj->Delete(sym1));
2961   CHECK(!obj->Has(sym1));
2962
2963   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2964   CHECK(obj->Has(sym1));
2965   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2966   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2967   CHECK(obj->Has(sym1));
2968   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2969   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2970
2971   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2972   int num_props = obj->GetPropertyNames()->Length();
2973   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2974                  v8::Integer::New(isolate, 20)));
2975   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2976   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2977
2978   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2979
2980   CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
2981   CHECK(obj->Get(sym3)->IsUndefined());
2982   CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
2983   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2984   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2985       v8::Integer::New(isolate, 42)));
2986
2987   // Add another property and delete it afterwards to force the object in
2988   // slow case.
2989   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2990   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2991   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2992   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2993   CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
2994
2995   CHECK(obj->Has(sym1));
2996   CHECK(obj->Has(sym2));
2997   CHECK(obj->Has(sym3));
2998   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2999   CHECK(obj->Delete(sym2));
3000   CHECK(obj->Has(sym1));
3001   CHECK(!obj->Has(sym2));
3002   CHECK(obj->Has(sym3));
3003   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
3004   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3005   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3006   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3007       v8::Integer::New(isolate, 42)));
3008   CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
3009
3010   // Symbol properties are inherited.
3011   v8::Local<v8::Object> child = v8::Object::New(isolate);
3012   child->SetPrototype(obj);
3013   CHECK(child->Has(sym1));
3014   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
3015   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3016   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3017       v8::Integer::New(isolate, 42)));
3018   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3019 }
3020
3021
3022 THREADED_TEST(SymbolTemplateProperties) {
3023   LocalContext env;
3024   v8::Isolate* isolate = env->GetIsolate();
3025   v8::HandleScope scope(isolate);
3026   v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3027   v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3028   CHECK(!name.IsEmpty());
3029   foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3030   v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
3031   CHECK(!new_instance.IsEmpty());
3032   CHECK(new_instance->Has(name));
3033 }
3034
3035
3036 THREADED_TEST(PrivateProperties) {
3037   LocalContext env;
3038   v8::Isolate* isolate = env->GetIsolate();
3039   v8::HandleScope scope(isolate);
3040
3041   v8::Local<v8::Object> obj = v8::Object::New(isolate);
3042   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3043   v8::Local<v8::Private> priv2 =
3044       v8::Private::New(isolate, v8_str("my-private"));
3045
3046   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3047
3048   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
3049
3050   // Make sure delete of a non-existent private symbol property works.
3051   CHECK(obj->DeletePrivate(priv1));
3052   CHECK(!obj->HasPrivate(priv1));
3053
3054   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
3055   CHECK(obj->HasPrivate(priv1));
3056   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
3057   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
3058   CHECK(obj->HasPrivate(priv1));
3059   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3060
3061   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
3062   int num_props = obj->GetPropertyNames()->Length();
3063   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
3064                  v8::Integer::New(isolate, 20)));
3065   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3066   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
3067
3068   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3069
3070   // Add another property and delete it afterwards to force the object in
3071   // slow case.
3072   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
3073   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3074   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
3075   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3076   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3077
3078   CHECK(obj->HasPrivate(priv1));
3079   CHECK(obj->HasPrivate(priv2));
3080   CHECK(obj->DeletePrivate(priv2));
3081   CHECK(obj->HasPrivate(priv1));
3082   CHECK(!obj->HasPrivate(priv2));
3083   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3084   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3085
3086   // Private properties are inherited (for the time being).
3087   v8::Local<v8::Object> child = v8::Object::New(isolate);
3088   child->SetPrototype(obj);
3089   CHECK(child->HasPrivate(priv1));
3090   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
3091   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3092 }
3093
3094
3095 THREADED_TEST(GlobalSymbols) {
3096   LocalContext env;
3097   v8::Isolate* isolate = env->GetIsolate();
3098   v8::HandleScope scope(isolate);
3099
3100   v8::Local<String> name = v8_str("my-symbol");
3101   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3102   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3103   CHECK(glob2->SameValue(glob));
3104
3105   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3106   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3107   CHECK(glob_api2->SameValue(glob_api));
3108   CHECK(!glob_api->SameValue(glob));
3109
3110   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3111   CHECK(!sym->SameValue(glob));
3112
3113   CompileRun("var sym2 = Symbol.for('my-symbol')");
3114   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
3115   CHECK(sym2->SameValue(glob));
3116   CHECK(!sym2->SameValue(glob_api));
3117 }
3118
3119
3120 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3121                                  const char* name) {
3122   LocalContext env;
3123   v8::Isolate* isolate = env->GetIsolate();
3124   v8::HandleScope scope(isolate);
3125
3126   v8::Local<v8::Symbol> symbol = getter(isolate);
3127   std::string script = std::string("var sym = ") + name;
3128   CompileRun(script.c_str());
3129   v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
3130
3131   CHECK(!value.IsEmpty());
3132   CHECK(!symbol.IsEmpty());
3133   CHECK(value->SameValue(symbol));
3134 }
3135
3136
3137 THREADED_TEST(WellKnownSymbols) {
3138   CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3139   CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3140 }
3141
3142
3143 THREADED_TEST(GlobalPrivates) {
3144   LocalContext env;
3145   v8::Isolate* isolate = env->GetIsolate();
3146   v8::HandleScope scope(isolate);
3147
3148   v8::Local<String> name = v8_str("my-private");
3149   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3150   v8::Local<v8::Object> obj = v8::Object::New(isolate);
3151   CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
3152
3153   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3154   CHECK(obj->HasPrivate(glob2));
3155
3156   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3157   CHECK(!obj->HasPrivate(priv));
3158
3159   CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
3160   v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
3161   CHECK(!obj->Has(intern));
3162 }
3163
3164
3165 class ScopedArrayBufferContents {
3166  public:
3167   explicit ScopedArrayBufferContents(
3168       const v8::ArrayBuffer::Contents& contents)
3169     : contents_(contents) {}
3170   ~ScopedArrayBufferContents() { free(contents_.Data()); }
3171   void* Data() const { return contents_.Data(); }
3172   size_t ByteLength() const { return contents_.ByteLength(); }
3173  private:
3174   const v8::ArrayBuffer::Contents contents_;
3175 };
3176
3177 template <typename T>
3178 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
3179   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3180   for (int i = 0; i < value->InternalFieldCount(); i++) {
3181     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
3182   }
3183 }
3184
3185
3186 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3187   LocalContext env;
3188   v8::Isolate* isolate = env->GetIsolate();
3189   v8::HandleScope handle_scope(isolate);
3190
3191   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3192   CheckInternalFieldsAreZero(ab);
3193   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3194   CHECK(!ab->IsExternal());
3195   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3196
3197   ScopedArrayBufferContents ab_contents(ab->Externalize());
3198   CHECK(ab->IsExternal());
3199
3200   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3201   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3202   DCHECK(data != NULL);
3203   env->Global()->Set(v8_str("ab"), ab);
3204
3205   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
3206   CHECK_EQ(1024, result->Int32Value());
3207
3208   result = CompileRun("var u8 = new Uint8Array(ab);"
3209                       "u8[0] = 0xFF;"
3210                       "u8[1] = 0xAA;"
3211                       "u8.length");
3212   CHECK_EQ(1024, result->Int32Value());
3213   CHECK_EQ(0xFF, data[0]);
3214   CHECK_EQ(0xAA, data[1]);
3215   data[0] = 0xCC;
3216   data[1] = 0x11;
3217   result = CompileRun("u8[0] + u8[1]");
3218   CHECK_EQ(0xDD, result->Int32Value());
3219 }
3220
3221
3222 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3223   LocalContext env;
3224   v8::Isolate* isolate = env->GetIsolate();
3225   v8::HandleScope handle_scope(isolate);
3226
3227
3228   v8::Local<v8::Value> result =
3229       CompileRun("var ab1 = new ArrayBuffer(2);"
3230                  "var u8_a = new Uint8Array(ab1);"
3231                  "u8_a[0] = 0xAA;"
3232                  "u8_a[1] = 0xFF; u8_a.buffer");
3233   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3234   CheckInternalFieldsAreZero(ab1);
3235   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3236   CHECK(!ab1->IsExternal());
3237   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3238   CHECK(ab1->IsExternal());
3239
3240   result = CompileRun("ab1.byteLength");
3241   CHECK_EQ(2, result->Int32Value());
3242   result = CompileRun("u8_a[0]");
3243   CHECK_EQ(0xAA, result->Int32Value());
3244   result = CompileRun("u8_a[1]");
3245   CHECK_EQ(0xFF, result->Int32Value());
3246   result = CompileRun("var u8_b = new Uint8Array(ab1);"
3247                       "u8_b[0] = 0xBB;"
3248                       "u8_a[0]");
3249   CHECK_EQ(0xBB, result->Int32Value());
3250   result = CompileRun("u8_b[1]");
3251   CHECK_EQ(0xFF, result->Int32Value());
3252
3253   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3254   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3255   CHECK_EQ(0xBB, ab1_data[0]);
3256   CHECK_EQ(0xFF, ab1_data[1]);
3257   ab1_data[0] = 0xCC;
3258   ab1_data[1] = 0x11;
3259   result = CompileRun("u8_a[0] + u8_a[1]");
3260   CHECK_EQ(0xDD, result->Int32Value());
3261 }
3262
3263
3264 THREADED_TEST(ArrayBuffer_External) {
3265   LocalContext env;
3266   v8::Isolate* isolate = env->GetIsolate();
3267   v8::HandleScope handle_scope(isolate);
3268
3269   i::ScopedVector<uint8_t> my_data(100);
3270   memset(my_data.start(), 0, 100);
3271   Local<v8::ArrayBuffer> ab3 =
3272       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3273   CheckInternalFieldsAreZero(ab3);
3274   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3275   CHECK(ab3->IsExternal());
3276
3277   env->Global()->Set(v8_str("ab3"), ab3);
3278
3279   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3280   CHECK_EQ(100, result->Int32Value());
3281
3282   result = CompileRun("var u8_b = new Uint8Array(ab3);"
3283                       "u8_b[0] = 0xBB;"
3284                       "u8_b[1] = 0xCC;"
3285                       "u8_b.length");
3286   CHECK_EQ(100, result->Int32Value());
3287   CHECK_EQ(0xBB, my_data[0]);
3288   CHECK_EQ(0xCC, my_data[1]);
3289   my_data[0] = 0xCC;
3290   my_data[1] = 0x11;
3291   result = CompileRun("u8_b[0] + u8_b[1]");
3292   CHECK_EQ(0xDD, result->Int32Value());
3293 }
3294
3295
3296 THREADED_TEST(ArrayBuffer_DisableNeuter) {
3297   LocalContext env;
3298   v8::Isolate* isolate = env->GetIsolate();
3299   v8::HandleScope handle_scope(isolate);
3300
3301   i::ScopedVector<uint8_t> my_data(100);
3302   memset(my_data.start(), 0, 100);
3303   Local<v8::ArrayBuffer> ab =
3304       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3305   CHECK(ab->IsNeuterable());
3306
3307   i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
3308   buf->set_is_neuterable(false);
3309
3310   CHECK(!ab->IsNeuterable());
3311 }
3312
3313
3314 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3315   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3316   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3317 }
3318
3319
3320 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3321   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3322   CHECK_EQ(0, static_cast<int>(ta->Length()));
3323   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3324 }
3325
3326
3327 static void CheckIsTypedArrayVarNeutered(const char* name) {
3328   i::ScopedVector<char> source(1024);
3329   i::SNPrintF(source,
3330       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3331       name, name, name);
3332   CHECK(CompileRun(source.start())->IsTrue());
3333   v8::Handle<v8::TypedArray> ta =
3334     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3335   CheckIsNeutered(ta);
3336 }
3337
3338
3339 template <typename TypedArray, int kElementSize>
3340 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3341                                          int byteOffset,
3342                                          int length) {
3343   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3344   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3345   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3346   CHECK_EQ(length, static_cast<int>(ta->Length()));
3347   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3348   return ta;
3349 }
3350
3351
3352 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3353   LocalContext env;
3354   v8::Isolate* isolate = env->GetIsolate();
3355   v8::HandleScope handle_scope(isolate);
3356
3357   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3358
3359   v8::Handle<v8::Uint8Array> u8a =
3360     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3361   v8::Handle<v8::Uint8ClampedArray> u8c =
3362     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3363   v8::Handle<v8::Int8Array> i8a =
3364     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3365
3366   v8::Handle<v8::Uint16Array> u16a =
3367     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3368   v8::Handle<v8::Int16Array> i16a =
3369     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3370
3371   v8::Handle<v8::Uint32Array> u32a =
3372     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3373   v8::Handle<v8::Int32Array> i32a =
3374     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3375
3376   v8::Handle<v8::Float32Array> f32a =
3377     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3378   v8::Handle<v8::Float64Array> f64a =
3379     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3380
3381   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3382   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3383   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3384   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3385
3386   ScopedArrayBufferContents contents(buffer->Externalize());
3387   buffer->Neuter();
3388   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3389   CheckIsNeutered(u8a);
3390   CheckIsNeutered(u8c);
3391   CheckIsNeutered(i8a);
3392   CheckIsNeutered(u16a);
3393   CheckIsNeutered(i16a);
3394   CheckIsNeutered(u32a);
3395   CheckIsNeutered(i32a);
3396   CheckIsNeutered(f32a);
3397   CheckIsNeutered(f64a);
3398   CheckDataViewIsNeutered(dv);
3399 }
3400
3401
3402 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3403   LocalContext env;
3404   v8::Isolate* isolate = env->GetIsolate();
3405   v8::HandleScope handle_scope(isolate);
3406
3407   CompileRun(
3408       "var ab = new ArrayBuffer(1024);"
3409       "var u8a = new Uint8Array(ab, 1, 1023);"
3410       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3411       "var i8a = new Int8Array(ab, 1, 1023);"
3412       "var u16a = new Uint16Array(ab, 2, 511);"
3413       "var i16a = new Int16Array(ab, 2, 511);"
3414       "var u32a = new Uint32Array(ab, 4, 255);"
3415       "var i32a = new Int32Array(ab, 4, 255);"
3416       "var f32a = new Float32Array(ab, 4, 255);"
3417       "var f64a = new Float64Array(ab, 8, 127);"
3418       "var dv = new DataView(ab, 1, 1023);");
3419
3420   v8::Handle<v8::ArrayBuffer> ab =
3421       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3422
3423   v8::Handle<v8::DataView> dv =
3424     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3425
3426   ScopedArrayBufferContents contents(ab->Externalize());
3427   ab->Neuter();
3428   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3429   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3430
3431   CheckIsTypedArrayVarNeutered("u8a");
3432   CheckIsTypedArrayVarNeutered("u8c");
3433   CheckIsTypedArrayVarNeutered("i8a");
3434   CheckIsTypedArrayVarNeutered("u16a");
3435   CheckIsTypedArrayVarNeutered("i16a");
3436   CheckIsTypedArrayVarNeutered("u32a");
3437   CheckIsTypedArrayVarNeutered("i32a");
3438   CheckIsTypedArrayVarNeutered("f32a");
3439   CheckIsTypedArrayVarNeutered("f64a");
3440
3441   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3442   CheckDataViewIsNeutered(dv);
3443 }
3444
3445
3446
3447 THREADED_TEST(HiddenProperties) {
3448   LocalContext env;
3449   v8::Isolate* isolate = env->GetIsolate();
3450   v8::HandleScope scope(isolate);
3451
3452   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3453   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3454   v8::Local<v8::String> empty = v8_str("");
3455   v8::Local<v8::String> prop_name = v8_str("prop_name");
3456
3457   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3458
3459   // Make sure delete of a non-existent hidden value works
3460   CHECK(obj->DeleteHiddenValue(key));
3461
3462   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3463   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3464   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3465   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3466
3467   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3468
3469   // Make sure we do not find the hidden property.
3470   CHECK(!obj->Has(empty));
3471   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3472   CHECK(obj->Get(empty)->IsUndefined());
3473   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3474   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3475   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3476   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3477
3478   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3479
3480   // Add another property and delete it afterwards to force the object in
3481   // slow case.
3482   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3483   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3484   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3485   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3486   CHECK(obj->Delete(prop_name));
3487   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3488
3489   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3490
3491   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3492   CHECK(obj->GetHiddenValue(key).IsEmpty());
3493
3494   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3495   CHECK(obj->DeleteHiddenValue(key));
3496   CHECK(obj->GetHiddenValue(key).IsEmpty());
3497 }
3498
3499
3500 THREADED_TEST(Regress97784) {
3501   // Regression test for crbug.com/97784
3502   // Messing with the Object.prototype should not have effect on
3503   // hidden properties.
3504   LocalContext env;
3505   v8::HandleScope scope(env->GetIsolate());
3506
3507   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3508   v8::Local<v8::String> key = v8_str("hidden");
3509
3510   CompileRun(
3511       "set_called = false;"
3512       "Object.defineProperty("
3513       "    Object.prototype,"
3514       "    'hidden',"
3515       "    {get: function() { return 45; },"
3516       "     set: function() { set_called = true; }})");
3517
3518   CHECK(obj->GetHiddenValue(key).IsEmpty());
3519   // Make sure that the getter and setter from Object.prototype is not invoked.
3520   // If it did we would have full access to the hidden properties in
3521   // the accessor.
3522   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3523   ExpectFalse("set_called");
3524   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3525 }
3526
3527
3528 static bool interceptor_for_hidden_properties_called;
3529 static void InterceptorForHiddenProperties(
3530     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3531   interceptor_for_hidden_properties_called = true;
3532 }
3533
3534
3535 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3536   LocalContext context;
3537   v8::Isolate* isolate = context->GetIsolate();
3538   v8::HandleScope scope(isolate);
3539
3540   interceptor_for_hidden_properties_called = false;
3541
3542   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3543
3544   // Associate an interceptor with an object and start setting hidden values.
3545   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3546   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3547   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3548   Local<v8::Function> function = fun_templ->GetFunction();
3549   Local<v8::Object> obj = function->NewInstance();
3550   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3551   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3552   CHECK(!interceptor_for_hidden_properties_called);
3553 }
3554
3555
3556 THREADED_TEST(External) {
3557   v8::HandleScope scope(CcTest::isolate());
3558   int x = 3;
3559   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3560   LocalContext env;
3561   env->Global()->Set(v8_str("ext"), ext);
3562   Local<Value> reext_obj = CompileRun("this.ext");
3563   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3564   int* ptr = static_cast<int*>(reext->Value());
3565   CHECK_EQ(x, 3);
3566   *ptr = 10;
3567   CHECK_EQ(x, 10);
3568
3569   // Make sure unaligned pointers are wrapped properly.
3570   char* data = i::StrDup("0123456789");
3571   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3572   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3573   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3574   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3575
3576   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3577   CHECK_EQ('0', *char_ptr);
3578   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3579   CHECK_EQ('1', *char_ptr);
3580   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3581   CHECK_EQ('2', *char_ptr);
3582   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3583   CHECK_EQ('3', *char_ptr);
3584   i::DeleteArray(data);
3585 }
3586
3587
3588 THREADED_TEST(GlobalHandle) {
3589   v8::Isolate* isolate = CcTest::isolate();
3590   v8::Persistent<String> global;
3591   {
3592     v8::HandleScope scope(isolate);
3593     global.Reset(isolate, v8_str("str"));
3594   }
3595   {
3596     v8::HandleScope scope(isolate);
3597     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3598   }
3599   global.Reset();
3600   {
3601     v8::HandleScope scope(isolate);
3602     global.Reset(isolate, v8_str("str"));
3603   }
3604   {
3605     v8::HandleScope scope(isolate);
3606     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3607   }
3608   global.Reset();
3609 }
3610
3611
3612 THREADED_TEST(ResettingGlobalHandle) {
3613   v8::Isolate* isolate = CcTest::isolate();
3614   v8::Persistent<String> global;
3615   {
3616     v8::HandleScope scope(isolate);
3617     global.Reset(isolate, v8_str("str"));
3618   }
3619   v8::internal::GlobalHandles* global_handles =
3620       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3621   int initial_handle_count = global_handles->global_handles_count();
3622   {
3623     v8::HandleScope scope(isolate);
3624     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3625   }
3626   {
3627     v8::HandleScope scope(isolate);
3628     global.Reset(isolate, v8_str("longer"));
3629   }
3630   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3631   {
3632     v8::HandleScope scope(isolate);
3633     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3634   }
3635   global.Reset();
3636   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3637 }
3638
3639
3640 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3641   v8::Isolate* isolate = CcTest::isolate();
3642   v8::Persistent<String> global;
3643   {
3644     v8::HandleScope scope(isolate);
3645     global.Reset(isolate, v8_str("str"));
3646   }
3647   v8::internal::GlobalHandles* global_handles =
3648       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3649   int initial_handle_count = global_handles->global_handles_count();
3650   {
3651     v8::HandleScope scope(isolate);
3652     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3653   }
3654   {
3655     v8::HandleScope scope(isolate);
3656     Local<String> empty;
3657     global.Reset(isolate, empty);
3658   }
3659   CHECK(global.IsEmpty());
3660   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3661 }
3662
3663
3664 template<class T>
3665 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3666   return unique.Pass();
3667 }
3668
3669
3670 template<class T>
3671 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3672                                             const v8::Persistent<T> & global) {
3673   v8::UniquePersistent<String> unique(isolate, global);
3674   return unique.Pass();
3675 }
3676
3677
3678 THREADED_TEST(UniquePersistent) {
3679   v8::Isolate* isolate = CcTest::isolate();
3680   v8::Persistent<String> global;
3681   {
3682     v8::HandleScope scope(isolate);
3683     global.Reset(isolate, v8_str("str"));
3684   }
3685   v8::internal::GlobalHandles* global_handles =
3686       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3687   int initial_handle_count = global_handles->global_handles_count();
3688   {
3689     v8::UniquePersistent<String> unique(isolate, global);
3690     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3691     // Test assignment via Pass
3692     {
3693       v8::UniquePersistent<String> copy = unique.Pass();
3694       CHECK(unique.IsEmpty());
3695       CHECK(copy == global);
3696       CHECK_EQ(initial_handle_count + 1,
3697                global_handles->global_handles_count());
3698       unique = copy.Pass();
3699     }
3700     // Test ctor via Pass
3701     {
3702       v8::UniquePersistent<String> copy(unique.Pass());
3703       CHECK(unique.IsEmpty());
3704       CHECK(copy == global);
3705       CHECK_EQ(initial_handle_count + 1,
3706                global_handles->global_handles_count());
3707       unique = copy.Pass();
3708     }
3709     // Test pass through function call
3710     {
3711       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3712       CHECK(unique.IsEmpty());
3713       CHECK(copy == global);
3714       CHECK_EQ(initial_handle_count + 1,
3715                global_handles->global_handles_count());
3716       unique = copy.Pass();
3717     }
3718     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3719   }
3720   // Test pass from function call
3721   {
3722     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3723     CHECK(unique == global);
3724     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3725   }
3726   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3727   global.Reset();
3728 }
3729
3730
3731 template<typename K, typename V>
3732 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3733  public:
3734   typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3735       MapType;
3736   static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3737   struct WeakCallbackDataType {
3738     MapType* map;
3739     K key;
3740   };
3741   static WeakCallbackDataType* WeakCallbackParameter(
3742       MapType* map, const K& key, Local<V> value) {
3743     WeakCallbackDataType* data = new WeakCallbackDataType;
3744     data->map = map;
3745     data->key = key;
3746     return data;
3747   }
3748   static MapType* MapFromWeakCallbackData(
3749       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3750     return data.GetParameter()->map;
3751   }
3752   static K KeyFromWeakCallbackData(
3753       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3754     return data.GetParameter()->key;
3755   }
3756   static void DisposeCallbackData(WeakCallbackDataType* data) {
3757     delete data;
3758   }
3759   static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3760       K key) { }
3761 };
3762
3763
3764 template<typename Map>
3765 static void TestPersistentValueMap() {
3766   LocalContext env;
3767   v8::Isolate* isolate = env->GetIsolate();
3768   Map map(isolate);
3769   v8::internal::GlobalHandles* global_handles =
3770       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3771   int initial_handle_count = global_handles->global_handles_count();
3772   CHECK_EQ(0, static_cast<int>(map.Size()));
3773   {
3774     HandleScope scope(isolate);
3775     Local<v8::Object> obj = map.Get(7);
3776     CHECK(obj.IsEmpty());
3777     Local<v8::Object> expected = v8::Object::New(isolate);
3778     map.Set(7, expected);
3779     CHECK_EQ(1, static_cast<int>(map.Size()));
3780     obj = map.Get(7);
3781     CHECK_EQ(expected, obj);
3782     {
3783       typename Map::PersistentValueReference ref = map.GetReference(7);
3784       CHECK_EQ(expected, ref.NewLocal(isolate));
3785     }
3786     v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3787     CHECK_EQ(0, static_cast<int>(map.Size()));
3788     CHECK(expected == removed);
3789     removed = map.Remove(7);
3790     CHECK(removed.IsEmpty());
3791     map.Set(8, expected);
3792     CHECK_EQ(1, static_cast<int>(map.Size()));
3793     map.Set(8, expected);
3794     CHECK_EQ(1, static_cast<int>(map.Size()));
3795     {
3796       typename Map::PersistentValueReference ref;
3797       Local<v8::Object> expected2 = v8::Object::New(isolate);
3798       removed = map.Set(8,
3799           v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3800       CHECK_EQ(1, static_cast<int>(map.Size()));
3801       CHECK(expected == removed);
3802       CHECK_EQ(expected2, ref.NewLocal(isolate));
3803     }
3804   }
3805   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3806   if (map.IsWeak()) {
3807     reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3808         CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3809   } else {
3810     map.Clear();
3811   }
3812   CHECK_EQ(0, static_cast<int>(map.Size()));
3813   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3814 }
3815
3816
3817 TEST(PersistentValueMap) {
3818   // Default case, w/o weak callbacks:
3819   TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3820
3821   // Custom traits with weak callbacks:
3822   typedef v8::PersistentValueMap<int, v8::Object,
3823       WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3824   TestPersistentValueMap<WeakPersistentValueMap>();
3825 }
3826
3827
3828 TEST(PersistentValueVector) {
3829   LocalContext env;
3830   v8::Isolate* isolate = env->GetIsolate();
3831   v8::internal::GlobalHandles* global_handles =
3832       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3833   int handle_count = global_handles->global_handles_count();
3834   HandleScope scope(isolate);
3835
3836   v8::PersistentValueVector<v8::Object> vector(isolate);
3837
3838   Local<v8::Object> obj1 = v8::Object::New(isolate);
3839   Local<v8::Object> obj2 = v8::Object::New(isolate);
3840   v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3841
3842   CHECK(vector.IsEmpty());
3843   CHECK_EQ(0, static_cast<int>(vector.Size()));
3844
3845   vector.ReserveCapacity(3);
3846   CHECK(vector.IsEmpty());
3847
3848   vector.Append(obj1);
3849   vector.Append(obj2);
3850   vector.Append(obj1);
3851   vector.Append(obj3.Pass());
3852   vector.Append(obj1);
3853
3854   CHECK(!vector.IsEmpty());
3855   CHECK_EQ(5, static_cast<int>(vector.Size()));
3856   CHECK(obj3.IsEmpty());
3857   CHECK_EQ(obj1, vector.Get(0));
3858   CHECK_EQ(obj1, vector.Get(2));
3859   CHECK_EQ(obj1, vector.Get(4));
3860   CHECK_EQ(obj2, vector.Get(1));
3861
3862   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3863
3864   vector.Clear();
3865   CHECK(vector.IsEmpty());
3866   CHECK_EQ(0, static_cast<int>(vector.Size()));
3867   CHECK_EQ(handle_count, global_handles->global_handles_count());
3868 }
3869
3870
3871 THREADED_TEST(GlobalHandleUpcast) {
3872   v8::Isolate* isolate = CcTest::isolate();
3873   v8::HandleScope scope(isolate);
3874   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3875   v8::Persistent<String> global_string(isolate, local);
3876   v8::Persistent<Value>& global_value =
3877       v8::Persistent<Value>::Cast(global_string);
3878   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3879   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3880   global_string.Reset();
3881 }
3882
3883
3884 THREADED_TEST(HandleEquality) {
3885   v8::Isolate* isolate = CcTest::isolate();
3886   v8::Persistent<String> global1;
3887   v8::Persistent<String> global2;
3888   {
3889     v8::HandleScope scope(isolate);
3890     global1.Reset(isolate, v8_str("str"));
3891     global2.Reset(isolate, v8_str("str2"));
3892   }
3893   CHECK_EQ(global1 == global1, true);
3894   CHECK_EQ(global1 != global1, false);
3895   {
3896     v8::HandleScope scope(isolate);
3897     Local<String> local1 = Local<String>::New(isolate, global1);
3898     Local<String> local2 = Local<String>::New(isolate, global2);
3899
3900     CHECK_EQ(global1 == local1, true);
3901     CHECK_EQ(global1 != local1, false);
3902     CHECK_EQ(local1 == global1, true);
3903     CHECK_EQ(local1 != global1, false);
3904
3905     CHECK_EQ(global1 == local2, false);
3906     CHECK_EQ(global1 != local2, true);
3907     CHECK_EQ(local2 == global1, false);
3908     CHECK_EQ(local2 != global1, true);
3909
3910     CHECK_EQ(local1 == local2, false);
3911     CHECK_EQ(local1 != local2, true);
3912
3913     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3914     CHECK_EQ(local1 == anotherLocal1, true);
3915     CHECK_EQ(local1 != anotherLocal1, false);
3916   }
3917   global1.Reset();
3918   global2.Reset();
3919 }
3920
3921
3922 THREADED_TEST(LocalHandle) {
3923   v8::HandleScope scope(CcTest::isolate());
3924   v8::Local<String> local =
3925       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3926   CHECK_EQ(local->Length(), 3);
3927 }
3928
3929
3930 class WeakCallCounter {
3931  public:
3932   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3933   int id() { return id_; }
3934   void increment() { number_of_weak_calls_++; }
3935   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3936  private:
3937   int id_;
3938   int number_of_weak_calls_;
3939 };
3940
3941
3942 template<typename T>
3943 struct WeakCallCounterAndPersistent {
3944   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3945       : counter(counter) {}
3946   WeakCallCounter* counter;
3947   v8::Persistent<T> handle;
3948 };
3949
3950
3951 template <typename T>
3952 static void WeakPointerCallback(
3953     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3954   CHECK_EQ(1234, data.GetParameter()->counter->id());
3955   data.GetParameter()->counter->increment();
3956   data.GetParameter()->handle.Reset();
3957 }
3958
3959
3960 template<typename T>
3961 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3962   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3963 }
3964
3965
3966 THREADED_TEST(ApiObjectGroups) {
3967   LocalContext env;
3968   v8::Isolate* iso = env->GetIsolate();
3969   HandleScope scope(iso);
3970
3971   WeakCallCounter counter(1234);
3972
3973   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3974   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3975   WeakCallCounterAndPersistent<Value> g1c1(&counter);
3976   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3977   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3978   WeakCallCounterAndPersistent<Value> g2c1(&counter);
3979
3980   {
3981     HandleScope scope(iso);
3982     g1s1.handle.Reset(iso, Object::New(iso));
3983     g1s2.handle.Reset(iso, Object::New(iso));
3984     g1c1.handle.Reset(iso, Object::New(iso));
3985     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3986     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3987     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3988
3989     g2s1.handle.Reset(iso, Object::New(iso));
3990     g2s2.handle.Reset(iso, Object::New(iso));
3991     g2c1.handle.Reset(iso, Object::New(iso));
3992     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3993     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3994     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3995   }
3996
3997   WeakCallCounterAndPersistent<Value> root(&counter);
3998   root.handle.Reset(iso, g1s1.handle);  // make a root.
3999
4000   // Connect group 1 and 2, make a cycle.
4001   {
4002     HandleScope scope(iso);
4003     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
4004             Set(0, Local<Value>::New(iso, g2s2.handle)));
4005     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
4006             Set(0, Local<Value>::New(iso, g1s1.handle)));
4007   }
4008
4009   {
4010     UniqueId id1 = MakeUniqueId(g1s1.handle);
4011     UniqueId id2 = MakeUniqueId(g2s2.handle);
4012     iso->SetObjectGroupId(g1s1.handle, id1);
4013     iso->SetObjectGroupId(g1s2.handle, id1);
4014     iso->SetReferenceFromGroup(id1, g1c1.handle);
4015     iso->SetObjectGroupId(g2s1.handle, id2);
4016     iso->SetObjectGroupId(g2s2.handle, id2);
4017     iso->SetReferenceFromGroup(id2, g2c1.handle);
4018   }
4019   // Do a single full GC, ensure incremental marking is stopped.
4020   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4021       iso)->heap();
4022   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4023
4024   // All object should be alive.
4025   CHECK_EQ(0, counter.NumberOfWeakCalls());
4026
4027   // Weaken the root.
4028   root.handle.SetWeak(&root, &WeakPointerCallback);
4029   // But make children strong roots---all the objects (except for children)
4030   // should be collectable now.
4031   g1c1.handle.ClearWeak();
4032   g2c1.handle.ClearWeak();
4033
4034   // Groups are deleted, rebuild groups.
4035   {
4036     UniqueId id1 = MakeUniqueId(g1s1.handle);
4037     UniqueId id2 = MakeUniqueId(g2s2.handle);
4038     iso->SetObjectGroupId(g1s1.handle, id1);
4039     iso->SetObjectGroupId(g1s2.handle, id1);
4040     iso->SetReferenceFromGroup(id1, g1c1.handle);
4041     iso->SetObjectGroupId(g2s1.handle, id2);
4042     iso->SetObjectGroupId(g2s2.handle, id2);
4043     iso->SetReferenceFromGroup(id2, g2c1.handle);
4044   }
4045
4046   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4047
4048   // All objects should be gone. 5 global handles in total.
4049   CHECK_EQ(5, counter.NumberOfWeakCalls());
4050
4051   // And now make children weak again and collect them.
4052   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4053   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4054
4055   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4056   CHECK_EQ(7, counter.NumberOfWeakCalls());
4057 }
4058
4059
4060 THREADED_TEST(ApiObjectGroupsForSubtypes) {
4061   LocalContext env;
4062   v8::Isolate* iso = env->GetIsolate();
4063   HandleScope scope(iso);
4064
4065   WeakCallCounter counter(1234);
4066
4067   WeakCallCounterAndPersistent<Object> g1s1(&counter);
4068   WeakCallCounterAndPersistent<String> g1s2(&counter);
4069   WeakCallCounterAndPersistent<String> g1c1(&counter);
4070   WeakCallCounterAndPersistent<Object> g2s1(&counter);
4071   WeakCallCounterAndPersistent<String> g2s2(&counter);
4072   WeakCallCounterAndPersistent<String> g2c1(&counter);
4073
4074   {
4075     HandleScope scope(iso);
4076     g1s1.handle.Reset(iso, Object::New(iso));
4077     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
4078     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
4079     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4080     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4081     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4082
4083     g2s1.handle.Reset(iso, Object::New(iso));
4084     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
4085     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
4086     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4087     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4088     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4089   }
4090
4091   WeakCallCounterAndPersistent<Value> root(&counter);
4092   root.handle.Reset(iso, g1s1.handle);  // make a root.
4093
4094   // Connect group 1 and 2, make a cycle.
4095   {
4096     HandleScope scope(iso);
4097     CHECK(Local<Object>::New(iso, g1s1.handle)
4098               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
4099     CHECK(Local<Object>::New(iso, g2s1.handle)
4100               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
4101   }
4102
4103   {
4104     UniqueId id1 = MakeUniqueId(g1s1.handle);
4105     UniqueId id2 = MakeUniqueId(g2s2.handle);
4106     iso->SetObjectGroupId(g1s1.handle, id1);
4107     iso->SetObjectGroupId(g1s2.handle, id1);
4108     iso->SetReference(g1s1.handle, g1c1.handle);
4109     iso->SetObjectGroupId(g2s1.handle, id2);
4110     iso->SetObjectGroupId(g2s2.handle, id2);
4111     iso->SetReferenceFromGroup(id2, g2c1.handle);
4112   }
4113   // Do a single full GC, ensure incremental marking is stopped.
4114   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4115       iso)->heap();
4116   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4117
4118   // All object should be alive.
4119   CHECK_EQ(0, counter.NumberOfWeakCalls());
4120
4121   // Weaken the root.
4122   root.handle.SetWeak(&root, &WeakPointerCallback);
4123   // But make children strong roots---all the objects (except for children)
4124   // should be collectable now.
4125   g1c1.handle.ClearWeak();
4126   g2c1.handle.ClearWeak();
4127
4128   // Groups are deleted, rebuild groups.
4129   {
4130     UniqueId id1 = MakeUniqueId(g1s1.handle);
4131     UniqueId id2 = MakeUniqueId(g2s2.handle);
4132     iso->SetObjectGroupId(g1s1.handle, id1);
4133     iso->SetObjectGroupId(g1s2.handle, id1);
4134     iso->SetReference(g1s1.handle, g1c1.handle);
4135     iso->SetObjectGroupId(g2s1.handle, id2);
4136     iso->SetObjectGroupId(g2s2.handle, id2);
4137     iso->SetReferenceFromGroup(id2, g2c1.handle);
4138   }
4139
4140   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4141
4142   // All objects should be gone. 5 global handles in total.
4143   CHECK_EQ(5, counter.NumberOfWeakCalls());
4144
4145   // And now make children weak again and collect them.
4146   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4147   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4148
4149   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4150   CHECK_EQ(7, counter.NumberOfWeakCalls());
4151 }
4152
4153
4154 THREADED_TEST(ApiObjectGroupsCycle) {
4155   LocalContext env;
4156   v8::Isolate* iso = env->GetIsolate();
4157   HandleScope scope(iso);
4158
4159   WeakCallCounter counter(1234);
4160
4161   WeakCallCounterAndPersistent<Value> g1s1(&counter);
4162   WeakCallCounterAndPersistent<Value> g1s2(&counter);
4163   WeakCallCounterAndPersistent<Value> g2s1(&counter);
4164   WeakCallCounterAndPersistent<Value> g2s2(&counter);
4165   WeakCallCounterAndPersistent<Value> g3s1(&counter);
4166   WeakCallCounterAndPersistent<Value> g3s2(&counter);
4167   WeakCallCounterAndPersistent<Value> g4s1(&counter);
4168   WeakCallCounterAndPersistent<Value> g4s2(&counter);
4169
4170   {
4171     HandleScope scope(iso);
4172     g1s1.handle.Reset(iso, Object::New(iso));
4173     g1s2.handle.Reset(iso, Object::New(iso));
4174     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4175     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4176     CHECK(g1s1.handle.IsWeak());
4177     CHECK(g1s2.handle.IsWeak());
4178
4179     g2s1.handle.Reset(iso, Object::New(iso));
4180     g2s2.handle.Reset(iso, Object::New(iso));
4181     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4182     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4183     CHECK(g2s1.handle.IsWeak());
4184     CHECK(g2s2.handle.IsWeak());
4185
4186     g3s1.handle.Reset(iso, Object::New(iso));
4187     g3s2.handle.Reset(iso, Object::New(iso));
4188     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4189     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4190     CHECK(g3s1.handle.IsWeak());
4191     CHECK(g3s2.handle.IsWeak());
4192
4193     g4s1.handle.Reset(iso, Object::New(iso));
4194     g4s2.handle.Reset(iso, Object::New(iso));
4195     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
4196     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
4197     CHECK(g4s1.handle.IsWeak());
4198     CHECK(g4s2.handle.IsWeak());
4199   }
4200
4201   WeakCallCounterAndPersistent<Value> root(&counter);
4202   root.handle.Reset(iso, g1s1.handle);  // make a root.
4203
4204   // Connect groups.  We're building the following cycle:
4205   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4206   // groups.
4207   {
4208     UniqueId id1 = MakeUniqueId(g1s1.handle);
4209     UniqueId id2 = MakeUniqueId(g2s1.handle);
4210     UniqueId id3 = MakeUniqueId(g3s1.handle);
4211     UniqueId id4 = MakeUniqueId(g4s1.handle);
4212     iso->SetObjectGroupId(g1s1.handle, id1);
4213     iso->SetObjectGroupId(g1s2.handle, id1);
4214     iso->SetReferenceFromGroup(id1, g2s1.handle);
4215     iso->SetObjectGroupId(g2s1.handle, id2);
4216     iso->SetObjectGroupId(g2s2.handle, id2);
4217     iso->SetReferenceFromGroup(id2, g3s1.handle);
4218     iso->SetObjectGroupId(g3s1.handle, id3);
4219     iso->SetObjectGroupId(g3s2.handle, id3);
4220     iso->SetReferenceFromGroup(id3, g4s1.handle);
4221     iso->SetObjectGroupId(g4s1.handle, id4);
4222     iso->SetObjectGroupId(g4s2.handle, id4);
4223     iso->SetReferenceFromGroup(id4, g1s1.handle);
4224   }
4225   // Do a single full GC
4226   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4227       iso)->heap();
4228   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4229
4230   // All object should be alive.
4231   CHECK_EQ(0, counter.NumberOfWeakCalls());
4232
4233   // Weaken the root.
4234   root.handle.SetWeak(&root, &WeakPointerCallback);
4235
4236   // Groups are deleted, rebuild groups.
4237   {
4238     UniqueId id1 = MakeUniqueId(g1s1.handle);
4239     UniqueId id2 = MakeUniqueId(g2s1.handle);
4240     UniqueId id3 = MakeUniqueId(g3s1.handle);
4241     UniqueId id4 = MakeUniqueId(g4s1.handle);
4242     iso->SetObjectGroupId(g1s1.handle, id1);
4243     iso->SetObjectGroupId(g1s2.handle, id1);
4244     iso->SetReferenceFromGroup(id1, g2s1.handle);
4245     iso->SetObjectGroupId(g2s1.handle, id2);
4246     iso->SetObjectGroupId(g2s2.handle, id2);
4247     iso->SetReferenceFromGroup(id2, g3s1.handle);
4248     iso->SetObjectGroupId(g3s1.handle, id3);
4249     iso->SetObjectGroupId(g3s2.handle, id3);
4250     iso->SetReferenceFromGroup(id3, g4s1.handle);
4251     iso->SetObjectGroupId(g4s1.handle, id4);
4252     iso->SetObjectGroupId(g4s2.handle, id4);
4253     iso->SetReferenceFromGroup(id4, g1s1.handle);
4254   }
4255
4256   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4257
4258   // All objects should be gone. 9 global handles in total.
4259   CHECK_EQ(9, counter.NumberOfWeakCalls());
4260 }
4261
4262
4263 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4264 // on the buildbots, so was made non-threaded for the time being.
4265 TEST(ApiObjectGroupsCycleForScavenger) {
4266   i::FLAG_stress_compaction = false;
4267   i::FLAG_gc_global = false;
4268   LocalContext env;
4269   v8::Isolate* iso = env->GetIsolate();
4270   HandleScope scope(iso);
4271
4272   WeakCallCounter counter(1234);
4273
4274   WeakCallCounterAndPersistent<Value> g1s1(&counter);
4275   WeakCallCounterAndPersistent<Value> g1s2(&counter);
4276   WeakCallCounterAndPersistent<Value> g2s1(&counter);
4277   WeakCallCounterAndPersistent<Value> g2s2(&counter);
4278   WeakCallCounterAndPersistent<Value> g3s1(&counter);
4279   WeakCallCounterAndPersistent<Value> g3s2(&counter);
4280
4281   {
4282     HandleScope scope(iso);
4283     g1s1.handle.Reset(iso, Object::New(iso));
4284     g1s2.handle.Reset(iso, Object::New(iso));
4285     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4286     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4287
4288     g2s1.handle.Reset(iso, Object::New(iso));
4289     g2s2.handle.Reset(iso, Object::New(iso));
4290     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4291     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4292
4293     g3s1.handle.Reset(iso, Object::New(iso));
4294     g3s2.handle.Reset(iso, Object::New(iso));
4295     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4296     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4297   }
4298
4299   // Make a root.
4300   WeakCallCounterAndPersistent<Value> root(&counter);
4301   root.handle.Reset(iso, g1s1.handle);
4302   root.handle.MarkPartiallyDependent();
4303
4304   // Connect groups.  We're building the following cycle:
4305   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4306   // groups.
4307   {
4308     HandleScope handle_scope(iso);
4309     g1s1.handle.MarkPartiallyDependent();
4310     g1s2.handle.MarkPartiallyDependent();
4311     g2s1.handle.MarkPartiallyDependent();
4312     g2s2.handle.MarkPartiallyDependent();
4313     g3s1.handle.MarkPartiallyDependent();
4314     g3s2.handle.MarkPartiallyDependent();
4315     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4316     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4317     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4318         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4319     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4320     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4321     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4322         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4323     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4324     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4325     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4326         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4327   }
4328
4329   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4330       iso)->heap();
4331   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4332
4333   // All objects should be alive.
4334   CHECK_EQ(0, counter.NumberOfWeakCalls());
4335
4336   // Weaken the root.
4337   root.handle.SetWeak(&root, &WeakPointerCallback);
4338   root.handle.MarkPartiallyDependent();
4339
4340   // Groups are deleted, rebuild groups.
4341   {
4342     HandleScope handle_scope(iso);
4343     g1s1.handle.MarkPartiallyDependent();
4344     g1s2.handle.MarkPartiallyDependent();
4345     g2s1.handle.MarkPartiallyDependent();
4346     g2s2.handle.MarkPartiallyDependent();
4347     g3s1.handle.MarkPartiallyDependent();
4348     g3s2.handle.MarkPartiallyDependent();
4349     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4350     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4351     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4352         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4353     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4354     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4355     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4356         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4357     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4358     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4359     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4360         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4361   }
4362
4363   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4364
4365   // All objects should be gone. 7 global handles in total.
4366   CHECK_EQ(7, counter.NumberOfWeakCalls());
4367 }
4368
4369
4370 THREADED_TEST(ScriptException) {
4371   LocalContext env;
4372   v8::HandleScope scope(env->GetIsolate());
4373   Local<Script> script = v8_compile("throw 'panama!';");
4374   v8::TryCatch try_catch;
4375   Local<Value> result = script->Run();
4376   CHECK(result.IsEmpty());
4377   CHECK(try_catch.HasCaught());
4378   String::Utf8Value exception_value(try_catch.Exception());
4379   CHECK_EQ(*exception_value, "panama!");
4380 }
4381
4382
4383 TEST(TryCatchCustomException) {
4384   LocalContext env;
4385   v8::HandleScope scope(env->GetIsolate());
4386   v8::TryCatch try_catch;
4387   CompileRun("function CustomError() { this.a = 'b'; }"
4388              "(function f() { throw new CustomError(); })();");
4389   CHECK(try_catch.HasCaught());
4390   CHECK(try_catch.Exception()->ToObject()->
4391             Get(v8_str("a"))->Equals(v8_str("b")));
4392 }
4393
4394
4395 bool message_received;
4396
4397
4398 static void check_message_0(v8::Handle<v8::Message> message,
4399                             v8::Handle<Value> data) {
4400   CHECK_EQ(5.76, data->NumberValue());
4401   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4402   CHECK(!message->IsSharedCrossOrigin());
4403   message_received = true;
4404 }
4405
4406
4407 THREADED_TEST(MessageHandler0) {
4408   message_received = false;
4409   v8::HandleScope scope(CcTest::isolate());
4410   CHECK(!message_received);
4411   LocalContext context;
4412   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4413   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4414   script->Run();
4415   CHECK(message_received);
4416   // clear out the message listener
4417   v8::V8::RemoveMessageListeners(check_message_0);
4418 }
4419
4420
4421 static void check_message_1(v8::Handle<v8::Message> message,
4422                             v8::Handle<Value> data) {
4423   CHECK(data->IsNumber());
4424   CHECK_EQ(1337, data->Int32Value());
4425   CHECK(!message->IsSharedCrossOrigin());
4426   message_received = true;
4427 }
4428
4429
4430 TEST(MessageHandler1) {
4431   message_received = false;
4432   v8::HandleScope scope(CcTest::isolate());
4433   CHECK(!message_received);
4434   v8::V8::AddMessageListener(check_message_1);
4435   LocalContext context;
4436   CompileRun("throw 1337;");
4437   CHECK(message_received);
4438   // clear out the message listener
4439   v8::V8::RemoveMessageListeners(check_message_1);
4440 }
4441
4442
4443 static void check_message_2(v8::Handle<v8::Message> message,
4444                             v8::Handle<Value> data) {
4445   LocalContext context;
4446   CHECK(data->IsObject());
4447   v8::Local<v8::Value> hidden_property =
4448       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4449   CHECK(v8_str("hidden value")->Equals(hidden_property));
4450   CHECK(!message->IsSharedCrossOrigin());
4451   message_received = true;
4452 }
4453
4454
4455 TEST(MessageHandler2) {
4456   message_received = false;
4457   v8::HandleScope scope(CcTest::isolate());
4458   CHECK(!message_received);
4459   v8::V8::AddMessageListener(check_message_2);
4460   LocalContext context;
4461   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4462   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4463                                            v8_str("hidden value"));
4464   context->Global()->Set(v8_str("error"), error);
4465   CompileRun("throw error;");
4466   CHECK(message_received);
4467   // clear out the message listener
4468   v8::V8::RemoveMessageListeners(check_message_2);
4469 }
4470
4471
4472 static void check_message_3(v8::Handle<v8::Message> message,
4473                             v8::Handle<Value> data) {
4474   CHECK(message->IsSharedCrossOrigin());
4475   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4476   message_received = true;
4477 }
4478
4479
4480 TEST(MessageHandler3) {
4481   message_received = false;
4482   v8::Isolate* isolate = CcTest::isolate();
4483   v8::HandleScope scope(isolate);
4484   CHECK(!message_received);
4485   v8::V8::AddMessageListener(check_message_3);
4486   LocalContext context;
4487   v8::ScriptOrigin origin =
4488       v8::ScriptOrigin(v8_str("6.75"),
4489                        v8::Integer::New(isolate, 1),
4490                        v8::Integer::New(isolate, 2),
4491                        v8::True(isolate));
4492   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4493                                                   &origin);
4494   script->Run();
4495   CHECK(message_received);
4496   // clear out the message listener
4497   v8::V8::RemoveMessageListeners(check_message_3);
4498 }
4499
4500
4501 static void check_message_4(v8::Handle<v8::Message> message,
4502                             v8::Handle<Value> data) {
4503   CHECK(!message->IsSharedCrossOrigin());
4504   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4505   message_received = true;
4506 }
4507
4508
4509 TEST(MessageHandler4) {
4510   message_received = false;
4511   v8::Isolate* isolate = CcTest::isolate();
4512   v8::HandleScope scope(isolate);
4513   CHECK(!message_received);
4514   v8::V8::AddMessageListener(check_message_4);
4515   LocalContext context;
4516   v8::ScriptOrigin origin =
4517       v8::ScriptOrigin(v8_str("6.75"),
4518                        v8::Integer::New(isolate, 1),
4519                        v8::Integer::New(isolate, 2),
4520                        v8::False(isolate));
4521   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4522                                                   &origin);
4523   script->Run();
4524   CHECK(message_received);
4525   // clear out the message listener
4526   v8::V8::RemoveMessageListeners(check_message_4);
4527 }
4528
4529
4530 static void check_message_5a(v8::Handle<v8::Message> message,
4531                             v8::Handle<Value> data) {
4532   CHECK(message->IsSharedCrossOrigin());
4533   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4534   message_received = true;
4535 }
4536
4537
4538 static void check_message_5b(v8::Handle<v8::Message> message,
4539                             v8::Handle<Value> data) {
4540   CHECK(!message->IsSharedCrossOrigin());
4541   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4542   message_received = true;
4543 }
4544
4545
4546 TEST(MessageHandler5) {
4547   message_received = false;
4548   v8::Isolate* isolate = CcTest::isolate();
4549   v8::HandleScope scope(isolate);
4550   CHECK(!message_received);
4551   v8::V8::AddMessageListener(check_message_5a);
4552   LocalContext context;
4553   v8::ScriptOrigin origin =
4554       v8::ScriptOrigin(v8_str("6.75"),
4555                        v8::Integer::New(isolate, 1),
4556                        v8::Integer::New(isolate, 2),
4557                        v8::True(isolate));
4558   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4559                                                   &origin);
4560   script->Run();
4561   CHECK(message_received);
4562   // clear out the message listener
4563   v8::V8::RemoveMessageListeners(check_message_5a);
4564
4565   message_received = false;
4566   v8::V8::AddMessageListener(check_message_5b);
4567   origin =
4568       v8::ScriptOrigin(v8_str("6.75"),
4569                        v8::Integer::New(isolate, 1),
4570                        v8::Integer::New(isolate, 2),
4571                        v8::False(isolate));
4572   script = Script::Compile(v8_str("throw 'error'"),
4573                            &origin);
4574   script->Run();
4575   CHECK(message_received);
4576   // clear out the message listener
4577   v8::V8::RemoveMessageListeners(check_message_5b);
4578 }
4579
4580
4581 THREADED_TEST(GetSetProperty) {
4582   LocalContext context;
4583   v8::Isolate* isolate = context->GetIsolate();
4584   v8::HandleScope scope(isolate);
4585   context->Global()->Set(v8_str("foo"), v8_num(14));
4586   context->Global()->Set(v8_str("12"), v8_num(92));
4587   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4588   context->Global()->Set(v8_num(13), v8_num(56));
4589   Local<Value> foo = CompileRun("this.foo");
4590   CHECK_EQ(14, foo->Int32Value());
4591   Local<Value> twelve = CompileRun("this[12]");
4592   CHECK_EQ(92, twelve->Int32Value());
4593   Local<Value> sixteen = CompileRun("this[16]");
4594   CHECK_EQ(32, sixteen->Int32Value());
4595   Local<Value> thirteen = CompileRun("this[13]");
4596   CHECK_EQ(56, thirteen->Int32Value());
4597   CHECK_EQ(92,
4598            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4599   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4600   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4601   CHECK_EQ(32,
4602            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4603   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4604   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4605   CHECK_EQ(56,
4606            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4607   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4608   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4609 }
4610
4611
4612 THREADED_TEST(PropertyAttributes) {
4613   LocalContext context;
4614   v8::HandleScope scope(context->GetIsolate());
4615   // none
4616   Local<String> prop = v8_str("none");
4617   context->Global()->Set(prop, v8_num(7));
4618   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4619   // read-only
4620   prop = v8_str("read_only");
4621   context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4622   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4623   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4624   CompileRun("read_only = 9");
4625   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4626   context->Global()->Set(prop, v8_num(10));
4627   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4628   // dont-delete
4629   prop = v8_str("dont_delete");
4630   context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4631   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4632   CompileRun("delete dont_delete");
4633   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4634   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4635   // dont-enum
4636   prop = v8_str("dont_enum");
4637   context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4638   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4639   // absent
4640   prop = v8_str("absent");
4641   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4642   Local<Value> fake_prop = v8_num(1);
4643   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4644   // exception
4645   TryCatch try_catch;
4646   Local<Value> exception =
4647       CompileRun("({ toString: function() { throw 'exception';} })");
4648   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4649   CHECK(try_catch.HasCaught());
4650   String::Utf8Value exception_value(try_catch.Exception());
4651   CHECK_EQ("exception", *exception_value);
4652   try_catch.Reset();
4653 }
4654
4655
4656 THREADED_TEST(Array) {
4657   LocalContext context;
4658   v8::HandleScope scope(context->GetIsolate());
4659   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4660   CHECK_EQ(0, array->Length());
4661   CHECK(array->Get(0)->IsUndefined());
4662   CHECK(!array->Has(0));
4663   CHECK(array->Get(100)->IsUndefined());
4664   CHECK(!array->Has(100));
4665   array->Set(2, v8_num(7));
4666   CHECK_EQ(3, array->Length());
4667   CHECK(!array->Has(0));
4668   CHECK(!array->Has(1));
4669   CHECK(array->Has(2));
4670   CHECK_EQ(7, array->Get(2)->Int32Value());
4671   Local<Value> obj = CompileRun("[1, 2, 3]");
4672   Local<v8::Array> arr = obj.As<v8::Array>();
4673   CHECK_EQ(3, arr->Length());
4674   CHECK_EQ(1, arr->Get(0)->Int32Value());
4675   CHECK_EQ(2, arr->Get(1)->Int32Value());
4676   CHECK_EQ(3, arr->Get(2)->Int32Value());
4677   array = v8::Array::New(context->GetIsolate(), 27);
4678   CHECK_EQ(27, array->Length());
4679   array = v8::Array::New(context->GetIsolate(), -27);
4680   CHECK_EQ(0, array->Length());
4681 }
4682
4683
4684 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4685   v8::EscapableHandleScope scope(args.GetIsolate());
4686   ApiTestFuzzer::Fuzz();
4687   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4688   for (int i = 0; i < args.Length(); i++)
4689     result->Set(i, args[i]);
4690   args.GetReturnValue().Set(scope.Escape(result));
4691 }
4692
4693
4694 THREADED_TEST(Vector) {
4695   v8::Isolate* isolate = CcTest::isolate();
4696   v8::HandleScope scope(isolate);
4697   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4698   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4699   LocalContext context(0, global);
4700
4701   const char* fun = "f()";
4702   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4703   CHECK_EQ(0, a0->Length());
4704
4705   const char* fun2 = "f(11)";
4706   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4707   CHECK_EQ(1, a1->Length());
4708   CHECK_EQ(11, a1->Get(0)->Int32Value());
4709
4710   const char* fun3 = "f(12, 13)";
4711   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4712   CHECK_EQ(2, a2->Length());
4713   CHECK_EQ(12, a2->Get(0)->Int32Value());
4714   CHECK_EQ(13, a2->Get(1)->Int32Value());
4715
4716   const char* fun4 = "f(14, 15, 16)";
4717   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4718   CHECK_EQ(3, a3->Length());
4719   CHECK_EQ(14, a3->Get(0)->Int32Value());
4720   CHECK_EQ(15, a3->Get(1)->Int32Value());
4721   CHECK_EQ(16, a3->Get(2)->Int32Value());
4722
4723   const char* fun5 = "f(17, 18, 19, 20)";
4724   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4725   CHECK_EQ(4, a4->Length());
4726   CHECK_EQ(17, a4->Get(0)->Int32Value());
4727   CHECK_EQ(18, a4->Get(1)->Int32Value());
4728   CHECK_EQ(19, a4->Get(2)->Int32Value());
4729   CHECK_EQ(20, a4->Get(3)->Int32Value());
4730 }
4731
4732
4733 THREADED_TEST(FunctionCall) {
4734   LocalContext context;
4735   v8::Isolate* isolate = context->GetIsolate();
4736   v8::HandleScope scope(isolate);
4737   CompileRun(
4738     "function Foo() {"
4739     "  var result = [];"
4740     "  for (var i = 0; i < arguments.length; i++) {"
4741     "    result.push(arguments[i]);"
4742     "  }"
4743     "  return result;"
4744     "}"
4745     "function ReturnThisSloppy() {"
4746     "  return this;"
4747     "}"
4748     "function ReturnThisStrict() {"
4749     "  'use strict';"
4750     "  return this;"
4751     "}");
4752   Local<Function> Foo =
4753       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4754   Local<Function> ReturnThisSloppy =
4755       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4756   Local<Function> ReturnThisStrict =
4757       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4758
4759   v8::Handle<Value>* args0 = NULL;
4760   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4761   CHECK_EQ(0, a0->Length());
4762
4763   v8::Handle<Value> args1[] = { v8_num(1.1) };
4764   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4765   CHECK_EQ(1, a1->Length());
4766   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4767
4768   v8::Handle<Value> args2[] = { v8_num(2.2),
4769                                 v8_num(3.3) };
4770   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4771   CHECK_EQ(2, a2->Length());
4772   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4773   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4774
4775   v8::Handle<Value> args3[] = { v8_num(4.4),
4776                                 v8_num(5.5),
4777                                 v8_num(6.6) };
4778   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4779   CHECK_EQ(3, a3->Length());
4780   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4781   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4782   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4783
4784   v8::Handle<Value> args4[] = { v8_num(7.7),
4785                                 v8_num(8.8),
4786                                 v8_num(9.9),
4787                                 v8_num(10.11) };
4788   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4789   CHECK_EQ(4, a4->Length());
4790   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4791   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4792   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4793   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4794
4795   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4796   CHECK(r1->StrictEquals(context->Global()));
4797   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4798   CHECK(r2->StrictEquals(context->Global()));
4799   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4800   CHECK(r3->IsNumberObject());
4801   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4802   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4803   CHECK(r4->IsStringObject());
4804   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4805   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4806   CHECK(r5->IsBooleanObject());
4807   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4808
4809   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4810   CHECK(r6->IsUndefined());
4811   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4812   CHECK(r7->IsNull());
4813   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4814   CHECK(r8->StrictEquals(v8_num(42)));
4815   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4816   CHECK(r9->StrictEquals(v8_str("hello")));
4817   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4818   CHECK(r10->StrictEquals(v8::True(isolate)));
4819 }
4820
4821
4822 THREADED_TEST(ConstructCall) {
4823   LocalContext context;
4824   v8::Isolate* isolate = context->GetIsolate();
4825   v8::HandleScope scope(isolate);
4826   CompileRun(
4827     "function Foo() {"
4828     "  var result = [];"
4829     "  for (var i = 0; i < arguments.length; i++) {"
4830     "    result.push(arguments[i]);"
4831     "  }"
4832     "  return result;"
4833     "}");
4834   Local<Function> Foo =
4835       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4836
4837   v8::Handle<Value>* args0 = NULL;
4838   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4839   CHECK_EQ(0, a0->Length());
4840
4841   v8::Handle<Value> args1[] = { v8_num(1.1) };
4842   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4843   CHECK_EQ(1, a1->Length());
4844   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4845
4846   v8::Handle<Value> args2[] = { v8_num(2.2),
4847                                 v8_num(3.3) };
4848   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4849   CHECK_EQ(2, a2->Length());
4850   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4851   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4852
4853   v8::Handle<Value> args3[] = { v8_num(4.4),
4854                                 v8_num(5.5),
4855                                 v8_num(6.6) };
4856   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4857   CHECK_EQ(3, a3->Length());
4858   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4859   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4860   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4861
4862   v8::Handle<Value> args4[] = { v8_num(7.7),
4863                                 v8_num(8.8),
4864                                 v8_num(9.9),
4865                                 v8_num(10.11) };
4866   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4867   CHECK_EQ(4, a4->Length());
4868   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4869   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4870   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4871   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4872 }
4873
4874
4875 static void CheckUncle(v8::TryCatch* try_catch) {
4876   CHECK(try_catch->HasCaught());
4877   String::Utf8Value str_value(try_catch->Exception());
4878   CHECK_EQ(*str_value, "uncle?");
4879   try_catch->Reset();
4880 }
4881
4882
4883 THREADED_TEST(ConversionNumber) {
4884   LocalContext env;
4885   v8::HandleScope scope(env->GetIsolate());
4886   // Very large number.
4887   CompileRun("var obj = Math.pow(2,32) * 1237;");
4888   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4889   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4890   CHECK_EQ(0, obj->ToInt32()->Value());
4891   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4892   // Large number.
4893   CompileRun("var obj = -1234567890123;");
4894   obj = env->Global()->Get(v8_str("obj"));
4895   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4896   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4897   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4898   // Small positive integer.
4899   CompileRun("var obj = 42;");
4900   obj = env->Global()->Get(v8_str("obj"));
4901   CHECK_EQ(42.0, obj->ToNumber()->Value());
4902   CHECK_EQ(42, obj->ToInt32()->Value());
4903   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4904   // Negative integer.
4905   CompileRun("var obj = -37;");
4906   obj = env->Global()->Get(v8_str("obj"));
4907   CHECK_EQ(-37.0, obj->ToNumber()->Value());
4908   CHECK_EQ(-37, obj->ToInt32()->Value());
4909   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4910   // Positive non-int32 integer.
4911   CompileRun("var obj = 0x81234567;");
4912   obj = env->Global()->Get(v8_str("obj"));
4913   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4914   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4915   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4916   // Fraction.
4917   CompileRun("var obj = 42.3;");
4918   obj = env->Global()->Get(v8_str("obj"));
4919   CHECK_EQ(42.3, obj->ToNumber()->Value());
4920   CHECK_EQ(42, obj->ToInt32()->Value());
4921   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4922   // Large negative fraction.
4923   CompileRun("var obj = -5726623061.75;");
4924   obj = env->Global()->Get(v8_str("obj"));
4925   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4926   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4927   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4928 }
4929
4930
4931 THREADED_TEST(isNumberType) {
4932   LocalContext env;
4933   v8::HandleScope scope(env->GetIsolate());
4934   // Very large number.
4935   CompileRun("var obj = Math.pow(2,32) * 1237;");
4936   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4937   CHECK(!obj->IsInt32());
4938   CHECK(!obj->IsUint32());
4939   // Large negative number.
4940   CompileRun("var obj = -1234567890123;");
4941   obj = env->Global()->Get(v8_str("obj"));
4942   CHECK(!obj->IsInt32());
4943   CHECK(!obj->IsUint32());
4944   // Small positive integer.
4945   CompileRun("var obj = 42;");
4946   obj = env->Global()->Get(v8_str("obj"));
4947   CHECK(obj->IsInt32());
4948   CHECK(obj->IsUint32());
4949   // Negative integer.
4950   CompileRun("var obj = -37;");
4951   obj = env->Global()->Get(v8_str("obj"));
4952   CHECK(obj->IsInt32());
4953   CHECK(!obj->IsUint32());
4954   // Positive non-int32 integer.
4955   CompileRun("var obj = 0x81234567;");
4956   obj = env->Global()->Get(v8_str("obj"));
4957   CHECK(!obj->IsInt32());
4958   CHECK(obj->IsUint32());
4959   // Fraction.
4960   CompileRun("var obj = 42.3;");
4961   obj = env->Global()->Get(v8_str("obj"));
4962   CHECK(!obj->IsInt32());
4963   CHECK(!obj->IsUint32());
4964   // Large negative fraction.
4965   CompileRun("var obj = -5726623061.75;");
4966   obj = env->Global()->Get(v8_str("obj"));
4967   CHECK(!obj->IsInt32());
4968   CHECK(!obj->IsUint32());
4969   // Positive zero
4970   CompileRun("var obj = 0.0;");
4971   obj = env->Global()->Get(v8_str("obj"));
4972   CHECK(obj->IsInt32());
4973   CHECK(obj->IsUint32());
4974   // Positive zero
4975   CompileRun("var obj = -0.0;");
4976   obj = env->Global()->Get(v8_str("obj"));
4977   CHECK(!obj->IsInt32());
4978   CHECK(!obj->IsUint32());
4979 }
4980
4981
4982 THREADED_TEST(ConversionException) {
4983   LocalContext env;
4984   v8::Isolate* isolate = env->GetIsolate();
4985   v8::HandleScope scope(isolate);
4986   CompileRun(
4987     "function TestClass() { };"
4988     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4989     "var obj = new TestClass();");
4990   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4991
4992   v8::TryCatch try_catch;
4993
4994   Local<Value> to_string_result = obj->ToString();
4995   CHECK(to_string_result.IsEmpty());
4996   CheckUncle(&try_catch);
4997
4998   Local<Value> to_number_result = obj->ToNumber();
4999   CHECK(to_number_result.IsEmpty());
5000   CheckUncle(&try_catch);
5001
5002   Local<Value> to_integer_result = obj->ToInteger();
5003   CHECK(to_integer_result.IsEmpty());
5004   CheckUncle(&try_catch);
5005
5006   Local<Value> to_uint32_result = obj->ToUint32();
5007   CHECK(to_uint32_result.IsEmpty());
5008   CheckUncle(&try_catch);
5009
5010   Local<Value> to_int32_result = obj->ToInt32();
5011   CHECK(to_int32_result.IsEmpty());
5012   CheckUncle(&try_catch);
5013
5014   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
5015   CHECK(to_object_result.IsEmpty());
5016   CHECK(try_catch.HasCaught());
5017   try_catch.Reset();
5018
5019   int32_t int32_value = obj->Int32Value();
5020   CHECK_EQ(0, int32_value);
5021   CheckUncle(&try_catch);
5022
5023   uint32_t uint32_value = obj->Uint32Value();
5024   CHECK_EQ(0, uint32_value);
5025   CheckUncle(&try_catch);
5026
5027   double number_value = obj->NumberValue();
5028   CHECK_NE(0, std::isnan(number_value));
5029   CheckUncle(&try_catch);
5030
5031   int64_t integer_value = obj->IntegerValue();
5032   CHECK_EQ(0.0, static_cast<double>(integer_value));
5033   CheckUncle(&try_catch);
5034 }
5035
5036
5037 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
5038   ApiTestFuzzer::Fuzz();
5039   args.GetIsolate()->ThrowException(v8_str("konto"));
5040 }
5041
5042
5043 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5044   if (args.Length() < 1) {
5045     args.GetReturnValue().Set(false);
5046     return;
5047   }
5048   v8::HandleScope scope(args.GetIsolate());
5049   v8::TryCatch try_catch;
5050   Local<Value> result = CompileRun(args[0]->ToString());
5051   CHECK(!try_catch.HasCaught() || result.IsEmpty());
5052   args.GetReturnValue().Set(try_catch.HasCaught());
5053 }
5054
5055
5056 THREADED_TEST(APICatch) {
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   CompileRun(
5064     "var thrown = false;"
5065     "try {"
5066     "  ThrowFromC();"
5067     "} catch (e) {"
5068     "  thrown = true;"
5069     "}");
5070   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
5071   CHECK(thrown->BooleanValue());
5072 }
5073
5074
5075 THREADED_TEST(APIThrowTryCatch) {
5076   v8::Isolate* isolate = CcTest::isolate();
5077   v8::HandleScope scope(isolate);
5078   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5079   templ->Set(v8_str("ThrowFromC"),
5080              v8::FunctionTemplate::New(isolate, ThrowFromC));
5081   LocalContext context(0, templ);
5082   v8::TryCatch try_catch;
5083   CompileRun("ThrowFromC();");
5084   CHECK(try_catch.HasCaught());
5085 }
5086
5087
5088 // Test that a try-finally block doesn't shadow a try-catch block
5089 // when setting up an external handler.
5090 //
5091 // BUG(271): Some of the exception propagation does not work on the
5092 // ARM simulator because the simulator separates the C++ stack and the
5093 // JS stack.  This test therefore fails on the simulator.  The test is
5094 // not threaded to allow the threading tests to run on the simulator.
5095 TEST(TryCatchInTryFinally) {
5096   v8::Isolate* isolate = CcTest::isolate();
5097   v8::HandleScope scope(isolate);
5098   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5099   templ->Set(v8_str("CCatcher"),
5100              v8::FunctionTemplate::New(isolate, CCatcher));
5101   LocalContext context(0, templ);
5102   Local<Value> result = CompileRun("try {"
5103                                    "  try {"
5104                                    "    CCatcher('throw 7;');"
5105                                    "  } finally {"
5106                                    "  }"
5107                                    "} catch (e) {"
5108                                    "}");
5109   CHECK(result->IsTrue());
5110 }
5111
5112
5113 static void check_reference_error_message(
5114     v8::Handle<v8::Message> message,
5115     v8::Handle<v8::Value> data) {
5116   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
5117   CHECK(message->Get()->Equals(v8_str(reference_error)));
5118 }
5119
5120
5121 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
5122   ApiTestFuzzer::Fuzz();
5123   CHECK(false);
5124 }
5125
5126
5127 // Test that overwritten methods are not invoked on uncaught exception
5128 // formatting. However, they are invoked when performing normal error
5129 // string conversions.
5130 TEST(APIThrowMessageOverwrittenToString) {
5131   v8::Isolate* isolate = CcTest::isolate();
5132   v8::HandleScope scope(isolate);
5133   v8::V8::AddMessageListener(check_reference_error_message);
5134   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5135   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
5136   LocalContext context(NULL, templ);
5137   CompileRun("asdf;");
5138   CompileRun("var limit = {};"
5139              "limit.valueOf = fail;"
5140              "Error.stackTraceLimit = limit;");
5141   CompileRun("asdf");
5142   CompileRun("Array.prototype.pop = fail;");
5143   CompileRun("Object.prototype.hasOwnProperty = fail;");
5144   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
5145   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
5146   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
5147   CompileRun("ReferenceError.prototype.toString ="
5148              "  function() { return 'Whoops' }");
5149   CompileRun("asdf;");
5150   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
5151   CompileRun("asdf;");
5152   CompileRun("ReferenceError.prototype.constructor = void 0;");
5153   CompileRun("asdf;");
5154   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
5155   CompileRun("asdf;");
5156   CompileRun("ReferenceError.prototype = new Object();");
5157   CompileRun("asdf;");
5158   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
5159   CHECK(string->Equals(v8_str("Whoops")));
5160   CompileRun("ReferenceError.prototype.constructor = new Object();"
5161              "ReferenceError.prototype.constructor.name = 1;"
5162              "Number.prototype.toString = function() { return 'Whoops'; };"
5163              "ReferenceError.prototype.toString = Object.prototype.toString;");
5164   CompileRun("asdf;");
5165   v8::V8::RemoveMessageListeners(check_reference_error_message);
5166 }
5167
5168
5169 static void check_custom_error_tostring(
5170     v8::Handle<v8::Message> message,
5171     v8::Handle<v8::Value> data) {
5172   const char* uncaught_error = "Uncaught MyError toString";
5173   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5174 }
5175
5176
5177 TEST(CustomErrorToString) {
5178   LocalContext context;
5179   v8::HandleScope scope(context->GetIsolate());
5180   v8::V8::AddMessageListener(check_custom_error_tostring);
5181   CompileRun(
5182     "function MyError(name, message) {                   "
5183     "  this.name = name;                                 "
5184     "  this.message = message;                           "
5185     "}                                                   "
5186     "MyError.prototype = Object.create(Error.prototype); "
5187     "MyError.prototype.toString = function() {           "
5188     "  return 'MyError toString';                        "
5189     "};                                                  "
5190     "throw new MyError('my name', 'my message');         ");
5191   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
5192 }
5193
5194
5195 static void check_custom_error_message(
5196     v8::Handle<v8::Message> message,
5197     v8::Handle<v8::Value> data) {
5198   const char* uncaught_error = "Uncaught MyError: my message";
5199   printf("%s\n", *v8::String::Utf8Value(message->Get()));
5200   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5201 }
5202
5203
5204 TEST(CustomErrorMessage) {
5205   LocalContext context;
5206   v8::HandleScope scope(context->GetIsolate());
5207   v8::V8::AddMessageListener(check_custom_error_message);
5208
5209   // Handlebars.
5210   CompileRun(
5211     "function MyError(msg) {                             "
5212     "  this.name = 'MyError';                            "
5213     "  this.message = msg;                               "
5214     "}                                                   "
5215     "MyError.prototype = new Error();                    "
5216     "throw new MyError('my message');                    ");
5217
5218   // Closure.
5219   CompileRun(
5220     "function MyError(msg) {                             "
5221     "  this.name = 'MyError';                            "
5222     "  this.message = msg;                               "
5223     "}                                                   "
5224     "inherits = function(childCtor, parentCtor) {        "
5225     "    function tempCtor() {};                         "
5226     "    tempCtor.prototype = parentCtor.prototype;      "
5227     "    childCtor.superClass_ = parentCtor.prototype;   "
5228     "    childCtor.prototype = new tempCtor();           "
5229     "    childCtor.prototype.constructor = childCtor;    "
5230     "};                                                  "
5231     "inherits(MyError, Error);                           "
5232     "throw new MyError('my message');                    ");
5233
5234   // Object.create.
5235   CompileRun(
5236     "function MyError(msg) {                             "
5237     "  this.name = 'MyError';                            "
5238     "  this.message = msg;                               "
5239     "}                                                   "
5240     "MyError.prototype = Object.create(Error.prototype); "
5241     "throw new MyError('my message');                    ");
5242
5243   v8::V8::RemoveMessageListeners(check_custom_error_message);
5244 }
5245
5246
5247 static void receive_message(v8::Handle<v8::Message> message,
5248                             v8::Handle<v8::Value> data) {
5249   message->Get();
5250   message_received = true;
5251 }
5252
5253
5254 TEST(APIThrowMessage) {
5255   message_received = false;
5256   v8::Isolate* isolate = CcTest::isolate();
5257   v8::HandleScope scope(isolate);
5258   v8::V8::AddMessageListener(receive_message);
5259   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5260   templ->Set(v8_str("ThrowFromC"),
5261              v8::FunctionTemplate::New(isolate, ThrowFromC));
5262   LocalContext context(0, templ);
5263   CompileRun("ThrowFromC();");
5264   CHECK(message_received);
5265   v8::V8::RemoveMessageListeners(receive_message);
5266 }
5267
5268
5269 TEST(APIThrowMessageAndVerboseTryCatch) {
5270   message_received = false;
5271   v8::Isolate* isolate = CcTest::isolate();
5272   v8::HandleScope scope(isolate);
5273   v8::V8::AddMessageListener(receive_message);
5274   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5275   templ->Set(v8_str("ThrowFromC"),
5276              v8::FunctionTemplate::New(isolate, ThrowFromC));
5277   LocalContext context(0, templ);
5278   v8::TryCatch try_catch;
5279   try_catch.SetVerbose(true);
5280   Local<Value> result = CompileRun("ThrowFromC();");
5281   CHECK(try_catch.HasCaught());
5282   CHECK(result.IsEmpty());
5283   CHECK(message_received);
5284   v8::V8::RemoveMessageListeners(receive_message);
5285 }
5286
5287
5288 TEST(APIStackOverflowAndVerboseTryCatch) {
5289   message_received = false;
5290   LocalContext context;
5291   v8::HandleScope scope(context->GetIsolate());
5292   v8::V8::AddMessageListener(receive_message);
5293   v8::TryCatch try_catch;
5294   try_catch.SetVerbose(true);
5295   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5296   CHECK(try_catch.HasCaught());
5297   CHECK(result.IsEmpty());
5298   CHECK(message_received);
5299   v8::V8::RemoveMessageListeners(receive_message);
5300 }
5301
5302
5303 THREADED_TEST(ExternalScriptException) {
5304   v8::Isolate* isolate = CcTest::isolate();
5305   v8::HandleScope scope(isolate);
5306   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5307   templ->Set(v8_str("ThrowFromC"),
5308              v8::FunctionTemplate::New(isolate, ThrowFromC));
5309   LocalContext context(0, templ);
5310
5311   v8::TryCatch try_catch;
5312   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5313   CHECK(result.IsEmpty());
5314   CHECK(try_catch.HasCaught());
5315   String::Utf8Value exception_value(try_catch.Exception());
5316   CHECK_EQ("konto", *exception_value);
5317 }
5318
5319
5320
5321 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5322   ApiTestFuzzer::Fuzz();
5323   CHECK_EQ(4, args.Length());
5324   int count = args[0]->Int32Value();
5325   int cInterval = args[2]->Int32Value();
5326   if (count == 0) {
5327     args.GetIsolate()->ThrowException(v8_str("FromC"));
5328     return;
5329   } else {
5330     Local<v8::Object> global =
5331         args.GetIsolate()->GetCurrentContext()->Global();
5332     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5333     v8::Handle<Value> argv[] = { v8_num(count - 1),
5334                                  args[1],
5335                                  args[2],
5336                                  args[3] };
5337     if (count % cInterval == 0) {
5338       v8::TryCatch try_catch;
5339       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5340       int expected = args[3]->Int32Value();
5341       if (try_catch.HasCaught()) {
5342         CHECK_EQ(expected, count);
5343         CHECK(result.IsEmpty());
5344         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5345       } else {
5346         CHECK_NE(expected, count);
5347       }
5348       args.GetReturnValue().Set(result);
5349       return;
5350     } else {
5351       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5352       return;
5353     }
5354   }
5355 }
5356
5357
5358 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5359   ApiTestFuzzer::Fuzz();
5360   CHECK_EQ(3, args.Length());
5361   bool equality = args[0]->BooleanValue();
5362   int count = args[1]->Int32Value();
5363   int expected = args[2]->Int32Value();
5364   if (equality) {
5365     CHECK_EQ(count, expected);
5366   } else {
5367     CHECK_NE(count, expected);
5368   }
5369 }
5370
5371
5372 THREADED_TEST(EvalInTryFinally) {
5373   LocalContext context;
5374   v8::HandleScope scope(context->GetIsolate());
5375   v8::TryCatch try_catch;
5376   CompileRun("(function() {"
5377              "  try {"
5378              "    eval('asldkf (*&^&*^');"
5379              "  } finally {"
5380              "    return;"
5381              "  }"
5382              "})()");
5383   CHECK(!try_catch.HasCaught());
5384 }
5385
5386
5387 // This test works by making a stack of alternating JavaScript and C
5388 // activations.  These activations set up exception handlers with regular
5389 // intervals, one interval for C activations and another for JavaScript
5390 // activations.  When enough activations have been created an exception is
5391 // thrown and we check that the right activation catches the exception and that
5392 // no other activations do.  The right activation is always the topmost one with
5393 // a handler, regardless of whether it is in JavaScript or C.
5394 //
5395 // The notation used to describe a test case looks like this:
5396 //
5397 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5398 //
5399 // Each entry is an activation, either JS or C.  The index is the count at that
5400 // level.  Stars identify activations with exception handlers, the @ identifies
5401 // the exception handler that should catch the exception.
5402 //
5403 // BUG(271): Some of the exception propagation does not work on the
5404 // ARM simulator because the simulator separates the C++ stack and the
5405 // JS stack.  This test therefore fails on the simulator.  The test is
5406 // not threaded to allow the threading tests to run on the simulator.
5407 TEST(ExceptionOrder) {
5408   v8::Isolate* isolate = CcTest::isolate();
5409   v8::HandleScope scope(isolate);
5410   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5411   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5412   templ->Set(v8_str("CThrowCountDown"),
5413              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5414   LocalContext context(0, templ);
5415   CompileRun(
5416     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5417     "  if (count == 0) throw 'FromJS';"
5418     "  if (count % jsInterval == 0) {"
5419     "    try {"
5420     "      var value = CThrowCountDown(count - 1,"
5421     "                                  jsInterval,"
5422     "                                  cInterval,"
5423     "                                  expected);"
5424     "      check(false, count, expected);"
5425     "      return value;"
5426     "    } catch (e) {"
5427     "      check(true, count, expected);"
5428     "    }"
5429     "  } else {"
5430     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5431     "  }"
5432     "}");
5433   Local<Function> fun =
5434       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5435
5436   const int argc = 4;
5437   //                             count      jsInterval cInterval  expected
5438
5439   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5440   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5441   fun->Call(fun, argc, a0);
5442
5443   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5444   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5445   fun->Call(fun, argc, a1);
5446
5447   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5448   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5449   fun->Call(fun, argc, a2);
5450
5451   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5452   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5453   fun->Call(fun, argc, a3);
5454
5455   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5456   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5457   fun->Call(fun, argc, a4);
5458
5459   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5460   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5461   fun->Call(fun, argc, a5);
5462 }
5463
5464
5465 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5466   ApiTestFuzzer::Fuzz();
5467   CHECK_EQ(1, args.Length());
5468   args.GetIsolate()->ThrowException(args[0]);
5469 }
5470
5471
5472 THREADED_TEST(ThrowValues) {
5473   v8::Isolate* isolate = CcTest::isolate();
5474   v8::HandleScope scope(isolate);
5475   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5476   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5477   LocalContext context(0, templ);
5478   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5479     "function Run(obj) {"
5480     "  try {"
5481     "    Throw(obj);"
5482     "  } catch (e) {"
5483     "    return e;"
5484     "  }"
5485     "  return 'no exception';"
5486     "}"
5487     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5488   CHECK_EQ(5, result->Length());
5489   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5490   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5491   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5492   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5493   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5494   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5495   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5496 }
5497
5498
5499 THREADED_TEST(CatchZero) {
5500   LocalContext context;
5501   v8::HandleScope scope(context->GetIsolate());
5502   v8::TryCatch try_catch;
5503   CHECK(!try_catch.HasCaught());
5504   CompileRun("throw 10");
5505   CHECK(try_catch.HasCaught());
5506   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5507   try_catch.Reset();
5508   CHECK(!try_catch.HasCaught());
5509   CompileRun("throw 0");
5510   CHECK(try_catch.HasCaught());
5511   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5512 }
5513
5514
5515 THREADED_TEST(CatchExceptionFromWith) {
5516   LocalContext context;
5517   v8::HandleScope scope(context->GetIsolate());
5518   v8::TryCatch try_catch;
5519   CHECK(!try_catch.HasCaught());
5520   CompileRun("var o = {}; with (o) { throw 42; }");
5521   CHECK(try_catch.HasCaught());
5522 }
5523
5524
5525 THREADED_TEST(TryCatchAndFinallyHidingException) {
5526   LocalContext context;
5527   v8::HandleScope scope(context->GetIsolate());
5528   v8::TryCatch try_catch;
5529   CHECK(!try_catch.HasCaught());
5530   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5531   CompileRun("f({toString: function() { throw 42; }});");
5532   CHECK(!try_catch.HasCaught());
5533 }
5534
5535
5536 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5537   v8::TryCatch try_catch;
5538 }
5539
5540
5541 THREADED_TEST(TryCatchAndFinally) {
5542   LocalContext context;
5543   v8::Isolate* isolate = context->GetIsolate();
5544   v8::HandleScope scope(isolate);
5545   context->Global()->Set(
5546       v8_str("native_with_try_catch"),
5547       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5548   v8::TryCatch try_catch;
5549   CHECK(!try_catch.HasCaught());
5550   CompileRun(
5551       "try {\n"
5552       "  throw new Error('a');\n"
5553       "} finally {\n"
5554       "  native_with_try_catch();\n"
5555       "}\n");
5556   CHECK(try_catch.HasCaught());
5557 }
5558
5559
5560 static void TryCatchNested1Helper(int depth) {
5561   if (depth > 0) {
5562     v8::TryCatch try_catch;
5563     try_catch.SetVerbose(true);
5564     TryCatchNested1Helper(depth - 1);
5565     CHECK(try_catch.HasCaught());
5566     try_catch.ReThrow();
5567   } else {
5568     CcTest::isolate()->ThrowException(v8_str("E1"));
5569   }
5570 }
5571
5572
5573 static void TryCatchNested2Helper(int depth) {
5574   if (depth > 0) {
5575     v8::TryCatch try_catch;
5576     try_catch.SetVerbose(true);
5577     TryCatchNested2Helper(depth - 1);
5578     CHECK(try_catch.HasCaught());
5579     try_catch.ReThrow();
5580   } else {
5581     CompileRun("throw 'E2';");
5582   }
5583 }
5584
5585
5586 TEST(TryCatchNested) {
5587   v8::V8::Initialize();
5588   LocalContext context;
5589   v8::HandleScope scope(context->GetIsolate());
5590
5591   {
5592     // Test nested try-catch with a native throw in the end.
5593     v8::TryCatch try_catch;
5594     TryCatchNested1Helper(5);
5595     CHECK(try_catch.HasCaught());
5596     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5597   }
5598
5599   {
5600     // Test nested try-catch with a JavaScript throw in the end.
5601     v8::TryCatch try_catch;
5602     TryCatchNested2Helper(5);
5603     CHECK(try_catch.HasCaught());
5604     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5605   }
5606 }
5607
5608
5609 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5610   CHECK(try_catch->HasCaught());
5611   Handle<Message> message = try_catch->Message();
5612   Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5613   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5614   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5615                      "Uncaught Error: a"));
5616   CHECK_EQ(1, message->GetLineNumber());
5617   CHECK_EQ(6, message->GetStartColumn());
5618 }
5619
5620
5621 void TryCatchMixedNestingHelper(
5622     const v8::FunctionCallbackInfo<v8::Value>& args) {
5623   ApiTestFuzzer::Fuzz();
5624   v8::TryCatch try_catch;
5625   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5626   CHECK(try_catch.HasCaught());
5627   TryCatchMixedNestingCheck(&try_catch);
5628   try_catch.ReThrow();
5629 }
5630
5631
5632 // This test ensures that an outer TryCatch in the following situation:
5633 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5634 // does not clobber the Message object generated for the inner TryCatch.
5635 // This exercises the ability of TryCatch.ReThrow() to restore the
5636 // inner pending Message before throwing the exception again.
5637 TEST(TryCatchMixedNesting) {
5638   v8::Isolate* isolate = CcTest::isolate();
5639   v8::HandleScope scope(isolate);
5640   v8::V8::Initialize();
5641   v8::TryCatch try_catch;
5642   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5643   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5644              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5645   LocalContext context(0, templ);
5646   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5647   TryCatchMixedNestingCheck(&try_catch);
5648 }
5649
5650
5651 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5652   ApiTestFuzzer::Fuzz();
5653   v8::TryCatch try_catch;
5654   args.GetIsolate()->ThrowException(v8_str("boom"));
5655   CHECK(try_catch.HasCaught());
5656 }
5657
5658
5659 TEST(TryCatchNative) {
5660   v8::Isolate* isolate = CcTest::isolate();
5661   v8::HandleScope scope(isolate);
5662   v8::V8::Initialize();
5663   v8::TryCatch try_catch;
5664   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5665   templ->Set(v8_str("TryCatchNativeHelper"),
5666              v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5667   LocalContext context(0, templ);
5668   CompileRun("TryCatchNativeHelper();");
5669   CHECK(!try_catch.HasCaught());
5670 }
5671
5672
5673 void TryCatchNativeResetHelper(
5674     const v8::FunctionCallbackInfo<v8::Value>& args) {
5675   ApiTestFuzzer::Fuzz();
5676   v8::TryCatch try_catch;
5677   args.GetIsolate()->ThrowException(v8_str("boom"));
5678   CHECK(try_catch.HasCaught());
5679   try_catch.Reset();
5680   CHECK(!try_catch.HasCaught());
5681 }
5682
5683
5684 TEST(TryCatchNativeReset) {
5685   v8::Isolate* isolate = CcTest::isolate();
5686   v8::HandleScope scope(isolate);
5687   v8::V8::Initialize();
5688   v8::TryCatch try_catch;
5689   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5690   templ->Set(v8_str("TryCatchNativeResetHelper"),
5691              v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5692   LocalContext context(0, templ);
5693   CompileRun("TryCatchNativeResetHelper();");
5694   CHECK(!try_catch.HasCaught());
5695 }
5696
5697
5698 THREADED_TEST(Equality) {
5699   LocalContext context;
5700   v8::Isolate* isolate = context->GetIsolate();
5701   v8::HandleScope scope(context->GetIsolate());
5702   // Check that equality works at all before relying on CHECK_EQ
5703   CHECK(v8_str("a")->Equals(v8_str("a")));
5704   CHECK(!v8_str("a")->Equals(v8_str("b")));
5705
5706   CHECK_EQ(v8_str("a"), v8_str("a"));
5707   CHECK_NE(v8_str("a"), v8_str("b"));
5708   CHECK_EQ(v8_num(1), v8_num(1));
5709   CHECK_EQ(v8_num(1.00), v8_num(1));
5710   CHECK_NE(v8_num(1), v8_num(2));
5711
5712   // Assume String is not internalized.
5713   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5714   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5715   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5716   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5717   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5718   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5719   Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
5720   CHECK(!not_a_number->StrictEquals(not_a_number));
5721   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5722   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5723
5724   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5725   v8::Persistent<v8::Object> alias(isolate, obj);
5726   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5727   alias.Reset();
5728
5729   CHECK(v8_str("a")->SameValue(v8_str("a")));
5730   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5731   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5732   CHECK(v8_num(1)->SameValue(v8_num(1)));
5733   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5734   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5735   CHECK(not_a_number->SameValue(not_a_number));
5736   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5737   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5738 }
5739
5740
5741 THREADED_TEST(MultiRun) {
5742   LocalContext context;
5743   v8::HandleScope scope(context->GetIsolate());
5744   Local<Script> script = v8_compile("x");
5745   for (int i = 0; i < 10; i++)
5746     script->Run();
5747 }
5748
5749
5750 static void GetXValue(Local<String> name,
5751                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5752   ApiTestFuzzer::Fuzz();
5753   CHECK_EQ(info.Data(), v8_str("donut"));
5754   CHECK_EQ(name, v8_str("x"));
5755   info.GetReturnValue().Set(name);
5756 }
5757
5758
5759 THREADED_TEST(SimplePropertyRead) {
5760   LocalContext context;
5761   v8::Isolate* isolate = context->GetIsolate();
5762   v8::HandleScope scope(isolate);
5763   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5764   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5765   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5766   Local<Script> script = v8_compile("obj.x");
5767   for (int i = 0; i < 10; i++) {
5768     Local<Value> result = script->Run();
5769     CHECK_EQ(result, v8_str("x"));
5770   }
5771 }
5772
5773
5774 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5775   LocalContext context;
5776   v8::Isolate* isolate = context->GetIsolate();
5777   v8::HandleScope scope(isolate);
5778   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5779   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5780   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5781
5782   // Uses getOwnPropertyDescriptor to check the configurable status
5783   Local<Script> script_desc = v8_compile(
5784       "var prop = Object.getOwnPropertyDescriptor( "
5785       "obj, 'x');"
5786       "prop.configurable;");
5787   Local<Value> result = script_desc->Run();
5788   CHECK_EQ(result->BooleanValue(), true);
5789
5790   // Redefine get - but still configurable
5791   Local<Script> script_define = v8_compile(
5792       "var desc = { get: function(){return 42; },"
5793       "            configurable: true };"
5794       "Object.defineProperty(obj, 'x', desc);"
5795       "obj.x");
5796   result = script_define->Run();
5797   CHECK_EQ(result, v8_num(42));
5798
5799   // Check that the accessor is still configurable
5800   result = script_desc->Run();
5801   CHECK_EQ(result->BooleanValue(), true);
5802
5803   // Redefine to a non-configurable
5804   script_define = v8_compile(
5805       "var desc = { get: function(){return 43; },"
5806       "             configurable: false };"
5807       "Object.defineProperty(obj, 'x', desc);"
5808       "obj.x");
5809   result = script_define->Run();
5810   CHECK_EQ(result, v8_num(43));
5811   result = script_desc->Run();
5812   CHECK_EQ(result->BooleanValue(), false);
5813
5814   // Make sure that it is not possible to redefine again
5815   v8::TryCatch try_catch;
5816   result = script_define->Run();
5817   CHECK(try_catch.HasCaught());
5818   String::Utf8Value exception_value(try_catch.Exception());
5819   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5820 }
5821
5822
5823 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5824   v8::Isolate* isolate = CcTest::isolate();
5825   v8::HandleScope scope(isolate);
5826   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5827   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5828   LocalContext context;
5829   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5830
5831   Local<Script> script_desc = v8_compile(
5832       "var prop ="
5833       "Object.getOwnPropertyDescriptor( "
5834       "obj, 'x');"
5835       "prop.configurable;");
5836   Local<Value> result = script_desc->Run();
5837   CHECK_EQ(result->BooleanValue(), true);
5838
5839   Local<Script> script_define = v8_compile(
5840       "var desc = {get: function(){return 42; },"
5841       "            configurable: true };"
5842       "Object.defineProperty(obj, 'x', desc);"
5843       "obj.x");
5844   result = script_define->Run();
5845   CHECK_EQ(result, v8_num(42));
5846
5847
5848   result = script_desc->Run();
5849   CHECK_EQ(result->BooleanValue(), true);
5850
5851
5852   script_define = v8_compile(
5853       "var desc = {get: function(){return 43; },"
5854       "            configurable: false };"
5855       "Object.defineProperty(obj, 'x', desc);"
5856       "obj.x");
5857   result = script_define->Run();
5858   CHECK_EQ(result, v8_num(43));
5859   result = script_desc->Run();
5860
5861   CHECK_EQ(result->BooleanValue(), false);
5862
5863   v8::TryCatch try_catch;
5864   result = script_define->Run();
5865   CHECK(try_catch.HasCaught());
5866   String::Utf8Value exception_value(try_catch.Exception());
5867   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5868 }
5869
5870
5871 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5872                                                 char const* name) {
5873   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5874 }
5875
5876
5877 THREADED_TEST(DefineAPIAccessorOnObject) {
5878   v8::Isolate* isolate = CcTest::isolate();
5879   v8::HandleScope scope(isolate);
5880   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5881   LocalContext context;
5882
5883   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5884   CompileRun("var obj2 = {};");
5885
5886   CHECK(CompileRun("obj1.x")->IsUndefined());
5887   CHECK(CompileRun("obj2.x")->IsUndefined());
5888
5889   CHECK(GetGlobalProperty(&context, "obj1")->
5890       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5891
5892   ExpectString("obj1.x", "x");
5893   CHECK(CompileRun("obj2.x")->IsUndefined());
5894
5895   CHECK(GetGlobalProperty(&context, "obj2")->
5896       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5897
5898   ExpectString("obj1.x", "x");
5899   ExpectString("obj2.x", "x");
5900
5901   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5902   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5903
5904   CompileRun("Object.defineProperty(obj1, 'x',"
5905              "{ get: function() { return 'y'; }, configurable: true })");
5906
5907   ExpectString("obj1.x", "y");
5908   ExpectString("obj2.x", "x");
5909
5910   CompileRun("Object.defineProperty(obj2, 'x',"
5911              "{ get: function() { return 'y'; }, configurable: true })");
5912
5913   ExpectString("obj1.x", "y");
5914   ExpectString("obj2.x", "y");
5915
5916   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5917   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5918
5919   CHECK(GetGlobalProperty(&context, "obj1")->
5920       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5921   CHECK(GetGlobalProperty(&context, "obj2")->
5922       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5923
5924   ExpectString("obj1.x", "x");
5925   ExpectString("obj2.x", "x");
5926
5927   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5928   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5929
5930   // Define getters/setters, but now make them not configurable.
5931   CompileRun("Object.defineProperty(obj1, 'x',"
5932              "{ get: function() { return 'z'; }, configurable: false })");
5933   CompileRun("Object.defineProperty(obj2, 'x',"
5934              "{ get: function() { return 'z'; }, configurable: false })");
5935
5936   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5937   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5938
5939   ExpectString("obj1.x", "z");
5940   ExpectString("obj2.x", "z");
5941
5942   CHECK(!GetGlobalProperty(&context, "obj1")->
5943       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5944   CHECK(!GetGlobalProperty(&context, "obj2")->
5945       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5946
5947   ExpectString("obj1.x", "z");
5948   ExpectString("obj2.x", "z");
5949 }
5950
5951
5952 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5953   v8::Isolate* isolate = CcTest::isolate();
5954   v8::HandleScope scope(isolate);
5955   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5956   LocalContext context;
5957
5958   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5959   CompileRun("var obj2 = {};");
5960
5961   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5962         v8_str("x"),
5963         GetXValue, NULL,
5964         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5965   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5966         v8_str("x"),
5967         GetXValue, NULL,
5968         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5969
5970   ExpectString("obj1.x", "x");
5971   ExpectString("obj2.x", "x");
5972
5973   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5974   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5975
5976   CHECK(!GetGlobalProperty(&context, "obj1")->
5977       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5978   CHECK(!GetGlobalProperty(&context, "obj2")->
5979       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5980
5981   {
5982     v8::TryCatch try_catch;
5983     CompileRun("Object.defineProperty(obj1, 'x',"
5984         "{get: function() { return 'func'; }})");
5985     CHECK(try_catch.HasCaught());
5986     String::Utf8Value exception_value(try_catch.Exception());
5987     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5988   }
5989   {
5990     v8::TryCatch try_catch;
5991     CompileRun("Object.defineProperty(obj2, 'x',"
5992         "{get: function() { return 'func'; }})");
5993     CHECK(try_catch.HasCaught());
5994     String::Utf8Value exception_value(try_catch.Exception());
5995     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5996   }
5997 }
5998
5999
6000 static void Get239Value(Local<String> name,
6001                         const v8::PropertyCallbackInfo<v8::Value>& info) {
6002   ApiTestFuzzer::Fuzz();
6003   CHECK_EQ(info.Data(), v8_str("donut"));
6004   CHECK_EQ(name, v8_str("239"));
6005   info.GetReturnValue().Set(name);
6006 }
6007
6008
6009 THREADED_TEST(ElementAPIAccessor) {
6010   v8::Isolate* isolate = CcTest::isolate();
6011   v8::HandleScope scope(isolate);
6012   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6013   LocalContext context;
6014
6015   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
6016   CompileRun("var obj2 = {};");
6017
6018   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
6019         v8_str("239"),
6020         Get239Value, NULL,
6021         v8_str("donut")));
6022   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
6023         v8_str("239"),
6024         Get239Value, NULL,
6025         v8_str("donut")));
6026
6027   ExpectString("obj1[239]", "239");
6028   ExpectString("obj2[239]", "239");
6029   ExpectString("obj1['239']", "239");
6030   ExpectString("obj2['239']", "239");
6031 }
6032
6033
6034 v8::Persistent<Value> xValue;
6035
6036
6037 static void SetXValue(Local<String> name,
6038                       Local<Value> value,
6039                       const v8::PropertyCallbackInfo<void>& info) {
6040   CHECK_EQ(value, v8_num(4));
6041   CHECK_EQ(info.Data(), v8_str("donut"));
6042   CHECK_EQ(name, v8_str("x"));
6043   CHECK(xValue.IsEmpty());
6044   xValue.Reset(info.GetIsolate(), value);
6045 }
6046
6047
6048 THREADED_TEST(SimplePropertyWrite) {
6049   v8::Isolate* isolate = CcTest::isolate();
6050   v8::HandleScope scope(isolate);
6051   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6052   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6053   LocalContext context;
6054   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6055   Local<Script> script = v8_compile("obj.x = 4");
6056   for (int i = 0; i < 10; i++) {
6057     CHECK(xValue.IsEmpty());
6058     script->Run();
6059     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6060     xValue.Reset();
6061   }
6062 }
6063
6064
6065 THREADED_TEST(SetterOnly) {
6066   v8::Isolate* isolate = CcTest::isolate();
6067   v8::HandleScope scope(isolate);
6068   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6069   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
6070   LocalContext context;
6071   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6072   Local<Script> script = v8_compile("obj.x = 4; obj.x");
6073   for (int i = 0; i < 10; i++) {
6074     CHECK(xValue.IsEmpty());
6075     script->Run();
6076     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6077     xValue.Reset();
6078   }
6079 }
6080
6081
6082 THREADED_TEST(NoAccessors) {
6083   v8::Isolate* isolate = CcTest::isolate();
6084   v8::HandleScope scope(isolate);
6085   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6086   templ->SetAccessor(v8_str("x"),
6087                      static_cast<v8::AccessorGetterCallback>(NULL),
6088                      NULL,
6089                      v8_str("donut"));
6090   LocalContext context;
6091   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6092   Local<Script> script = v8_compile("obj.x = 4; obj.x");
6093   for (int i = 0; i < 10; i++) {
6094     script->Run();
6095   }
6096 }
6097
6098
6099 static void XPropertyGetter(Local<String> property,
6100                             const v8::PropertyCallbackInfo<v8::Value>& info) {
6101   ApiTestFuzzer::Fuzz();
6102   CHECK(info.Data()->IsUndefined());
6103   info.GetReturnValue().Set(property);
6104 }
6105
6106
6107 THREADED_TEST(NamedInterceptorPropertyRead) {
6108   v8::Isolate* isolate = CcTest::isolate();
6109   v8::HandleScope scope(isolate);
6110   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6111   templ->SetNamedPropertyHandler(XPropertyGetter);
6112   LocalContext context;
6113   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6114   Local<Script> script = v8_compile("obj.x");
6115   for (int i = 0; i < 10; i++) {
6116     Local<Value> result = script->Run();
6117     CHECK_EQ(result, v8_str("x"));
6118   }
6119 }
6120
6121
6122 THREADED_TEST(NamedInterceptorDictionaryIC) {
6123   v8::Isolate* isolate = CcTest::isolate();
6124   v8::HandleScope scope(isolate);
6125   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6126   templ->SetNamedPropertyHandler(XPropertyGetter);
6127   LocalContext context;
6128   // Create an object with a named interceptor.
6129   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
6130   Local<Script> script = v8_compile("interceptor_obj.x");
6131   for (int i = 0; i < 10; i++) {
6132     Local<Value> result = script->Run();
6133     CHECK_EQ(result, v8_str("x"));
6134   }
6135   // Create a slow case object and a function accessing a property in
6136   // that slow case object (with dictionary probing in generated
6137   // code). Then force object with a named interceptor into slow-case,
6138   // pass it to the function, and check that the interceptor is called
6139   // instead of accessing the local property.
6140   Local<Value> result =
6141       CompileRun("function get_x(o) { return o.x; };"
6142                  "var obj = { x : 42, y : 0 };"
6143                  "delete obj.y;"
6144                  "for (var i = 0; i < 10; i++) get_x(obj);"
6145                  "interceptor_obj.x = 42;"
6146                  "interceptor_obj.y = 10;"
6147                  "delete interceptor_obj.y;"
6148                  "get_x(interceptor_obj)");
6149   CHECK_EQ(result, v8_str("x"));
6150 }
6151
6152
6153 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
6154   v8::Isolate* isolate = CcTest::isolate();
6155   v8::HandleScope scope(isolate);
6156   v8::Local<Context> context1 = Context::New(isolate);
6157
6158   context1->Enter();
6159   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6160   templ->SetNamedPropertyHandler(XPropertyGetter);
6161   // Create an object with a named interceptor.
6162   v8::Local<v8::Object> object = templ->NewInstance();
6163   context1->Global()->Set(v8_str("interceptor_obj"), object);
6164
6165   // Force the object into the slow case.
6166   CompileRun("interceptor_obj.y = 0;"
6167              "delete interceptor_obj.y;");
6168   context1->Exit();
6169
6170   {
6171     // Introduce the object into a different context.
6172     // Repeat named loads to exercise ICs.
6173     LocalContext context2;
6174     context2->Global()->Set(v8_str("interceptor_obj"), object);
6175     Local<Value> result =
6176       CompileRun("function get_x(o) { return o.x; }"
6177                  "interceptor_obj.x = 42;"
6178                  "for (var i=0; i != 10; i++) {"
6179                  "  get_x(interceptor_obj);"
6180                  "}"
6181                  "get_x(interceptor_obj)");
6182     // Check that the interceptor was actually invoked.
6183     CHECK_EQ(result, v8_str("x"));
6184   }
6185
6186   // Return to the original context and force some object to the slow case
6187   // to cause the NormalizedMapCache to verify.
6188   context1->Enter();
6189   CompileRun("var obj = { x : 0 }; delete obj.x;");
6190   context1->Exit();
6191 }
6192
6193
6194 static void SetXOnPrototypeGetter(
6195     Local<String> property,
6196     const v8::PropertyCallbackInfo<v8::Value>& info) {
6197   // Set x on the prototype object and do not handle the get request.
6198   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
6199   proto.As<v8::Object>()->Set(v8_str("x"),
6200                               v8::Integer::New(info.GetIsolate(), 23));
6201 }
6202
6203
6204 // This is a regression test for http://crbug.com/20104. Map
6205 // transitions should not interfere with post interceptor lookup.
6206 THREADED_TEST(NamedInterceptorMapTransitionRead) {
6207   v8::Isolate* isolate = CcTest::isolate();
6208   v8::HandleScope scope(isolate);
6209   Local<v8::FunctionTemplate> function_template =
6210       v8::FunctionTemplate::New(isolate);
6211   Local<v8::ObjectTemplate> instance_template
6212       = function_template->InstanceTemplate();
6213   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
6214   LocalContext context;
6215   context->Global()->Set(v8_str("F"), function_template->GetFunction());
6216   // Create an instance of F and introduce a map transition for x.
6217   CompileRun("var o = new F(); o.x = 23;");
6218   // Create an instance of F and invoke the getter. The result should be 23.
6219   Local<Value> result = CompileRun("o = new F(); o.x");
6220   CHECK_EQ(result->Int32Value(), 23);
6221 }
6222
6223
6224 static void IndexedPropertyGetter(
6225     uint32_t index,
6226     const v8::PropertyCallbackInfo<v8::Value>& info) {
6227   ApiTestFuzzer::Fuzz();
6228   if (index == 37) {
6229     info.GetReturnValue().Set(v8_num(625));
6230   }
6231 }
6232
6233
6234 static void IndexedPropertySetter(
6235     uint32_t index,
6236     Local<Value> value,
6237     const v8::PropertyCallbackInfo<v8::Value>& info) {
6238   ApiTestFuzzer::Fuzz();
6239   if (index == 39) {
6240     info.GetReturnValue().Set(value);
6241   }
6242 }
6243
6244
6245 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
6246   v8::Isolate* isolate = CcTest::isolate();
6247   v8::HandleScope scope(isolate);
6248   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6249   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
6250                                    IndexedPropertySetter);
6251   LocalContext context;
6252   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6253   Local<Script> getter_script = v8_compile(
6254       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6255   Local<Script> setter_script = v8_compile(
6256       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6257       "obj[17] = 23;"
6258       "obj.foo;");
6259   Local<Script> interceptor_setter_script = v8_compile(
6260       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6261       "obj[39] = 47;"
6262       "obj.foo;");  // This setter should not run, due to the interceptor.
6263   Local<Script> interceptor_getter_script = v8_compile(
6264       "obj[37];");
6265   Local<Value> result = getter_script->Run();
6266   CHECK_EQ(v8_num(5), result);
6267   result = setter_script->Run();
6268   CHECK_EQ(v8_num(23), result);
6269   result = interceptor_setter_script->Run();
6270   CHECK_EQ(v8_num(23), result);
6271   result = interceptor_getter_script->Run();
6272   CHECK_EQ(v8_num(625), result);
6273 }
6274
6275
6276 static void UnboxedDoubleIndexedPropertyGetter(
6277     uint32_t index,
6278     const v8::PropertyCallbackInfo<v8::Value>& info) {
6279   ApiTestFuzzer::Fuzz();
6280   if (index < 25) {
6281     info.GetReturnValue().Set(v8_num(index));
6282   }
6283 }
6284
6285
6286 static void UnboxedDoubleIndexedPropertySetter(
6287     uint32_t index,
6288     Local<Value> value,
6289     const v8::PropertyCallbackInfo<v8::Value>& info) {
6290   ApiTestFuzzer::Fuzz();
6291   if (index < 25) {
6292     info.GetReturnValue().Set(v8_num(index));
6293   }
6294 }
6295
6296
6297 void UnboxedDoubleIndexedPropertyEnumerator(
6298     const v8::PropertyCallbackInfo<v8::Array>& info) {
6299   // Force the list of returned keys to be stored in a FastDoubleArray.
6300   Local<Script> indexed_property_names_script = v8_compile(
6301       "keys = new Array(); keys[125000] = 1;"
6302       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6303       "keys.length = 25; keys;");
6304   Local<Value> result = indexed_property_names_script->Run();
6305   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6306 }
6307
6308
6309 // Make sure that the the interceptor code in the runtime properly handles
6310 // merging property name lists for double-array-backed arrays.
6311 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6312   v8::Isolate* isolate = CcTest::isolate();
6313   v8::HandleScope scope(isolate);
6314   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6315   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6316                                    UnboxedDoubleIndexedPropertySetter,
6317                                    0,
6318                                    0,
6319                                    UnboxedDoubleIndexedPropertyEnumerator);
6320   LocalContext context;
6321   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6322   // When obj is created, force it to be Stored in a FastDoubleArray.
6323   Local<Script> create_unboxed_double_script = v8_compile(
6324       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6325       "key_count = 0; "
6326       "for (x in obj) {key_count++;};"
6327       "obj;");
6328   Local<Value> result = create_unboxed_double_script->Run();
6329   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6330   Local<Script> key_count_check = v8_compile("key_count;");
6331   result = key_count_check->Run();
6332   CHECK_EQ(v8_num(40013), result);
6333 }
6334
6335
6336 void SloppyArgsIndexedPropertyEnumerator(
6337     const v8::PropertyCallbackInfo<v8::Array>& info) {
6338   // Force the list of returned keys to be stored in a Arguments object.
6339   Local<Script> indexed_property_names_script = v8_compile(
6340       "function f(w,x) {"
6341       " return arguments;"
6342       "}"
6343       "keys = f(0, 1, 2, 3);"
6344       "keys;");
6345   Local<Object> result =
6346       Local<Object>::Cast(indexed_property_names_script->Run());
6347   // Have to populate the handle manually, as it's not Cast-able.
6348   i::Handle<i::JSObject> o =
6349       v8::Utils::OpenHandle<Object, i::JSObject>(result);
6350   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6351   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6352 }
6353
6354
6355 static void SloppyIndexedPropertyGetter(
6356     uint32_t index,
6357     const v8::PropertyCallbackInfo<v8::Value>& info) {
6358   ApiTestFuzzer::Fuzz();
6359   if (index < 4) {
6360     info.GetReturnValue().Set(v8_num(index));
6361   }
6362 }
6363
6364
6365 // Make sure that the the interceptor code in the runtime properly handles
6366 // merging property name lists for non-string arguments arrays.
6367 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6368   v8::Isolate* isolate = CcTest::isolate();
6369   v8::HandleScope scope(isolate);
6370   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6371   templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6372                                    0,
6373                                    0,
6374                                    0,
6375                                    SloppyArgsIndexedPropertyEnumerator);
6376   LocalContext context;
6377   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6378   Local<Script> create_args_script = v8_compile(
6379       "var key_count = 0;"
6380       "for (x in obj) {key_count++;} key_count;");
6381   Local<Value> result = create_args_script->Run();
6382   CHECK_EQ(v8_num(4), result);
6383 }
6384
6385
6386 static void IdentityIndexedPropertyGetter(
6387     uint32_t index,
6388     const v8::PropertyCallbackInfo<v8::Value>& info) {
6389   info.GetReturnValue().Set(index);
6390 }
6391
6392
6393 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6394   v8::Isolate* isolate = CcTest::isolate();
6395   v8::HandleScope scope(isolate);
6396   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6397   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6398
6399   LocalContext context;
6400   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6401
6402   // Check fast object case.
6403   const char* fast_case_code =
6404       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6405   ExpectString(fast_case_code, "0");
6406
6407   // Check slow case.
6408   const char* slow_case_code =
6409       "obj.x = 1; delete obj.x;"
6410       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6411   ExpectString(slow_case_code, "1");
6412 }
6413
6414
6415 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6416   v8::Isolate* isolate = CcTest::isolate();
6417   v8::HandleScope scope(isolate);
6418   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6419   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6420
6421   LocalContext context;
6422   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6423
6424   const char* code =
6425       "try {"
6426       "  obj[0] = 239;"
6427       "  for (var i = 0; i < 100; i++) {"
6428       "    var v = obj[0];"
6429       "    if (v != 0) 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(IndexedInterceptorWithAccessorCheck) {
6440   v8::Isolate* isolate = CcTest::isolate();
6441   v8::HandleScope scope(isolate);
6442   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6443   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6444
6445   LocalContext context;
6446   Local<v8::Object> obj = templ->NewInstance();
6447   obj->TurnOnAccessCheck();
6448   context->Global()->Set(v8_str("obj"), obj);
6449
6450   const char* code =
6451       "var result = 'PASSED';"
6452       "for (var i = 0; i < 100; i++) {"
6453       "  try {"
6454       "    var v = obj[0];"
6455       "    result = 'Wrong value ' + v + ' at iteration ' + i;"
6456       "    break;"
6457       "  } catch (e) {"
6458       "    /* pass */"
6459       "  }"
6460       "}"
6461       "result";
6462   ExpectString(code, "PASSED");
6463 }
6464
6465
6466 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6467   i::FLAG_allow_natives_syntax = true;
6468   v8::Isolate* isolate = CcTest::isolate();
6469   v8::HandleScope scope(isolate);
6470   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6471   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6472
6473   LocalContext context;
6474   Local<v8::Object> obj = templ->NewInstance();
6475   context->Global()->Set(v8_str("obj"), obj);
6476
6477   const char* code =
6478       "var result = 'PASSED';"
6479       "for (var i = 0; i < 100; i++) {"
6480       "  var expected = i;"
6481       "  if (i == 5) {"
6482       "    %EnableAccessChecks(obj);"
6483       "  }"
6484       "  try {"
6485       "    var v = obj[i];"
6486       "    if (i == 5) {"
6487       "      result = 'Should not have reached this!';"
6488       "      break;"
6489       "    } else if (v != expected) {"
6490       "      result = 'Wrong value ' + v + ' at iteration ' + i;"
6491       "      break;"
6492       "    }"
6493       "  } catch (e) {"
6494       "    if (i != 5) {"
6495       "      result = e;"
6496       "    }"
6497       "  }"
6498       "  if (i == 5) %DisableAccessChecks(obj);"
6499       "}"
6500       "result";
6501   ExpectString(code, "PASSED");
6502 }
6503
6504
6505 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6506   v8::Isolate* isolate = CcTest::isolate();
6507   v8::HandleScope scope(isolate);
6508   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6509   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6510
6511   LocalContext context;
6512   Local<v8::Object> obj = templ->NewInstance();
6513   context->Global()->Set(v8_str("obj"), obj);
6514
6515   const char* code =
6516       "try {"
6517       "  for (var i = 0; i < 100; i++) {"
6518       "    var v = obj[i];"
6519       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6520       "  }"
6521       "  'PASSED'"
6522       "} catch(e) {"
6523       "  e"
6524       "}";
6525   ExpectString(code, "PASSED");
6526 }
6527
6528
6529 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6530   v8::Isolate* isolate = CcTest::isolate();
6531   v8::HandleScope scope(isolate);
6532   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6533   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6534
6535   LocalContext context;
6536   Local<v8::Object> obj = templ->NewInstance();
6537   context->Global()->Set(v8_str("obj"), obj);
6538
6539   const char* code =
6540       "try {"
6541       "  for (var i = 0; i < 100; i++) {"
6542       "    var expected = i;"
6543       "    var key = i;"
6544       "    if (i == 25) {"
6545       "       key = -1;"
6546       "       expected = undefined;"
6547       "    }"
6548       "    if (i == 50) {"
6549       "       /* probe minimal Smi number on 32-bit platforms */"
6550       "       key = -(1 << 30);"
6551       "       expected = undefined;"
6552       "    }"
6553       "    if (i == 75) {"
6554       "       /* probe minimal Smi number on 64-bit platforms */"
6555       "       key = 1 << 31;"
6556       "       expected = undefined;"
6557       "    }"
6558       "    var v = obj[key];"
6559       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6560       "  }"
6561       "  'PASSED'"
6562       "} catch(e) {"
6563       "  e"
6564       "}";
6565   ExpectString(code, "PASSED");
6566 }
6567
6568
6569 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6570   v8::Isolate* isolate = CcTest::isolate();
6571   v8::HandleScope scope(isolate);
6572   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6573   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6574
6575   LocalContext context;
6576   Local<v8::Object> obj = templ->NewInstance();
6577   context->Global()->Set(v8_str("obj"), obj);
6578
6579   const char* code =
6580       "try {"
6581       "  for (var i = 0; i < 100; i++) {"
6582       "    var expected = i;"
6583       "    var key = i;"
6584       "    if (i == 50) {"
6585       "       key = 'foobar';"
6586       "       expected = undefined;"
6587       "    }"
6588       "    var v = obj[key];"
6589       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6590       "  }"
6591       "  'PASSED'"
6592       "} catch(e) {"
6593       "  e"
6594       "}";
6595   ExpectString(code, "PASSED");
6596 }
6597
6598
6599 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6600   v8::Isolate* isolate = CcTest::isolate();
6601   v8::HandleScope scope(isolate);
6602   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6603   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6604
6605   LocalContext context;
6606   Local<v8::Object> obj = templ->NewInstance();
6607   context->Global()->Set(v8_str("obj"), obj);
6608
6609   const char* code =
6610       "var original = obj;"
6611       "try {"
6612       "  for (var i = 0; i < 100; i++) {"
6613       "    var expected = i;"
6614       "    if (i == 50) {"
6615       "       obj = {50: 'foobar'};"
6616       "       expected = 'foobar';"
6617       "    }"
6618       "    var v = obj[i];"
6619       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6620       "    if (i == 50) obj = original;"
6621       "  }"
6622       "  'PASSED'"
6623       "} catch(e) {"
6624       "  e"
6625       "}";
6626   ExpectString(code, "PASSED");
6627 }
6628
6629
6630 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6631   v8::Isolate* isolate = CcTest::isolate();
6632   v8::HandleScope scope(isolate);
6633   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6634   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6635
6636   LocalContext context;
6637   Local<v8::Object> obj = templ->NewInstance();
6638   context->Global()->Set(v8_str("obj"), obj);
6639
6640   const char* code =
6641       "var original = obj;"
6642       "try {"
6643       "  for (var i = 0; i < 100; i++) {"
6644       "    var expected = i;"
6645       "    if (i == 5) {"
6646       "       obj = 239;"
6647       "       expected = undefined;"
6648       "    }"
6649       "    var v = obj[i];"
6650       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6651       "    if (i == 5) obj = original;"
6652       "  }"
6653       "  'PASSED'"
6654       "} catch(e) {"
6655       "  e"
6656       "}";
6657   ExpectString(code, "PASSED");
6658 }
6659
6660
6661 THREADED_TEST(IndexedInterceptorOnProto) {
6662   v8::Isolate* isolate = CcTest::isolate();
6663   v8::HandleScope scope(isolate);
6664   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6665   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6666
6667   LocalContext context;
6668   Local<v8::Object> obj = templ->NewInstance();
6669   context->Global()->Set(v8_str("obj"), obj);
6670
6671   const char* code =
6672       "var o = {__proto__: obj};"
6673       "try {"
6674       "  for (var i = 0; i < 100; i++) {"
6675       "    var v = o[i];"
6676       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6677       "  }"
6678       "  'PASSED'"
6679       "} catch(e) {"
6680       "  e"
6681       "}";
6682   ExpectString(code, "PASSED");
6683 }
6684
6685
6686 THREADED_TEST(MultiContexts) {
6687   v8::Isolate* isolate = CcTest::isolate();
6688   v8::HandleScope scope(isolate);
6689   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6690   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6691                                                         DummyCallHandler));
6692
6693   Local<String> password = v8_str("Password");
6694
6695   // Create an environment
6696   LocalContext context0(0, templ);
6697   context0->SetSecurityToken(password);
6698   v8::Handle<v8::Object> global0 = context0->Global();
6699   global0->Set(v8_str("custom"), v8_num(1234));
6700   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6701
6702   // Create an independent environment
6703   LocalContext context1(0, templ);
6704   context1->SetSecurityToken(password);
6705   v8::Handle<v8::Object> global1 = context1->Global();
6706   global1->Set(v8_str("custom"), v8_num(1234));
6707   CHECK_NE(global0, global1);
6708   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6709   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6710
6711   // Now create a new context with the old global
6712   LocalContext context2(0, templ, global1);
6713   context2->SetSecurityToken(password);
6714   v8::Handle<v8::Object> global2 = context2->Global();
6715   CHECK_EQ(global1, global2);
6716   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6717   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6718 }
6719
6720
6721 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6722   // Make sure that functions created by cloning boilerplates cannot
6723   // communicate through their __proto__ field.
6724
6725   v8::HandleScope scope(CcTest::isolate());
6726
6727   LocalContext env0;
6728   v8::Handle<v8::Object> global0 =
6729       env0->Global();
6730   v8::Handle<v8::Object> object0 =
6731       global0->Get(v8_str("Object")).As<v8::Object>();
6732   v8::Handle<v8::Object> tostring0 =
6733       object0->Get(v8_str("toString")).As<v8::Object>();
6734   v8::Handle<v8::Object> proto0 =
6735       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6736   proto0->Set(v8_str("custom"), v8_num(1234));
6737
6738   LocalContext env1;
6739   v8::Handle<v8::Object> global1 =
6740       env1->Global();
6741   v8::Handle<v8::Object> object1 =
6742       global1->Get(v8_str("Object")).As<v8::Object>();
6743   v8::Handle<v8::Object> tostring1 =
6744       object1->Get(v8_str("toString")).As<v8::Object>();
6745   v8::Handle<v8::Object> proto1 =
6746       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6747   CHECK(!proto1->Has(v8_str("custom")));
6748 }
6749
6750
6751 THREADED_TEST(Regress892105) {
6752   // Make sure that object and array literals created by cloning
6753   // boilerplates cannot communicate through their __proto__
6754   // field. This is rather difficult to check, but we try to add stuff
6755   // to Object.prototype and Array.prototype and create a new
6756   // environment. This should succeed.
6757
6758   v8::HandleScope scope(CcTest::isolate());
6759
6760   Local<String> source = v8_str("Object.prototype.obj = 1234;"
6761                                 "Array.prototype.arr = 4567;"
6762                                 "8901");
6763
6764   LocalContext env0;
6765   Local<Script> script0 = v8_compile(source);
6766   CHECK_EQ(8901.0, script0->Run()->NumberValue());
6767
6768   LocalContext env1;
6769   Local<Script> script1 = v8_compile(source);
6770   CHECK_EQ(8901.0, script1->Run()->NumberValue());
6771 }
6772
6773
6774 THREADED_TEST(UndetectableObject) {
6775   LocalContext env;
6776   v8::HandleScope scope(env->GetIsolate());
6777
6778   Local<v8::FunctionTemplate> desc =
6779       v8::FunctionTemplate::New(env->GetIsolate());
6780   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6781
6782   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6783   env->Global()->Set(v8_str("undetectable"), obj);
6784
6785   ExpectString("undetectable.toString()", "[object Object]");
6786   ExpectString("typeof undetectable", "undefined");
6787   ExpectString("typeof(undetectable)", "undefined");
6788   ExpectBoolean("typeof undetectable == 'undefined'", true);
6789   ExpectBoolean("typeof undetectable == 'object'", false);
6790   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6791   ExpectBoolean("!undetectable", true);
6792
6793   ExpectObject("true&&undetectable", obj);
6794   ExpectBoolean("false&&undetectable", false);
6795   ExpectBoolean("true||undetectable", true);
6796   ExpectObject("false||undetectable", obj);
6797
6798   ExpectObject("undetectable&&true", obj);
6799   ExpectObject("undetectable&&false", obj);
6800   ExpectBoolean("undetectable||true", true);
6801   ExpectBoolean("undetectable||false", false);
6802
6803   ExpectBoolean("undetectable==null", true);
6804   ExpectBoolean("null==undetectable", true);
6805   ExpectBoolean("undetectable==undefined", true);
6806   ExpectBoolean("undefined==undetectable", true);
6807   ExpectBoolean("undetectable==undetectable", true);
6808
6809
6810   ExpectBoolean("undetectable===null", false);
6811   ExpectBoolean("null===undetectable", false);
6812   ExpectBoolean("undetectable===undefined", false);
6813   ExpectBoolean("undefined===undetectable", false);
6814   ExpectBoolean("undetectable===undetectable", true);
6815 }
6816
6817
6818 THREADED_TEST(VoidLiteral) {
6819   LocalContext env;
6820   v8::Isolate* isolate = env->GetIsolate();
6821   v8::HandleScope scope(isolate);
6822
6823   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6824   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6825
6826   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6827   env->Global()->Set(v8_str("undetectable"), obj);
6828
6829   ExpectBoolean("undefined == void 0", true);
6830   ExpectBoolean("undetectable == void 0", true);
6831   ExpectBoolean("null == void 0", true);
6832   ExpectBoolean("undefined === void 0", true);
6833   ExpectBoolean("undetectable === void 0", false);
6834   ExpectBoolean("null === void 0", false);
6835
6836   ExpectBoolean("void 0 == undefined", true);
6837   ExpectBoolean("void 0 == undetectable", true);
6838   ExpectBoolean("void 0 == null", true);
6839   ExpectBoolean("void 0 === undefined", true);
6840   ExpectBoolean("void 0 === undetectable", false);
6841   ExpectBoolean("void 0 === null", false);
6842
6843   ExpectString("(function() {"
6844                "  try {"
6845                "    return x === void 0;"
6846                "  } catch(e) {"
6847                "    return e.toString();"
6848                "  }"
6849                "})()",
6850                "ReferenceError: x is not defined");
6851   ExpectString("(function() {"
6852                "  try {"
6853                "    return void 0 === x;"
6854                "  } catch(e) {"
6855                "    return e.toString();"
6856                "  }"
6857                "})()",
6858                "ReferenceError: x is not defined");
6859 }
6860
6861
6862 THREADED_TEST(ExtensibleOnUndetectable) {
6863   LocalContext env;
6864   v8::Isolate* isolate = env->GetIsolate();
6865   v8::HandleScope scope(isolate);
6866
6867   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6868   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6869
6870   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6871   env->Global()->Set(v8_str("undetectable"), obj);
6872
6873   Local<String> source = v8_str("undetectable.x = 42;"
6874                                 "undetectable.x");
6875
6876   Local<Script> script = v8_compile(source);
6877
6878   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6879
6880   ExpectBoolean("Object.isExtensible(undetectable)", true);
6881
6882   source = v8_str("Object.preventExtensions(undetectable);");
6883   script = v8_compile(source);
6884   script->Run();
6885   ExpectBoolean("Object.isExtensible(undetectable)", false);
6886
6887   source = v8_str("undetectable.y = 2000;");
6888   script = v8_compile(source);
6889   script->Run();
6890   ExpectBoolean("undetectable.y == undefined", true);
6891 }
6892
6893
6894
6895 THREADED_TEST(UndetectableString) {
6896   LocalContext env;
6897   v8::HandleScope scope(env->GetIsolate());
6898
6899   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6900                                           String::kUndetectableString);
6901   env->Global()->Set(v8_str("undetectable"), obj);
6902
6903   ExpectString("undetectable", "foo");
6904   ExpectString("typeof undetectable", "undefined");
6905   ExpectString("typeof(undetectable)", "undefined");
6906   ExpectBoolean("typeof undetectable == 'undefined'", true);
6907   ExpectBoolean("typeof undetectable == 'string'", false);
6908   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6909   ExpectBoolean("!undetectable", true);
6910
6911   ExpectObject("true&&undetectable", obj);
6912   ExpectBoolean("false&&undetectable", false);
6913   ExpectBoolean("true||undetectable", true);
6914   ExpectObject("false||undetectable", obj);
6915
6916   ExpectObject("undetectable&&true", obj);
6917   ExpectObject("undetectable&&false", obj);
6918   ExpectBoolean("undetectable||true", true);
6919   ExpectBoolean("undetectable||false", false);
6920
6921   ExpectBoolean("undetectable==null", true);
6922   ExpectBoolean("null==undetectable", true);
6923   ExpectBoolean("undetectable==undefined", true);
6924   ExpectBoolean("undefined==undetectable", true);
6925   ExpectBoolean("undetectable==undetectable", true);
6926
6927
6928   ExpectBoolean("undetectable===null", false);
6929   ExpectBoolean("null===undetectable", false);
6930   ExpectBoolean("undetectable===undefined", false);
6931   ExpectBoolean("undefined===undetectable", false);
6932   ExpectBoolean("undetectable===undetectable", true);
6933 }
6934
6935
6936 TEST(UndetectableOptimized) {
6937   i::FLAG_allow_natives_syntax = true;
6938   LocalContext env;
6939   v8::HandleScope scope(env->GetIsolate());
6940
6941   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6942                                           String::kUndetectableString);
6943   env->Global()->Set(v8_str("undetectable"), obj);
6944   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6945
6946   ExpectString(
6947       "function testBranch() {"
6948       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
6949       "  if (%_IsUndetectableObject(detectable)) throw 2;"
6950       "}\n"
6951       "function testBool() {"
6952       "  var b1 = !%_IsUndetectableObject(undetectable);"
6953       "  var b2 = %_IsUndetectableObject(detectable);"
6954       "  if (b1) throw 3;"
6955       "  if (b2) throw 4;"
6956       "  return b1 == b2;"
6957       "}\n"
6958       "%OptimizeFunctionOnNextCall(testBranch);"
6959       "%OptimizeFunctionOnNextCall(testBool);"
6960       "for (var i = 0; i < 10; i++) {"
6961       "  testBranch();"
6962       "  testBool();"
6963       "}\n"
6964       "\"PASS\"",
6965       "PASS");
6966 }
6967
6968
6969 // The point of this test is type checking. We run it only so compilers
6970 // don't complain about an unused function.
6971 TEST(PersistentHandles) {
6972   LocalContext env;
6973   v8::Isolate* isolate = CcTest::isolate();
6974   v8::HandleScope scope(isolate);
6975   Local<String> str = v8_str("foo");
6976   v8::Persistent<String> p_str(isolate, str);
6977   p_str.Reset();
6978   Local<Script> scr = v8_compile("");
6979   v8::Persistent<Script> p_scr(isolate, scr);
6980   p_scr.Reset();
6981   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6982   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6983   p_templ.Reset();
6984 }
6985
6986
6987 static void HandleLogDelegator(
6988     const v8::FunctionCallbackInfo<v8::Value>& args) {
6989   ApiTestFuzzer::Fuzz();
6990 }
6991
6992
6993 THREADED_TEST(GlobalObjectTemplate) {
6994   v8::Isolate* isolate = CcTest::isolate();
6995   v8::HandleScope handle_scope(isolate);
6996   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6997   global_template->Set(v8_str("JSNI_Log"),
6998                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6999   v8::Local<Context> context = Context::New(isolate, 0, global_template);
7000   Context::Scope context_scope(context);
7001   CompileRun("JSNI_Log('LOG')");
7002 }
7003
7004
7005 static const char* kSimpleExtensionSource =
7006   "function Foo() {"
7007   "  return 4;"
7008   "}";
7009
7010
7011 TEST(SimpleExtensions) {
7012   v8::HandleScope handle_scope(CcTest::isolate());
7013   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
7014   const char* extension_names[] = { "simpletest" };
7015   v8::ExtensionConfiguration extensions(1, extension_names);
7016   v8::Handle<Context> context =
7017       Context::New(CcTest::isolate(), &extensions);
7018   Context::Scope lock(context);
7019   v8::Handle<Value> result = CompileRun("Foo()");
7020   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7021 }
7022
7023
7024 static const char* kStackTraceFromExtensionSource =
7025   "function foo() {"
7026   "  throw new Error();"
7027   "}"
7028   "function bar() {"
7029   "  foo();"
7030   "}";
7031
7032
7033 TEST(StackTraceInExtension) {
7034   v8::HandleScope handle_scope(CcTest::isolate());
7035   v8::RegisterExtension(new Extension("stacktracetest",
7036                         kStackTraceFromExtensionSource));
7037   const char* extension_names[] = { "stacktracetest" };
7038   v8::ExtensionConfiguration extensions(1, extension_names);
7039   v8::Handle<Context> context =
7040       Context::New(CcTest::isolate(), &extensions);
7041   Context::Scope lock(context);
7042   CompileRun("function user() { bar(); }"
7043              "var error;"
7044              "try{ user(); } catch (e) { error = e; }");
7045   CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
7046   CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
7047   CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
7048 }
7049
7050
7051 TEST(NullExtensions) {
7052   v8::HandleScope handle_scope(CcTest::isolate());
7053   v8::RegisterExtension(new Extension("nulltest", NULL));
7054   const char* extension_names[] = { "nulltest" };
7055   v8::ExtensionConfiguration extensions(1, extension_names);
7056   v8::Handle<Context> context =
7057       Context::New(CcTest::isolate(), &extensions);
7058   Context::Scope lock(context);
7059   v8::Handle<Value> result = CompileRun("1+3");
7060   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7061 }
7062
7063
7064 static const char* kEmbeddedExtensionSource =
7065     "function Ret54321(){return 54321;}~~@@$"
7066     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
7067 static const int kEmbeddedExtensionSourceValidLen = 34;
7068
7069
7070 TEST(ExtensionMissingSourceLength) {
7071   v8::HandleScope handle_scope(CcTest::isolate());
7072   v8::RegisterExtension(new Extension("srclentest_fail",
7073                                       kEmbeddedExtensionSource));
7074   const char* extension_names[] = { "srclentest_fail" };
7075   v8::ExtensionConfiguration extensions(1, extension_names);
7076   v8::Handle<Context> context =
7077       Context::New(CcTest::isolate(), &extensions);
7078   CHECK_EQ(0, *context);
7079 }
7080
7081
7082 TEST(ExtensionWithSourceLength) {
7083   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7084        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7085     v8::HandleScope handle_scope(CcTest::isolate());
7086     i::ScopedVector<char> extension_name(32);
7087     i::SNPrintF(extension_name, "ext #%d", source_len);
7088     v8::RegisterExtension(new Extension(extension_name.start(),
7089                                         kEmbeddedExtensionSource, 0, 0,
7090                                         source_len));
7091     const char* extension_names[1] = { extension_name.start() };
7092     v8::ExtensionConfiguration extensions(1, extension_names);
7093     v8::Handle<Context> context =
7094       Context::New(CcTest::isolate(), &extensions);
7095     if (source_len == kEmbeddedExtensionSourceValidLen) {
7096       Context::Scope lock(context);
7097       v8::Handle<Value> result = CompileRun("Ret54321()");
7098       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
7099     } else {
7100       // Anything but exactly the right length should fail to compile.
7101       CHECK_EQ(0, *context);
7102     }
7103   }
7104 }
7105
7106
7107 static const char* kEvalExtensionSource1 =
7108   "function UseEval1() {"
7109   "  var x = 42;"
7110   "  return eval('x');"
7111   "}";
7112
7113
7114 static const char* kEvalExtensionSource2 =
7115   "(function() {"
7116   "  var x = 42;"
7117   "  function e() {"
7118   "    return eval('x');"
7119   "  }"
7120   "  this.UseEval2 = e;"
7121   "})()";
7122
7123
7124 TEST(UseEvalFromExtension) {
7125   v8::HandleScope handle_scope(CcTest::isolate());
7126   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7127   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7128   const char* extension_names[] = { "evaltest1", "evaltest2" };
7129   v8::ExtensionConfiguration extensions(2, extension_names);
7130   v8::Handle<Context> context =
7131       Context::New(CcTest::isolate(), &extensions);
7132   Context::Scope lock(context);
7133   v8::Handle<Value> result = CompileRun("UseEval1()");
7134   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7135   result = CompileRun("UseEval2()");
7136   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7137 }
7138
7139
7140 static const char* kWithExtensionSource1 =
7141   "function UseWith1() {"
7142   "  var x = 42;"
7143   "  with({x:87}) { return x; }"
7144   "}";
7145
7146
7147
7148 static const char* kWithExtensionSource2 =
7149   "(function() {"
7150   "  var x = 42;"
7151   "  function e() {"
7152   "    with ({x:87}) { return x; }"
7153   "  }"
7154   "  this.UseWith2 = e;"
7155   "})()";
7156
7157
7158 TEST(UseWithFromExtension) {
7159   v8::HandleScope handle_scope(CcTest::isolate());
7160   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7161   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7162   const char* extension_names[] = { "withtest1", "withtest2" };
7163   v8::ExtensionConfiguration extensions(2, extension_names);
7164   v8::Handle<Context> context =
7165       Context::New(CcTest::isolate(), &extensions);
7166   Context::Scope lock(context);
7167   v8::Handle<Value> result = CompileRun("UseWith1()");
7168   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7169   result = CompileRun("UseWith2()");
7170   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7171 }
7172
7173
7174 TEST(AutoExtensions) {
7175   v8::HandleScope handle_scope(CcTest::isolate());
7176   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7177   extension->set_auto_enable(true);
7178   v8::RegisterExtension(extension);
7179   v8::Handle<Context> context =
7180       Context::New(CcTest::isolate());
7181   Context::Scope lock(context);
7182   v8::Handle<Value> result = CompileRun("Foo()");
7183   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7184 }
7185
7186
7187 static const char* kSyntaxErrorInExtensionSource =
7188     "[";
7189
7190
7191 // Test that a syntax error in an extension does not cause a fatal
7192 // error but results in an empty context.
7193 TEST(SyntaxErrorExtensions) {
7194   v8::HandleScope handle_scope(CcTest::isolate());
7195   v8::RegisterExtension(new Extension("syntaxerror",
7196                                       kSyntaxErrorInExtensionSource));
7197   const char* extension_names[] = { "syntaxerror" };
7198   v8::ExtensionConfiguration extensions(1, extension_names);
7199   v8::Handle<Context> context =
7200       Context::New(CcTest::isolate(), &extensions);
7201   CHECK(context.IsEmpty());
7202 }
7203
7204
7205 static const char* kExceptionInExtensionSource =
7206     "throw 42";
7207
7208
7209 // Test that an exception when installing an extension does not cause
7210 // a fatal error but results in an empty context.
7211 TEST(ExceptionExtensions) {
7212   v8::HandleScope handle_scope(CcTest::isolate());
7213   v8::RegisterExtension(new Extension("exception",
7214                                       kExceptionInExtensionSource));
7215   const char* extension_names[] = { "exception" };
7216   v8::ExtensionConfiguration extensions(1, extension_names);
7217   v8::Handle<Context> context =
7218       Context::New(CcTest::isolate(), &extensions);
7219   CHECK(context.IsEmpty());
7220 }
7221
7222
7223 static const char* kNativeCallInExtensionSource =
7224     "function call_runtime_last_index_of(x) {"
7225     "  return %StringLastIndexOf(x, 'bob', 10);"
7226     "}";
7227
7228
7229 static const char* kNativeCallTest =
7230     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7231
7232 // Test that a native runtime calls are supported in extensions.
7233 TEST(NativeCallInExtensions) {
7234   v8::HandleScope handle_scope(CcTest::isolate());
7235   v8::RegisterExtension(new Extension("nativecall",
7236                                       kNativeCallInExtensionSource));
7237   const char* extension_names[] = { "nativecall" };
7238   v8::ExtensionConfiguration extensions(1, extension_names);
7239   v8::Handle<Context> context =
7240       Context::New(CcTest::isolate(), &extensions);
7241   Context::Scope lock(context);
7242   v8::Handle<Value> result = CompileRun(kNativeCallTest);
7243   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
7244 }
7245
7246
7247 class NativeFunctionExtension : public Extension {
7248  public:
7249   NativeFunctionExtension(const char* name,
7250                           const char* source,
7251                           v8::FunctionCallback fun = &Echo)
7252       : Extension(name, source),
7253         function_(fun) { }
7254
7255   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7256       v8::Isolate* isolate,
7257       v8::Handle<v8::String> name) {
7258     return v8::FunctionTemplate::New(isolate, function_);
7259   }
7260
7261   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7262     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7263   }
7264  private:
7265   v8::FunctionCallback function_;
7266 };
7267
7268
7269 TEST(NativeFunctionDeclaration) {
7270   v8::HandleScope handle_scope(CcTest::isolate());
7271   const char* name = "nativedecl";
7272   v8::RegisterExtension(new NativeFunctionExtension(name,
7273                                                     "native function foo();"));
7274   const char* extension_names[] = { name };
7275   v8::ExtensionConfiguration extensions(1, extension_names);
7276   v8::Handle<Context> context =
7277       Context::New(CcTest::isolate(), &extensions);
7278   Context::Scope lock(context);
7279   v8::Handle<Value> result = CompileRun("foo(42);");
7280   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7281 }
7282
7283
7284 TEST(NativeFunctionDeclarationError) {
7285   v8::HandleScope handle_scope(CcTest::isolate());
7286   const char* name = "nativedeclerr";
7287   // Syntax error in extension code.
7288   v8::RegisterExtension(new NativeFunctionExtension(name,
7289                                                     "native\nfunction foo();"));
7290   const char* extension_names[] = { name };
7291   v8::ExtensionConfiguration extensions(1, extension_names);
7292   v8::Handle<Context> context =
7293       Context::New(CcTest::isolate(), &extensions);
7294   CHECK(context.IsEmpty());
7295 }
7296
7297
7298 TEST(NativeFunctionDeclarationErrorEscape) {
7299   v8::HandleScope handle_scope(CcTest::isolate());
7300   const char* name = "nativedeclerresc";
7301   // Syntax error in extension code - escape code in "native" means that
7302   // it's not treated as a keyword.
7303   v8::RegisterExtension(new NativeFunctionExtension(
7304       name,
7305       "nativ\\u0065 function foo();"));
7306   const char* extension_names[] = { name };
7307   v8::ExtensionConfiguration extensions(1, extension_names);
7308   v8::Handle<Context> context =
7309       Context::New(CcTest::isolate(), &extensions);
7310   CHECK(context.IsEmpty());
7311 }
7312
7313
7314 static void CheckDependencies(const char* name, const char* expected) {
7315   v8::HandleScope handle_scope(CcTest::isolate());
7316   v8::ExtensionConfiguration config(1, &name);
7317   LocalContext context(&config);
7318   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7319            context->Global()->Get(v8_str("loaded")));
7320 }
7321
7322
7323 /*
7324  * Configuration:
7325  *
7326  *     /-- B <--\
7327  * A <-          -- D <-- E
7328  *     \-- C <--/
7329  */
7330 THREADED_TEST(ExtensionDependency) {
7331   static const char* kEDeps[] = { "D" };
7332   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7333   static const char* kDDeps[] = { "B", "C" };
7334   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7335   static const char* kBCDeps[] = { "A" };
7336   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7337   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7338   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7339   CheckDependencies("A", "undefinedA");
7340   CheckDependencies("B", "undefinedAB");
7341   CheckDependencies("C", "undefinedAC");
7342   CheckDependencies("D", "undefinedABCD");
7343   CheckDependencies("E", "undefinedABCDE");
7344   v8::HandleScope handle_scope(CcTest::isolate());
7345   static const char* exts[2] = { "C", "E" };
7346   v8::ExtensionConfiguration config(2, exts);
7347   LocalContext context(&config);
7348   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7349 }
7350
7351
7352 static const char* kExtensionTestScript =
7353   "native function A();"
7354   "native function B();"
7355   "native function C();"
7356   "function Foo(i) {"
7357   "  if (i == 0) return A();"
7358   "  if (i == 1) return B();"
7359   "  if (i == 2) return C();"
7360   "}";
7361
7362
7363 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7364   ApiTestFuzzer::Fuzz();
7365   if (args.IsConstructCall()) {
7366     args.This()->Set(v8_str("data"), args.Data());
7367     args.GetReturnValue().SetNull();
7368     return;
7369   }
7370   args.GetReturnValue().Set(args.Data());
7371 }
7372
7373
7374 class FunctionExtension : public Extension {
7375  public:
7376   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7377   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7378       v8::Isolate* isolate,
7379       v8::Handle<String> name);
7380 };
7381
7382
7383 static int lookup_count = 0;
7384 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7385     v8::Isolate* isolate, v8::Handle<String> name) {
7386   lookup_count++;
7387   if (name->Equals(v8_str("A"))) {
7388     return v8::FunctionTemplate::New(
7389         isolate, CallFun, v8::Integer::New(isolate, 8));
7390   } else if (name->Equals(v8_str("B"))) {
7391     return v8::FunctionTemplate::New(
7392         isolate, CallFun, v8::Integer::New(isolate, 7));
7393   } else if (name->Equals(v8_str("C"))) {
7394     return v8::FunctionTemplate::New(
7395         isolate, CallFun, v8::Integer::New(isolate, 6));
7396   } else {
7397     return v8::Handle<v8::FunctionTemplate>();
7398   }
7399 }
7400
7401
7402 THREADED_TEST(FunctionLookup) {
7403   v8::RegisterExtension(new FunctionExtension());
7404   v8::HandleScope handle_scope(CcTest::isolate());
7405   static const char* exts[1] = { "functiontest" };
7406   v8::ExtensionConfiguration config(1, exts);
7407   LocalContext context(&config);
7408   CHECK_EQ(3, lookup_count);
7409   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7410            CompileRun("Foo(0)"));
7411   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7412            CompileRun("Foo(1)"));
7413   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7414            CompileRun("Foo(2)"));
7415 }
7416
7417
7418 THREADED_TEST(NativeFunctionConstructCall) {
7419   v8::RegisterExtension(new FunctionExtension());
7420   v8::HandleScope handle_scope(CcTest::isolate());
7421   static const char* exts[1] = { "functiontest" };
7422   v8::ExtensionConfiguration config(1, exts);
7423   LocalContext context(&config);
7424   for (int i = 0; i < 10; i++) {
7425     // Run a few times to ensure that allocation of objects doesn't
7426     // change behavior of a constructor function.
7427     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7428              CompileRun("(new A()).data"));
7429     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7430              CompileRun("(new B()).data"));
7431     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7432              CompileRun("(new C()).data"));
7433   }
7434 }
7435
7436
7437 static const char* last_location;
7438 static const char* last_message;
7439 void StoringErrorCallback(const char* location, const char* message) {
7440   if (last_location == NULL) {
7441     last_location = location;
7442     last_message = message;
7443   }
7444 }
7445
7446
7447 // ErrorReporting creates a circular extensions configuration and
7448 // tests that the fatal error handler gets called.  This renders V8
7449 // unusable and therefore this test cannot be run in parallel.
7450 TEST(ErrorReporting) {
7451   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7452   static const char* aDeps[] = { "B" };
7453   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7454   static const char* bDeps[] = { "A" };
7455   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7456   last_location = NULL;
7457   v8::ExtensionConfiguration config(1, bDeps);
7458   v8::Handle<Context> context =
7459       Context::New(CcTest::isolate(), &config);
7460   CHECK(context.IsEmpty());
7461   CHECK_NE(last_location, NULL);
7462 }
7463
7464
7465 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7466                                              v8::Handle<Value> data) {
7467   CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7468   CHECK_EQ(v8::Undefined(CcTest::isolate()),
7469       message->GetScriptOrigin().ResourceName());
7470   message->GetLineNumber();
7471   message->GetSourceLine();
7472 }
7473
7474
7475 THREADED_TEST(ErrorWithMissingScriptInfo) {
7476   LocalContext context;
7477   v8::HandleScope scope(context->GetIsolate());
7478   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7479   CompileRun("throw Error()");
7480   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7481 }
7482
7483
7484 struct FlagAndPersistent {
7485   bool flag;
7486   v8::Persistent<v8::Object> handle;
7487 };
7488
7489
7490 static void SetFlag(
7491     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7492   data.GetParameter()->flag = true;
7493 }
7494
7495
7496 static void IndependentWeakHandle(bool global_gc, bool interlinked) {
7497   v8::Isolate* iso = CcTest::isolate();
7498   v8::HandleScope scope(iso);
7499   v8::Handle<Context> context = Context::New(iso);
7500   Context::Scope context_scope(context);
7501
7502   FlagAndPersistent object_a, object_b;
7503
7504   intptr_t big_heap_size;
7505
7506   {
7507     v8::HandleScope handle_scope(iso);
7508     Local<Object> a(v8::Object::New(iso));
7509     Local<Object> b(v8::Object::New(iso));
7510     object_a.handle.Reset(iso, a);
7511     object_b.handle.Reset(iso, b);
7512     if (interlinked) {
7513       a->Set(v8_str("x"), b);
7514       b->Set(v8_str("x"), a);
7515     }
7516     if (global_gc) {
7517       CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7518     } else {
7519       CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7520     }
7521     // We are relying on this creating a big flag array and reserving the space
7522     // up front.
7523     v8::Handle<Value> big_array = CompileRun("new Array(50000)");
7524     a->Set(v8_str("y"), big_array);
7525     big_heap_size = CcTest::heap()->SizeOfObjects();
7526   }
7527
7528   object_a.flag = false;
7529   object_b.flag = false;
7530   object_a.handle.SetPhantom(&object_a, &SetFlag);
7531   object_b.handle.SetPhantom(&object_b, &SetFlag);
7532   CHECK(!object_b.handle.IsIndependent());
7533   object_a.handle.MarkIndependent();
7534   object_b.handle.MarkIndependent();
7535   CHECK(object_b.handle.IsIndependent());
7536   if (global_gc) {
7537     CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7538   } else {
7539     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7540   }
7541   // A single GC should be enough to reclaim the memory, since we are using
7542   // phantom handles.
7543   CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
7544   CHECK(object_a.flag);
7545   CHECK(object_b.flag);
7546 }
7547
7548
7549 THREADED_TEST(IndependentWeakHandle) {
7550   IndependentWeakHandle(false, false);
7551   IndependentWeakHandle(false, true);
7552   IndependentWeakHandle(true, false);
7553   IndependentWeakHandle(true, true);
7554 }
7555
7556
7557 static void ResetUseValueAndSetFlag(
7558     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7559   // Blink will reset the handle, and then use the other handle, so they
7560   // can't use the same backing slot.
7561   data.GetParameter()->handle.Reset();
7562   data.GetValue()->IsBoolean();  // Make sure the handle still works.
7563   data.GetParameter()->flag = true;
7564 }
7565
7566
7567 static void ResetWeakHandle(bool global_gc) {
7568   v8::Isolate* iso = CcTest::isolate();
7569   v8::HandleScope scope(iso);
7570   v8::Handle<Context> context = Context::New(iso);
7571   Context::Scope context_scope(context);
7572
7573   FlagAndPersistent object_a, object_b;
7574
7575   {
7576     v8::HandleScope handle_scope(iso);
7577     Local<Object> a(v8::Object::New(iso));
7578     Local<Object> b(v8::Object::New(iso));
7579     object_a.handle.Reset(iso, a);
7580     object_b.handle.Reset(iso, b);
7581     if (global_gc) {
7582       CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7583     } else {
7584       CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7585     }
7586   }
7587
7588   object_a.flag = false;
7589   object_b.flag = false;
7590   object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
7591   object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
7592   if (!global_gc) {
7593     object_a.handle.MarkIndependent();
7594     object_b.handle.MarkIndependent();
7595     CHECK(object_b.handle.IsIndependent());
7596   }
7597   if (global_gc) {
7598     CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7599   } else {
7600     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7601   }
7602   CHECK(object_a.flag);
7603   CHECK(object_b.flag);
7604 }
7605
7606
7607 THREADED_TEST(ResetWeakHandle) {
7608   ResetWeakHandle(false);
7609   ResetWeakHandle(true);
7610 }
7611
7612
7613 static void InvokeScavenge() {
7614   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7615 }
7616
7617
7618 static void InvokeMarkSweep() {
7619   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7620 }
7621
7622
7623 static void ForceScavenge(
7624     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7625   data.GetParameter()->handle.Reset();
7626   data.GetParameter()->flag = true;
7627   InvokeScavenge();
7628 }
7629
7630
7631 static void ForceMarkSweep(
7632     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7633   data.GetParameter()->handle.Reset();
7634   data.GetParameter()->flag = true;
7635   InvokeMarkSweep();
7636 }
7637
7638
7639 THREADED_TEST(GCFromWeakCallbacks) {
7640   v8::Isolate* isolate = CcTest::isolate();
7641   v8::HandleScope scope(isolate);
7642   v8::Handle<Context> context = Context::New(isolate);
7643   Context::Scope context_scope(context);
7644
7645   static const int kNumberOfGCTypes = 2;
7646   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7647       Callback;
7648   Callback gc_forcing_callback[kNumberOfGCTypes] =
7649       {&ForceScavenge, &ForceMarkSweep};
7650
7651   typedef void (*GCInvoker)();
7652   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7653
7654   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7655     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7656       FlagAndPersistent object;
7657       {
7658         v8::HandleScope handle_scope(isolate);
7659         object.handle.Reset(isolate, v8::Object::New(isolate));
7660       }
7661       object.flag = false;
7662       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7663       object.handle.MarkIndependent();
7664       invoke_gc[outer_gc]();
7665       CHECK(object.flag);
7666     }
7667   }
7668 }
7669
7670
7671 static void RevivingCallback(
7672     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7673   data.GetParameter()->handle.ClearWeak();
7674   data.GetParameter()->flag = true;
7675 }
7676
7677
7678 THREADED_TEST(IndependentHandleRevival) {
7679   v8::Isolate* isolate = CcTest::isolate();
7680   v8::HandleScope scope(isolate);
7681   v8::Handle<Context> context = Context::New(isolate);
7682   Context::Scope context_scope(context);
7683
7684   FlagAndPersistent object;
7685   {
7686     v8::HandleScope handle_scope(isolate);
7687     v8::Local<v8::Object> o = v8::Object::New(isolate);
7688     object.handle.Reset(isolate, o);
7689     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7690     v8::Local<String> y_str = v8_str("y");
7691     o->Set(y_str, y_str);
7692   }
7693   object.flag = false;
7694   object.handle.SetWeak(&object, &RevivingCallback);
7695   object.handle.MarkIndependent();
7696   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7697   CHECK(object.flag);
7698   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7699   {
7700     v8::HandleScope handle_scope(isolate);
7701     v8::Local<v8::Object> o =
7702         v8::Local<v8::Object>::New(isolate, object.handle);
7703     v8::Local<String> y_str = v8_str("y");
7704     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7705     CHECK(o->Get(y_str)->Equals(y_str));
7706   }
7707 }
7708
7709
7710 v8::Handle<Function> args_fun;
7711
7712
7713 static void ArgumentsTestCallback(
7714     const v8::FunctionCallbackInfo<v8::Value>& args) {
7715   ApiTestFuzzer::Fuzz();
7716   v8::Isolate* isolate = args.GetIsolate();
7717   CHECK_EQ(args_fun, args.Callee());
7718   CHECK_EQ(3, args.Length());
7719   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7720   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7721   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7722   CHECK_EQ(v8::Undefined(isolate), args[3]);
7723   v8::HandleScope scope(args.GetIsolate());
7724   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7725 }
7726
7727
7728 THREADED_TEST(Arguments) {
7729   v8::Isolate* isolate = CcTest::isolate();
7730   v8::HandleScope scope(isolate);
7731   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7732   global->Set(v8_str("f"),
7733               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7734   LocalContext context(NULL, global);
7735   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7736   v8_compile("f(1, 2, 3)")->Run();
7737 }
7738
7739
7740 static void NoBlockGetterX(Local<String> name,
7741                            const v8::PropertyCallbackInfo<v8::Value>&) {
7742 }
7743
7744
7745 static void NoBlockGetterI(uint32_t index,
7746                            const v8::PropertyCallbackInfo<v8::Value>&) {
7747 }
7748
7749
7750 static void PDeleter(Local<String> name,
7751                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7752   if (!name->Equals(v8_str("foo"))) {
7753     return;  // not intercepted
7754   }
7755
7756   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7757 }
7758
7759
7760 static void IDeleter(uint32_t index,
7761                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7762   if (index != 2) {
7763     return;  // not intercepted
7764   }
7765
7766   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7767 }
7768
7769
7770 THREADED_TEST(Deleter) {
7771   v8::Isolate* isolate = CcTest::isolate();
7772   v8::HandleScope scope(isolate);
7773   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7774   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7775   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7776   LocalContext context;
7777   context->Global()->Set(v8_str("k"), obj->NewInstance());
7778   CompileRun(
7779     "k.foo = 'foo';"
7780     "k.bar = 'bar';"
7781     "k[2] = 2;"
7782     "k[4] = 4;");
7783   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7784   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7785
7786   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7787   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7788
7789   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7790   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7791
7792   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7793   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7794 }
7795
7796
7797 static void GetK(Local<String> name,
7798                  const v8::PropertyCallbackInfo<v8::Value>& info) {
7799   ApiTestFuzzer::Fuzz();
7800   if (name->Equals(v8_str("foo")) ||
7801       name->Equals(v8_str("bar")) ||
7802       name->Equals(v8_str("baz"))) {
7803     info.GetReturnValue().SetUndefined();
7804   }
7805 }
7806
7807
7808 static void IndexedGetK(uint32_t index,
7809                         const v8::PropertyCallbackInfo<v8::Value>& info) {
7810   ApiTestFuzzer::Fuzz();
7811   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7812 }
7813
7814
7815 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7816   ApiTestFuzzer::Fuzz();
7817   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7818   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7819   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7820   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7821   info.GetReturnValue().Set(result);
7822 }
7823
7824
7825 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7826   ApiTestFuzzer::Fuzz();
7827   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7828   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7829   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7830   info.GetReturnValue().Set(result);
7831 }
7832
7833
7834 THREADED_TEST(Enumerators) {
7835   v8::Isolate* isolate = CcTest::isolate();
7836   v8::HandleScope scope(isolate);
7837   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7838   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7839   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7840   LocalContext context;
7841   context->Global()->Set(v8_str("k"), obj->NewInstance());
7842   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7843     "k[10] = 0;"
7844     "k.a = 0;"
7845     "k[5] = 0;"
7846     "k.b = 0;"
7847     "k[4294967295] = 0;"
7848     "k.c = 0;"
7849     "k[4294967296] = 0;"
7850     "k.d = 0;"
7851     "k[140000] = 0;"
7852     "k.e = 0;"
7853     "k[30000000000] = 0;"
7854     "k.f = 0;"
7855     "var result = [];"
7856     "for (var prop in k) {"
7857     "  result.push(prop);"
7858     "}"
7859     "result"));
7860   // Check that we get all the property names returned including the
7861   // ones from the enumerators in the right order: indexed properties
7862   // in numerical order, indexed interceptor properties, named
7863   // properties in insertion order, named interceptor properties.
7864   // This order is not mandated by the spec, so this test is just
7865   // documenting our behavior.
7866   CHECK_EQ(17, result->Length());
7867   // Indexed properties in numerical order.
7868   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7869   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7870   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7871   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7872   // Indexed interceptor properties in the order they are returned
7873   // from the enumerator interceptor.
7874   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7875   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7876   // Named properties in insertion order.
7877   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7878   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7879   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7880   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7881   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7882   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7883   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7884   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7885   // Named interceptor properties.
7886   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7887   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7888   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7889 }
7890
7891
7892 int p_getter_count;
7893 int p_getter_count2;
7894
7895
7896 static void PGetter(Local<String> name,
7897                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7898   ApiTestFuzzer::Fuzz();
7899   p_getter_count++;
7900   v8::Handle<v8::Object> global =
7901       info.GetIsolate()->GetCurrentContext()->Global();
7902   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7903   if (name->Equals(v8_str("p1"))) {
7904     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7905   } else if (name->Equals(v8_str("p2"))) {
7906     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7907   } else if (name->Equals(v8_str("p3"))) {
7908     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7909   } else if (name->Equals(v8_str("p4"))) {
7910     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7911   }
7912 }
7913
7914
7915 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7916   ApiTestFuzzer::Fuzz();
7917   LocalContext context;
7918   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7919   CompileRun(
7920     "o1.__proto__ = { };"
7921     "var o2 = { __proto__: o1 };"
7922     "var o3 = { __proto__: o2 };"
7923     "var o4 = { __proto__: o3 };"
7924     "for (var i = 0; i < 10; i++) o4.p4;"
7925     "for (var i = 0; i < 10; i++) o3.p3;"
7926     "for (var i = 0; i < 10; i++) o2.p2;"
7927     "for (var i = 0; i < 10; i++) o1.p1;");
7928 }
7929
7930
7931 static void PGetter2(Local<String> name,
7932                      const v8::PropertyCallbackInfo<v8::Value>& info) {
7933   ApiTestFuzzer::Fuzz();
7934   p_getter_count2++;
7935   v8::Handle<v8::Object> global =
7936       info.GetIsolate()->GetCurrentContext()->Global();
7937   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7938   if (name->Equals(v8_str("p1"))) {
7939     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7940   } else if (name->Equals(v8_str("p2"))) {
7941     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7942   } else if (name->Equals(v8_str("p3"))) {
7943     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7944   } else if (name->Equals(v8_str("p4"))) {
7945     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7946   }
7947 }
7948
7949
7950 THREADED_TEST(GetterHolders) {
7951   v8::Isolate* isolate = CcTest::isolate();
7952   v8::HandleScope scope(isolate);
7953   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7954   obj->SetAccessor(v8_str("p1"), PGetter);
7955   obj->SetAccessor(v8_str("p2"), PGetter);
7956   obj->SetAccessor(v8_str("p3"), PGetter);
7957   obj->SetAccessor(v8_str("p4"), PGetter);
7958   p_getter_count = 0;
7959   RunHolderTest(obj);
7960   CHECK_EQ(40, p_getter_count);
7961 }
7962
7963
7964 THREADED_TEST(PreInterceptorHolders) {
7965   v8::Isolate* isolate = CcTest::isolate();
7966   v8::HandleScope scope(isolate);
7967   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7968   obj->SetNamedPropertyHandler(PGetter2);
7969   p_getter_count2 = 0;
7970   RunHolderTest(obj);
7971   CHECK_EQ(40, p_getter_count2);
7972 }
7973
7974
7975 THREADED_TEST(ObjectInstantiation) {
7976   v8::Isolate* isolate = CcTest::isolate();
7977   v8::HandleScope scope(isolate);
7978   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7979   templ->SetAccessor(v8_str("t"), PGetter2);
7980   LocalContext context;
7981   context->Global()->Set(v8_str("o"), templ->NewInstance());
7982   for (int i = 0; i < 100; i++) {
7983     v8::HandleScope inner_scope(CcTest::isolate());
7984     v8::Handle<v8::Object> obj = templ->NewInstance();
7985     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7986     context->Global()->Set(v8_str("o2"), obj);
7987     v8::Handle<Value> value =
7988         CompileRun("o.__proto__ === o2.__proto__");
7989     CHECK_EQ(v8::True(isolate), value);
7990     context->Global()->Set(v8_str("o"), obj);
7991   }
7992 }
7993
7994
7995 static int StrCmp16(uint16_t* a, uint16_t* b) {
7996   while (true) {
7997     if (*a == 0 && *b == 0) return 0;
7998     if (*a != *b) return 0 + *a - *b;
7999     a++;
8000     b++;
8001   }
8002 }
8003
8004
8005 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
8006   while (true) {
8007     if (n-- == 0) return 0;
8008     if (*a == 0 && *b == 0) return 0;
8009     if (*a != *b) return 0 + *a - *b;
8010     a++;
8011     b++;
8012   }
8013 }
8014
8015
8016 int GetUtf8Length(Handle<String> str) {
8017   int len = str->Utf8Length();
8018   if (len < 0) {
8019     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
8020     i::String::Flatten(istr);
8021     len = str->Utf8Length();
8022   }
8023   return len;
8024 }
8025
8026
8027 THREADED_TEST(StringWrite) {
8028   LocalContext context;
8029   v8::HandleScope scope(context->GetIsolate());
8030   v8::Handle<String> str = v8_str("abcde");
8031   // abc<Icelandic eth><Unicode snowman>.
8032   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
8033   v8::Handle<String> str3 = v8::String::NewFromUtf8(
8034       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
8035   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
8036   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
8037   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
8038       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
8039   // single lead surrogate
8040   uint16_t lead[1] = { 0xd800 };
8041   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
8042       context->GetIsolate(), lead, v8::String::kNormalString, 1);
8043   // single trail surrogate
8044   uint16_t trail[1] = { 0xdc00 };
8045   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
8046       context->GetIsolate(), trail, v8::String::kNormalString, 1);
8047   // surrogate pair
8048   uint16_t pair[2] = { 0xd800,  0xdc00 };
8049   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
8050       context->GetIsolate(), pair, v8::String::kNormalString, 2);
8051   const int kStride = 4;  // Must match stride in for loops in JS below.
8052   CompileRun(
8053       "var left = '';"
8054       "for (var i = 0; i < 0xd800; i += 4) {"
8055       "  left = left + String.fromCharCode(i);"
8056       "}");
8057   CompileRun(
8058       "var right = '';"
8059       "for (var i = 0; i < 0xd800; i += 4) {"
8060       "  right = String.fromCharCode(i) + right;"
8061       "}");
8062   v8::Handle<v8::Object> global = context->Global();
8063   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
8064   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
8065
8066   CHECK_EQ(5, str2->Length());
8067   CHECK_EQ(0xd800 / kStride, left_tree->Length());
8068   CHECK_EQ(0xd800 / kStride, right_tree->Length());
8069
8070   char buf[100];
8071   char utf8buf[0xd800 * 3];
8072   uint16_t wbuf[100];
8073   int len;
8074   int charlen;
8075
8076   memset(utf8buf, 0x1, 1000);
8077   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8078   CHECK_EQ(9, len);
8079   CHECK_EQ(5, charlen);
8080   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8081
8082   memset(utf8buf, 0x1, 1000);
8083   len = str2->WriteUtf8(utf8buf, 8, &charlen);
8084   CHECK_EQ(8, len);
8085   CHECK_EQ(5, charlen);
8086   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
8087
8088   memset(utf8buf, 0x1, 1000);
8089   len = str2->WriteUtf8(utf8buf, 7, &charlen);
8090   CHECK_EQ(5, len);
8091   CHECK_EQ(4, charlen);
8092   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8093
8094   memset(utf8buf, 0x1, 1000);
8095   len = str2->WriteUtf8(utf8buf, 6, &charlen);
8096   CHECK_EQ(5, len);
8097   CHECK_EQ(4, charlen);
8098   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8099
8100   memset(utf8buf, 0x1, 1000);
8101   len = str2->WriteUtf8(utf8buf, 5, &charlen);
8102   CHECK_EQ(5, len);
8103   CHECK_EQ(4, charlen);
8104   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8105
8106   memset(utf8buf, 0x1, 1000);
8107   len = str2->WriteUtf8(utf8buf, 4, &charlen);
8108   CHECK_EQ(3, len);
8109   CHECK_EQ(3, charlen);
8110   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8111
8112   memset(utf8buf, 0x1, 1000);
8113   len = str2->WriteUtf8(utf8buf, 3, &charlen);
8114   CHECK_EQ(3, len);
8115   CHECK_EQ(3, charlen);
8116   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8117
8118   memset(utf8buf, 0x1, 1000);
8119   len = str2->WriteUtf8(utf8buf, 2, &charlen);
8120   CHECK_EQ(2, len);
8121   CHECK_EQ(2, charlen);
8122   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
8123
8124   // allow orphan surrogates by default
8125   memset(utf8buf, 0x1, 1000);
8126   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8127   CHECK_EQ(13, len);
8128   CHECK_EQ(8, charlen);
8129   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
8130
8131   // replace orphan surrogates with unicode replacement character
8132   memset(utf8buf, 0x1, 1000);
8133   len = orphans_str->WriteUtf8(utf8buf,
8134                                sizeof(utf8buf),
8135                                &charlen,
8136                                String::REPLACE_INVALID_UTF8);
8137   CHECK_EQ(13, len);
8138   CHECK_EQ(8, charlen);
8139   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
8140
8141   // replace single lead surrogate with unicode replacement character
8142   memset(utf8buf, 0x1, 1000);
8143   len = lead_str->WriteUtf8(utf8buf,
8144                             sizeof(utf8buf),
8145                             &charlen,
8146                             String::REPLACE_INVALID_UTF8);
8147   CHECK_EQ(4, len);
8148   CHECK_EQ(1, charlen);
8149   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8150
8151   // replace single trail surrogate with unicode replacement character
8152   memset(utf8buf, 0x1, 1000);
8153   len = trail_str->WriteUtf8(utf8buf,
8154                              sizeof(utf8buf),
8155                              &charlen,
8156                              String::REPLACE_INVALID_UTF8);
8157   CHECK_EQ(4, len);
8158   CHECK_EQ(1, charlen);
8159   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8160
8161   // do not replace / write anything if surrogate pair does not fit the buffer
8162   // space
8163   memset(utf8buf, 0x1, 1000);
8164   len = pair_str->WriteUtf8(utf8buf,
8165                              3,
8166                              &charlen,
8167                              String::REPLACE_INVALID_UTF8);
8168   CHECK_EQ(0, len);
8169   CHECK_EQ(0, charlen);
8170
8171   memset(utf8buf, 0x1, sizeof(utf8buf));
8172   len = GetUtf8Length(left_tree);
8173   int utf8_expected =
8174       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
8175   CHECK_EQ(utf8_expected, len);
8176   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8177   CHECK_EQ(utf8_expected, len);
8178   CHECK_EQ(0xd800 / kStride, charlen);
8179   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8180   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8181   CHECK_EQ(0xc0 - kStride,
8182            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8183   CHECK_EQ(1, utf8buf[utf8_expected]);
8184
8185   memset(utf8buf, 0x1, sizeof(utf8buf));
8186   len = GetUtf8Length(right_tree);
8187   CHECK_EQ(utf8_expected, len);
8188   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8189   CHECK_EQ(utf8_expected, len);
8190   CHECK_EQ(0xd800 / kStride, charlen);
8191   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
8192   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
8193   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8194   CHECK_EQ(1, utf8buf[utf8_expected]);
8195
8196   memset(buf, 0x1, sizeof(buf));
8197   memset(wbuf, 0x1, sizeof(wbuf));
8198   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8199   CHECK_EQ(5, len);
8200   len = str->Write(wbuf);
8201   CHECK_EQ(5, len);
8202   CHECK_EQ(0, strcmp("abcde", buf));
8203   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8204   CHECK_EQ(0, StrCmp16(answer1, wbuf));
8205
8206   memset(buf, 0x1, sizeof(buf));
8207   memset(wbuf, 0x1, sizeof(wbuf));
8208   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
8209   CHECK_EQ(4, len);
8210   len = str->Write(wbuf, 0, 4);
8211   CHECK_EQ(4, len);
8212   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
8213   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8214   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8215
8216   memset(buf, 0x1, sizeof(buf));
8217   memset(wbuf, 0x1, sizeof(wbuf));
8218   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
8219   CHECK_EQ(5, len);
8220   len = str->Write(wbuf, 0, 5);
8221   CHECK_EQ(5, len);
8222   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
8223   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8224   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8225
8226   memset(buf, 0x1, sizeof(buf));
8227   memset(wbuf, 0x1, sizeof(wbuf));
8228   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
8229   CHECK_EQ(5, len);
8230   len = str->Write(wbuf, 0, 6);
8231   CHECK_EQ(5, len);
8232   CHECK_EQ(0, strcmp("abcde", buf));
8233   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8234   CHECK_EQ(0, StrCmp16(answer4, wbuf));
8235
8236   memset(buf, 0x1, sizeof(buf));
8237   memset(wbuf, 0x1, sizeof(wbuf));
8238   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
8239   CHECK_EQ(1, len);
8240   len = str->Write(wbuf, 4, -1);
8241   CHECK_EQ(1, len);
8242   CHECK_EQ(0, strcmp("e", buf));
8243   uint16_t answer5[] = {'e', '\0'};
8244   CHECK_EQ(0, StrCmp16(answer5, wbuf));
8245
8246   memset(buf, 0x1, sizeof(buf));
8247   memset(wbuf, 0x1, sizeof(wbuf));
8248   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
8249   CHECK_EQ(1, len);
8250   len = str->Write(wbuf, 4, 6);
8251   CHECK_EQ(1, len);
8252   CHECK_EQ(0, strcmp("e", buf));
8253   CHECK_EQ(0, StrCmp16(answer5, wbuf));
8254
8255   memset(buf, 0x1, sizeof(buf));
8256   memset(wbuf, 0x1, sizeof(wbuf));
8257   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
8258   CHECK_EQ(1, len);
8259   len = str->Write(wbuf, 4, 1);
8260   CHECK_EQ(1, len);
8261   CHECK_EQ(0, strncmp("e\1", buf, 2));
8262   uint16_t answer6[] = {'e', 0x101};
8263   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8264
8265   memset(buf, 0x1, sizeof(buf));
8266   memset(wbuf, 0x1, sizeof(wbuf));
8267   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
8268   CHECK_EQ(1, len);
8269   len = str->Write(wbuf, 3, 1);
8270   CHECK_EQ(1, len);
8271   CHECK_EQ(0, strncmp("d\1", buf, 2));
8272   uint16_t answer7[] = {'d', 0x101};
8273   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8274
8275   memset(wbuf, 0x1, sizeof(wbuf));
8276   wbuf[5] = 'X';
8277   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
8278   CHECK_EQ(5, len);
8279   CHECK_EQ('X', wbuf[5]);
8280   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8281   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8282   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8283   CHECK_NE(0, StrCmp16(answer8b, wbuf));
8284   wbuf[5] = '\0';
8285   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8286
8287   memset(buf, 0x1, sizeof(buf));
8288   buf[5] = 'X';
8289   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8290                           0,
8291                           6,
8292                           String::NO_NULL_TERMINATION);
8293   CHECK_EQ(5, len);
8294   CHECK_EQ('X', buf[5]);
8295   CHECK_EQ(0, strncmp("abcde", buf, 5));
8296   CHECK_NE(0, strcmp("abcde", buf));
8297   buf[5] = '\0';
8298   CHECK_EQ(0, strcmp("abcde", buf));
8299
8300   memset(utf8buf, 0x1, sizeof(utf8buf));
8301   utf8buf[8] = 'X';
8302   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8303                         String::NO_NULL_TERMINATION);
8304   CHECK_EQ(8, len);
8305   CHECK_EQ('X', utf8buf[8]);
8306   CHECK_EQ(5, charlen);
8307   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
8308   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8309   utf8buf[8] = '\0';
8310   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8311
8312   memset(utf8buf, 0x1, sizeof(utf8buf));
8313   utf8buf[5] = 'X';
8314   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8315                         String::NO_NULL_TERMINATION);
8316   CHECK_EQ(5, len);
8317   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
8318   CHECK_EQ(5, charlen);
8319   utf8buf[5] = '\0';
8320   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8321
8322   memset(buf, 0x1, sizeof(buf));
8323   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8324   CHECK_EQ(7, len);
8325   CHECK_EQ(0, strcmp("abc", buf));
8326   CHECK_EQ(0, buf[3]);
8327   CHECK_EQ(0, strcmp("def", buf + 4));
8328
8329   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
8330   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
8331   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
8332 }
8333
8334
8335 static void Utf16Helper(
8336     LocalContext& context,  // NOLINT
8337     const char* name,
8338     const char* lengths_name,
8339     int len) {
8340   Local<v8::Array> a =
8341       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8342   Local<v8::Array> alens =
8343       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8344   for (int i = 0; i < len; i++) {
8345     Local<v8::String> string =
8346       Local<v8::String>::Cast(a->Get(i));
8347     Local<v8::Number> expected_len =
8348       Local<v8::Number>::Cast(alens->Get(i));
8349     int length = GetUtf8Length(string);
8350     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8351   }
8352 }
8353
8354
8355 static uint16_t StringGet(Handle<String> str, int index) {
8356   i::Handle<i::String> istring =
8357       v8::Utils::OpenHandle(String::Cast(*str));
8358   return istring->Get(index);
8359 }
8360
8361
8362 static void WriteUtf8Helper(
8363     LocalContext& context,  // NOLINT
8364     const char* name,
8365     const char* lengths_name,
8366     int len) {
8367   Local<v8::Array> b =
8368       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8369   Local<v8::Array> alens =
8370       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8371   char buffer[1000];
8372   char buffer2[1000];
8373   for (int i = 0; i < len; i++) {
8374     Local<v8::String> string =
8375       Local<v8::String>::Cast(b->Get(i));
8376     Local<v8::Number> expected_len =
8377       Local<v8::Number>::Cast(alens->Get(i));
8378     int utf8_length = static_cast<int>(expected_len->Value());
8379     for (int j = utf8_length + 1; j >= 0; j--) {
8380       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
8381       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
8382       int nchars;
8383       int utf8_written =
8384           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
8385       int utf8_written2 =
8386           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
8387       CHECK_GE(utf8_length + 1, utf8_written);
8388       CHECK_GE(utf8_length, utf8_written2);
8389       for (int k = 0; k < utf8_written2; k++) {
8390         CHECK_EQ(buffer[k], buffer2[k]);
8391       }
8392       CHECK(nchars * 3 >= utf8_written - 1);
8393       CHECK(nchars <= utf8_written);
8394       if (j == utf8_length + 1) {
8395         CHECK_EQ(utf8_written2, utf8_length);
8396         CHECK_EQ(utf8_written2 + 1, utf8_written);
8397       }
8398       CHECK_EQ(buffer[utf8_written], 42);
8399       if (j > utf8_length) {
8400         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
8401         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8402         Handle<String> roundtrip = v8_str(buffer);
8403         CHECK(roundtrip->Equals(string));
8404       } else {
8405         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8406       }
8407       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8408       if (nchars >= 2) {
8409         uint16_t trail = StringGet(string, nchars - 1);
8410         uint16_t lead = StringGet(string, nchars - 2);
8411         if (((lead & 0xfc00) == 0xd800) &&
8412             ((trail & 0xfc00) == 0xdc00)) {
8413           unsigned char u1 = buffer2[utf8_written2 - 4];
8414           unsigned char u2 = buffer2[utf8_written2 - 3];
8415           unsigned char u3 = buffer2[utf8_written2 - 2];
8416           unsigned char u4 = buffer2[utf8_written2 - 1];
8417           CHECK_EQ((u1 & 0xf8), 0xf0);
8418           CHECK_EQ((u2 & 0xc0), 0x80);
8419           CHECK_EQ((u3 & 0xc0), 0x80);
8420           CHECK_EQ((u4 & 0xc0), 0x80);
8421           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8422           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8423           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8424           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8425           CHECK_EQ((u1 & 0x3), c >> 18);
8426         }
8427       }
8428     }
8429   }
8430 }
8431
8432
8433 THREADED_TEST(Utf16) {
8434   LocalContext context;
8435   v8::HandleScope scope(context->GetIsolate());
8436   CompileRun(
8437       "var pad = '01234567890123456789';"
8438       "var p = [];"
8439       "var plens = [20, 3, 3];"
8440       "p.push('01234567890123456789');"
8441       "var lead = 0xd800;"
8442       "var trail = 0xdc00;"
8443       "p.push(String.fromCharCode(0xd800));"
8444       "p.push(String.fromCharCode(0xdc00));"
8445       "var a = [];"
8446       "var b = [];"
8447       "var c = [];"
8448       "var alens = [];"
8449       "for (var i = 0; i < 3; i++) {"
8450       "  p[1] = String.fromCharCode(lead++);"
8451       "  for (var j = 0; j < 3; j++) {"
8452       "    p[2] = String.fromCharCode(trail++);"
8453       "    a.push(p[i] + p[j]);"
8454       "    b.push(p[i] + p[j]);"
8455       "    c.push(p[i] + p[j]);"
8456       "    alens.push(plens[i] + plens[j]);"
8457       "  }"
8458       "}"
8459       "alens[5] -= 2;"  // Here the surrogate pairs match up.
8460       "var a2 = [];"
8461       "var b2 = [];"
8462       "var c2 = [];"
8463       "var a2lens = [];"
8464       "for (var m = 0; m < 9; m++) {"
8465       "  for (var n = 0; n < 9; n++) {"
8466       "    a2.push(a[m] + a[n]);"
8467       "    b2.push(b[m] + b[n]);"
8468       "    var newc = 'x' + c[m] + c[n] + 'y';"
8469       "    c2.push(newc.substring(1, newc.length - 1));"
8470       "    var utf = alens[m] + alens[n];"  // And here.
8471            // The 'n's that start with 0xdc.. are 6-8
8472            // The 'm's that end with 0xd8.. are 1, 4 and 7
8473       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
8474       "    a2lens.push(utf);"
8475       "  }"
8476       "}");
8477   Utf16Helper(context, "a", "alens", 9);
8478   Utf16Helper(context, "a2", "a2lens", 81);
8479   WriteUtf8Helper(context, "b", "alens", 9);
8480   WriteUtf8Helper(context, "b2", "a2lens", 81);
8481   WriteUtf8Helper(context, "c2", "a2lens", 81);
8482 }
8483
8484
8485 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8486   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8487   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8488   return *is1 == *is2;
8489 }
8490
8491 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8492                              const char* b) {
8493   Handle<String> symbol1 =
8494       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8495   Handle<String> symbol2 =
8496       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8497   CHECK(SameSymbol(symbol1, symbol2));
8498 }
8499
8500
8501 THREADED_TEST(Utf16Symbol) {
8502   LocalContext context;
8503   v8::HandleScope scope(context->GetIsolate());
8504
8505   Handle<String> symbol1 = v8::String::NewFromUtf8(
8506       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8507   Handle<String> symbol2 = v8::String::NewFromUtf8(
8508       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8509   CHECK(SameSymbol(symbol1, symbol2));
8510
8511   SameSymbolHelper(context->GetIsolate(),
8512                    "\360\220\220\205",  // 4 byte encoding.
8513                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
8514   SameSymbolHelper(context->GetIsolate(),
8515                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
8516                    "\360\220\220\206");  // 4 byte encoding.
8517   SameSymbolHelper(context->GetIsolate(),
8518                    "x\360\220\220\205",  // 4 byte encoding.
8519                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
8520   SameSymbolHelper(context->GetIsolate(),
8521                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
8522                    "x\360\220\220\206");  // 4 byte encoding.
8523   CompileRun(
8524       "var sym0 = 'benedictus';"
8525       "var sym0b = 'S\303\270ren';"
8526       "var sym1 = '\355\240\201\355\260\207';"
8527       "var sym2 = '\360\220\220\210';"
8528       "var sym3 = 'x\355\240\201\355\260\207';"
8529       "var sym4 = 'x\360\220\220\210';"
8530       "if (sym1.length != 2) throw sym1;"
8531       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8532       "if (sym2.length != 2) throw sym2;"
8533       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8534       "if (sym3.length != 3) throw sym3;"
8535       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8536       "if (sym4.length != 3) throw sym4;"
8537       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8538   Handle<String> sym0 = v8::String::NewFromUtf8(
8539       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8540   Handle<String> sym0b = v8::String::NewFromUtf8(
8541       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8542   Handle<String> sym1 =
8543       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8544                               v8::String::kInternalizedString);
8545   Handle<String> sym2 =
8546       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8547                               v8::String::kInternalizedString);
8548   Handle<String> sym3 = v8::String::NewFromUtf8(
8549       context->GetIsolate(), "x\355\240\201\355\260\207",
8550       v8::String::kInternalizedString);
8551   Handle<String> sym4 =
8552       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8553                               v8::String::kInternalizedString);
8554   v8::Local<v8::Object> global = context->Global();
8555   Local<Value> s0 = global->Get(v8_str("sym0"));
8556   Local<Value> s0b = global->Get(v8_str("sym0b"));
8557   Local<Value> s1 = global->Get(v8_str("sym1"));
8558   Local<Value> s2 = global->Get(v8_str("sym2"));
8559   Local<Value> s3 = global->Get(v8_str("sym3"));
8560   Local<Value> s4 = global->Get(v8_str("sym4"));
8561   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8562   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8563   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8564   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8565   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8566   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8567 }
8568
8569
8570 THREADED_TEST(ToArrayIndex) {
8571   LocalContext context;
8572   v8::Isolate* isolate = context->GetIsolate();
8573   v8::HandleScope scope(isolate);
8574
8575   v8::Handle<String> str = v8_str("42");
8576   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8577   CHECK(!index.IsEmpty());
8578   CHECK_EQ(42.0, index->Uint32Value());
8579   str = v8_str("42asdf");
8580   index = str->ToArrayIndex();
8581   CHECK(index.IsEmpty());
8582   str = v8_str("-42");
8583   index = str->ToArrayIndex();
8584   CHECK(index.IsEmpty());
8585   str = v8_str("4294967295");
8586   index = str->ToArrayIndex();
8587   CHECK(!index.IsEmpty());
8588   CHECK_EQ(4294967295.0, index->Uint32Value());
8589   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8590   index = num->ToArrayIndex();
8591   CHECK(!index.IsEmpty());
8592   CHECK_EQ(1.0, index->Uint32Value());
8593   num = v8::Number::New(isolate, -1);
8594   index = num->ToArrayIndex();
8595   CHECK(index.IsEmpty());
8596   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8597   index = obj->ToArrayIndex();
8598   CHECK(index.IsEmpty());
8599 }
8600
8601
8602 THREADED_TEST(ErrorConstruction) {
8603   LocalContext context;
8604   v8::HandleScope scope(context->GetIsolate());
8605
8606   v8::Handle<String> foo = v8_str("foo");
8607   v8::Handle<String> message = v8_str("message");
8608   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8609   CHECK(range_error->IsObject());
8610   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8611   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8612   CHECK(reference_error->IsObject());
8613   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8614   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8615   CHECK(syntax_error->IsObject());
8616   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8617   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8618   CHECK(type_error->IsObject());
8619   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8620   v8::Handle<Value> error = v8::Exception::Error(foo);
8621   CHECK(error->IsObject());
8622   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8623 }
8624
8625
8626 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
8627   ApiTestFuzzer::Fuzz();
8628   v8::Handle<String> foo = v8_str("foo");
8629   v8::Handle<String> message = v8_str("message");
8630   v8::Handle<Value> error = v8::Exception::Error(foo);
8631   CHECK(error->IsObject());
8632   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8633   info.GetIsolate()->ThrowException(error);
8634   info.GetReturnValue().SetUndefined();
8635 }
8636
8637
8638 THREADED_TEST(ExceptionGetMessage) {
8639   LocalContext context;
8640   v8::HandleScope scope(context->GetIsolate());
8641   v8::Handle<String> foo_str = v8_str("foo");
8642   v8::Handle<String> message_str = v8_str("message");
8643
8644   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
8645
8646   Local<v8::FunctionTemplate> fun =
8647       v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
8648   v8::Local<v8::Object> global = context->Global();
8649   global->Set(v8_str("throwV8Exception"), fun->GetFunction());
8650
8651   TryCatch try_catch;
8652   CompileRun(
8653       "function f1() {\n"
8654       "  throwV8Exception();\n"
8655       "};\n"
8656       "f1();");
8657   CHECK(try_catch.HasCaught());
8658
8659   v8::Handle<v8::Value> error = try_catch.Exception();
8660   CHECK(error->IsObject());
8661   CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
8662
8663   v8::Handle<v8::Message> message = v8::Exception::GetMessage(error);
8664   CHECK(!message.IsEmpty());
8665   CHECK_EQ(2, message->GetLineNumber());
8666   CHECK_EQ(2, message->GetStartColumn());
8667
8668   v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
8669   CHECK(!stackTrace.IsEmpty());
8670   CHECK_EQ(2, stackTrace->GetFrameCount());
8671
8672   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
8673
8674   // Now check message location when SetCaptureStackTraceForUncaughtExceptions
8675   // is false.
8676   try_catch.Reset();
8677
8678   CompileRun(
8679       "function f2() {\n"
8680       "  return throwV8Exception();\n"
8681       "};\n"
8682       "f2();");
8683   CHECK(try_catch.HasCaught());
8684
8685   error = try_catch.Exception();
8686   CHECK(error->IsObject());
8687   CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
8688
8689   message = v8::Exception::GetMessage(error);
8690   CHECK(!message.IsEmpty());
8691   CHECK_EQ(2, message->GetLineNumber());
8692   CHECK_EQ(9, message->GetStartColumn());
8693
8694   // Should be empty stack trace.
8695   stackTrace = message->GetStackTrace();
8696   CHECK(stackTrace.IsEmpty());
8697 }
8698
8699
8700 static void YGetter(Local<String> name,
8701                     const v8::PropertyCallbackInfo<v8::Value>& info) {
8702   ApiTestFuzzer::Fuzz();
8703   info.GetReturnValue().Set(v8_num(10));
8704 }
8705
8706
8707 static void YSetter(Local<String> name,
8708                     Local<Value> value,
8709                     const v8::PropertyCallbackInfo<void>& info) {
8710   Local<Object> this_obj = Local<Object>::Cast(info.This());
8711   if (this_obj->Has(name)) this_obj->Delete(name);
8712   this_obj->Set(name, value);
8713 }
8714
8715
8716 THREADED_TEST(DeleteAccessor) {
8717   v8::Isolate* isolate = CcTest::isolate();
8718   v8::HandleScope scope(isolate);
8719   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8720   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8721   LocalContext context;
8722   v8::Handle<v8::Object> holder = obj->NewInstance();
8723   context->Global()->Set(v8_str("holder"), holder);
8724   v8::Handle<Value> result = CompileRun(
8725       "holder.y = 11; holder.y = 12; holder.y");
8726   CHECK_EQ(12, result->Uint32Value());
8727 }
8728
8729
8730 THREADED_TEST(TypeSwitch) {
8731   v8::Isolate* isolate = CcTest::isolate();
8732   v8::HandleScope scope(isolate);
8733   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8734   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8735   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8736   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8737   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8738   LocalContext context;
8739   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8740   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8741   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8742   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8743   for (int i = 0; i < 10; i++) {
8744     CHECK_EQ(0, type_switch->match(obj0));
8745     CHECK_EQ(1, type_switch->match(obj1));
8746     CHECK_EQ(2, type_switch->match(obj2));
8747     CHECK_EQ(3, type_switch->match(obj3));
8748     CHECK_EQ(3, type_switch->match(obj3));
8749     CHECK_EQ(2, type_switch->match(obj2));
8750     CHECK_EQ(1, type_switch->match(obj1));
8751     CHECK_EQ(0, type_switch->match(obj0));
8752   }
8753 }
8754
8755
8756 static int trouble_nesting = 0;
8757 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8758   ApiTestFuzzer::Fuzz();
8759   trouble_nesting++;
8760
8761   // Call a JS function that throws an uncaught exception.
8762   Local<v8::Object> arg_this =
8763       args.GetIsolate()->GetCurrentContext()->Global();
8764   Local<Value> trouble_callee = (trouble_nesting == 3) ?
8765     arg_this->Get(v8_str("trouble_callee")) :
8766     arg_this->Get(v8_str("trouble_caller"));
8767   CHECK(trouble_callee->IsFunction());
8768   args.GetReturnValue().Set(
8769       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8770 }
8771
8772
8773 static int report_count = 0;
8774 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8775                                              v8::Handle<Value>) {
8776   report_count++;
8777 }
8778
8779
8780 // Counts uncaught exceptions, but other tests running in parallel
8781 // also have uncaught exceptions.
8782 TEST(ApiUncaughtException) {
8783   report_count = 0;
8784   LocalContext env;
8785   v8::Isolate* isolate = env->GetIsolate();
8786   v8::HandleScope scope(isolate);
8787   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8788
8789   Local<v8::FunctionTemplate> fun =
8790       v8::FunctionTemplate::New(isolate, TroubleCallback);
8791   v8::Local<v8::Object> global = env->Global();
8792   global->Set(v8_str("trouble"), fun->GetFunction());
8793
8794   CompileRun(
8795       "function trouble_callee() {"
8796       "  var x = null;"
8797       "  return x.foo;"
8798       "};"
8799       "function trouble_caller() {"
8800       "  trouble();"
8801       "};");
8802   Local<Value> trouble = global->Get(v8_str("trouble"));
8803   CHECK(trouble->IsFunction());
8804   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8805   CHECK(trouble_callee->IsFunction());
8806   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8807   CHECK(trouble_caller->IsFunction());
8808   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8809   CHECK_EQ(1, report_count);
8810   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8811 }
8812
8813 static const char* script_resource_name = "ExceptionInNativeScript.js";
8814 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8815                                                 v8::Handle<Value>) {
8816   v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
8817   CHECK(!name_val.IsEmpty() && name_val->IsString());
8818   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
8819   CHECK_EQ(script_resource_name, *name);
8820   CHECK_EQ(3, message->GetLineNumber());
8821   v8::String::Utf8Value source_line(message->GetSourceLine());
8822   CHECK_EQ("  new o.foo();", *source_line);
8823 }
8824
8825
8826 TEST(ExceptionInNativeScript) {
8827   LocalContext env;
8828   v8::Isolate* isolate = env->GetIsolate();
8829   v8::HandleScope scope(isolate);
8830   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8831
8832   Local<v8::FunctionTemplate> fun =
8833       v8::FunctionTemplate::New(isolate, TroubleCallback);
8834   v8::Local<v8::Object> global = env->Global();
8835   global->Set(v8_str("trouble"), fun->GetFunction());
8836
8837   CompileRunWithOrigin(
8838       "function trouble() {\n"
8839       "  var o = {};\n"
8840       "  new o.foo();\n"
8841       "};",
8842       script_resource_name);
8843   Local<Value> trouble = global->Get(v8_str("trouble"));
8844   CHECK(trouble->IsFunction());
8845   Function::Cast(*trouble)->Call(global, 0, NULL);
8846   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8847 }
8848
8849
8850 TEST(CompilationErrorUsingTryCatchHandler) {
8851   LocalContext env;
8852   v8::HandleScope scope(env->GetIsolate());
8853   v8::TryCatch try_catch;
8854   v8_compile("This doesn't &*&@#$&*^ compile.");
8855   CHECK_NE(NULL, *try_catch.Exception());
8856   CHECK(try_catch.HasCaught());
8857 }
8858
8859
8860 TEST(TryCatchFinallyUsingTryCatchHandler) {
8861   LocalContext env;
8862   v8::HandleScope scope(env->GetIsolate());
8863   v8::TryCatch try_catch;
8864   CompileRun("try { throw ''; } catch (e) {}");
8865   CHECK(!try_catch.HasCaught());
8866   CompileRun("try { throw ''; } finally {}");
8867   CHECK(try_catch.HasCaught());
8868   try_catch.Reset();
8869   CompileRun(
8870       "(function() {"
8871       "try { throw ''; } finally { return; }"
8872       "})()");
8873   CHECK(!try_catch.HasCaught());
8874   CompileRun(
8875       "(function()"
8876       "  { try { throw ''; } finally { throw 0; }"
8877       "})()");
8878   CHECK(try_catch.HasCaught());
8879 }
8880
8881
8882 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
8883   v8::HandleScope scope(args.GetIsolate());
8884   CompileRun(args[0]->ToString());
8885 }
8886
8887
8888 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
8889   v8::Isolate* isolate = CcTest::isolate();
8890   v8::HandleScope scope(isolate);
8891   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
8892   templ->Set(v8_str("CEvaluate"),
8893              v8::FunctionTemplate::New(isolate, CEvaluate));
8894   LocalContext context(0, templ);
8895   v8::TryCatch try_catch;
8896   CompileRun("try {"
8897              "  CEvaluate('throw 1;');"
8898              "} finally {"
8899              "}");
8900   CHECK(try_catch.HasCaught());
8901   CHECK(!try_catch.Message().IsEmpty());
8902   String::Utf8Value exception_value(try_catch.Exception());
8903   CHECK_EQ(*exception_value, "1");
8904   try_catch.Reset();
8905   CompileRun("try {"
8906              "  CEvaluate('throw 1;');"
8907              "} finally {"
8908              "  throw 2;"
8909              "}");
8910   CHECK(try_catch.HasCaught());
8911   CHECK(!try_catch.Message().IsEmpty());
8912   String::Utf8Value finally_exception_value(try_catch.Exception());
8913   CHECK_EQ(*finally_exception_value, "2");
8914 }
8915
8916
8917 // For use within the TestSecurityHandler() test.
8918 static bool g_security_callback_result = false;
8919 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8920                                       Local<Value> name,
8921                                       v8::AccessType type,
8922                                       Local<Value> data) {
8923   printf("a\n");
8924   // Always allow read access.
8925   if (type == v8::ACCESS_GET)
8926     return true;
8927
8928   // Sometimes allow other access.
8929   return g_security_callback_result;
8930 }
8931
8932
8933 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8934                                         uint32_t key,
8935                                         v8::AccessType type,
8936                                         Local<Value> data) {
8937   printf("b\n");
8938   // Always allow read access.
8939   if (type == v8::ACCESS_GET)
8940     return true;
8941
8942   // Sometimes allow other access.
8943   return g_security_callback_result;
8944 }
8945
8946
8947 // SecurityHandler can't be run twice
8948 TEST(SecurityHandler) {
8949   v8::Isolate* isolate = CcTest::isolate();
8950   v8::HandleScope scope0(isolate);
8951   v8::Handle<v8::ObjectTemplate> global_template =
8952       v8::ObjectTemplate::New(isolate);
8953   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8954                                            IndexedSecurityTestCallback);
8955   // Create an environment
8956   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8957   context0->Enter();
8958
8959   v8::Handle<v8::Object> global0 = context0->Global();
8960   v8::Handle<Script> script0 = v8_compile("foo = 111");
8961   script0->Run();
8962   global0->Set(v8_str("0"), v8_num(999));
8963   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8964   CHECK_EQ(111, foo0->Int32Value());
8965   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8966   CHECK_EQ(999, z0->Int32Value());
8967
8968   // Create another environment, should fail security checks.
8969   v8::HandleScope scope1(isolate);
8970
8971   v8::Handle<Context> context1 =
8972     Context::New(isolate, NULL, global_template);
8973   context1->Enter();
8974
8975   v8::Handle<v8::Object> global1 = context1->Global();
8976   global1->Set(v8_str("othercontext"), global0);
8977   // This set will fail the security check.
8978   v8::Handle<Script> script1 =
8979     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8980   script1->Run();
8981   // This read will pass the security check.
8982   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8983   CHECK_EQ(111, foo1->Int32Value());
8984   // This read will pass the security check.
8985   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8986   CHECK_EQ(999, z1->Int32Value());
8987
8988   // Create another environment, should pass security checks.
8989   { g_security_callback_result = true;  // allow security handler to pass.
8990     v8::HandleScope scope2(isolate);
8991     LocalContext context2;
8992     v8::Handle<v8::Object> global2 = context2->Global();
8993     global2->Set(v8_str("othercontext"), global0);
8994     v8::Handle<Script> script2 =
8995         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8996     script2->Run();
8997     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8998     CHECK_EQ(333, foo2->Int32Value());
8999     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
9000     CHECK_EQ(888, z2->Int32Value());
9001   }
9002
9003   context1->Exit();
9004   context0->Exit();
9005 }
9006
9007
9008 THREADED_TEST(SecurityChecks) {
9009   LocalContext env1;
9010   v8::HandleScope handle_scope(env1->GetIsolate());
9011   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9012
9013   Local<Value> foo = v8_str("foo");
9014   Local<Value> bar = v8_str("bar");
9015
9016   // Set to the same domain.
9017   env1->SetSecurityToken(foo);
9018
9019   // Create a function in env1.
9020   CompileRun("spy=function(){return spy;}");
9021   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
9022   CHECK(spy->IsFunction());
9023
9024   // Create another function accessing global objects.
9025   CompileRun("spy2=function(){return new this.Array();}");
9026   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
9027   CHECK(spy2->IsFunction());
9028
9029   // Switch to env2 in the same domain and invoke spy on env2.
9030   {
9031     env2->SetSecurityToken(foo);
9032     // Enter env2
9033     Context::Scope scope_env2(env2);
9034     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
9035     CHECK(result->IsFunction());
9036   }
9037
9038   {
9039     env2->SetSecurityToken(bar);
9040     Context::Scope scope_env2(env2);
9041
9042     // Call cross_domain_call, it should throw an exception
9043     v8::TryCatch try_catch;
9044     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
9045     CHECK(try_catch.HasCaught());
9046   }
9047 }
9048
9049
9050 // Regression test case for issue 1183439.
9051 THREADED_TEST(SecurityChecksForPrototypeChain) {
9052   LocalContext current;
9053   v8::HandleScope scope(current->GetIsolate());
9054   v8::Handle<Context> other = Context::New(current->GetIsolate());
9055
9056   // Change context to be able to get to the Object function in the
9057   // other context without hitting the security checks.
9058   v8::Local<Value> other_object;
9059   { Context::Scope scope(other);
9060     other_object = other->Global()->Get(v8_str("Object"));
9061     other->Global()->Set(v8_num(42), v8_num(87));
9062   }
9063
9064   current->Global()->Set(v8_str("other"), other->Global());
9065   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
9066
9067   // Make sure the security check fails here and we get an undefined
9068   // result instead of getting the Object function. Repeat in a loop
9069   // to make sure to exercise the IC code.
9070   v8::Local<Script> access_other0 = v8_compile("other.Object");
9071   v8::Local<Script> access_other1 = v8_compile("other[42]");
9072   for (int i = 0; i < 5; i++) {
9073     CHECK(access_other0->Run().IsEmpty());
9074     CHECK(access_other1->Run().IsEmpty());
9075   }
9076
9077   // Create an object that has 'other' in its prototype chain and make
9078   // sure we cannot access the Object function indirectly through
9079   // that. Repeat in a loop to make sure to exercise the IC code.
9080   v8_compile("function F() { };"
9081              "F.prototype = other;"
9082              "var f = new F();")->Run();
9083   v8::Local<Script> access_f0 = v8_compile("f.Object");
9084   v8::Local<Script> access_f1 = v8_compile("f[42]");
9085   for (int j = 0; j < 5; j++) {
9086     CHECK(access_f0->Run().IsEmpty());
9087     CHECK(access_f1->Run().IsEmpty());
9088   }
9089
9090   // Now it gets hairy: Set the prototype for the other global object
9091   // to be the current global object. The prototype chain for 'f' now
9092   // goes through 'other' but ends up in the current global object.
9093   { Context::Scope scope(other);
9094     other->Global()->Set(v8_str("__proto__"), current->Global());
9095   }
9096   // Set a named and an index property on the current global
9097   // object. To force the lookup to go through the other global object,
9098   // the properties must not exist in the other global object.
9099   current->Global()->Set(v8_str("foo"), v8_num(100));
9100   current->Global()->Set(v8_num(99), v8_num(101));
9101   // Try to read the properties from f and make sure that the access
9102   // gets stopped by the security checks on the other global object.
9103   Local<Script> access_f2 = v8_compile("f.foo");
9104   Local<Script> access_f3 = v8_compile("f[99]");
9105   for (int k = 0; k < 5; k++) {
9106     CHECK(access_f2->Run().IsEmpty());
9107     CHECK(access_f3->Run().IsEmpty());
9108   }
9109 }
9110
9111
9112 static bool named_security_check_with_gc_called;
9113
9114 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
9115                                         Local<Value> name,
9116                                         v8::AccessType type,
9117                                         Local<Value> data) {
9118   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
9119   named_security_check_with_gc_called = true;
9120   return true;
9121 }
9122
9123
9124 static bool indexed_security_check_with_gc_called;
9125
9126 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
9127                                               uint32_t key,
9128                                               v8::AccessType type,
9129                                               Local<Value> data) {
9130   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
9131   indexed_security_check_with_gc_called = true;
9132   return true;
9133 }
9134
9135
9136 TEST(SecurityTestGCAllowed) {
9137   v8::Isolate* isolate = CcTest::isolate();
9138   v8::HandleScope handle_scope(isolate);
9139   v8::Handle<v8::ObjectTemplate> object_template =
9140       v8::ObjectTemplate::New(isolate);
9141   object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
9142                                            IndexedSecurityTestCallbackWithGC);
9143
9144   v8::Handle<Context> context = Context::New(isolate);
9145   v8::Context::Scope context_scope(context);
9146
9147   context->Global()->Set(v8_str("obj"), object_template->NewInstance());
9148
9149   named_security_check_with_gc_called = false;
9150   CompileRun("obj.foo = new String(1001);");
9151   CHECK(named_security_check_with_gc_called);
9152
9153   indexed_security_check_with_gc_called = false;
9154   CompileRun("obj[0] = new String(1002);");
9155   CHECK(indexed_security_check_with_gc_called);
9156
9157   named_security_check_with_gc_called = false;
9158   CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
9159   CHECK(named_security_check_with_gc_called);
9160
9161   indexed_security_check_with_gc_called = false;
9162   CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
9163   CHECK(indexed_security_check_with_gc_called);
9164 }
9165
9166
9167 THREADED_TEST(CrossDomainDelete) {
9168   LocalContext env1;
9169   v8::HandleScope handle_scope(env1->GetIsolate());
9170   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9171
9172   Local<Value> foo = v8_str("foo");
9173   Local<Value> bar = v8_str("bar");
9174
9175   // Set to the same domain.
9176   env1->SetSecurityToken(foo);
9177   env2->SetSecurityToken(foo);
9178
9179   env1->Global()->Set(v8_str("prop"), v8_num(3));
9180   env2->Global()->Set(v8_str("env1"), env1->Global());
9181
9182   // Change env2 to a different domain and delete env1.prop.
9183   env2->SetSecurityToken(bar);
9184   {
9185     Context::Scope scope_env2(env2);
9186     Local<Value> result =
9187         CompileRun("delete env1.prop");
9188     CHECK(result.IsEmpty());
9189   }
9190
9191   // Check that env1.prop still exists.
9192   Local<Value> v = env1->Global()->Get(v8_str("prop"));
9193   CHECK(v->IsNumber());
9194   CHECK_EQ(3, v->Int32Value());
9195 }
9196
9197
9198 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
9199   LocalContext env1;
9200   v8::HandleScope handle_scope(env1->GetIsolate());
9201   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9202
9203   Local<Value> foo = v8_str("foo");
9204   Local<Value> bar = v8_str("bar");
9205
9206   // Set to the same domain.
9207   env1->SetSecurityToken(foo);
9208   env2->SetSecurityToken(foo);
9209
9210   env1->Global()->Set(v8_str("prop"), v8_num(3));
9211   env2->Global()->Set(v8_str("env1"), env1->Global());
9212
9213   // env1.prop is enumerable in env2.
9214   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9215   {
9216     Context::Scope scope_env2(env2);
9217     Local<Value> result = CompileRun(test);
9218     CHECK(result->IsTrue());
9219   }
9220
9221   // Change env2 to a different domain and test again.
9222   env2->SetSecurityToken(bar);
9223   {
9224     Context::Scope scope_env2(env2);
9225     Local<Value> result = CompileRun(test);
9226     CHECK(result.IsEmpty());
9227   }
9228 }
9229
9230
9231 THREADED_TEST(CrossDomainForIn) {
9232   LocalContext env1;
9233   v8::HandleScope handle_scope(env1->GetIsolate());
9234   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9235
9236   Local<Value> foo = v8_str("foo");
9237   Local<Value> bar = v8_str("bar");
9238
9239   // Set to the same domain.
9240   env1->SetSecurityToken(foo);
9241   env2->SetSecurityToken(foo);
9242
9243   env1->Global()->Set(v8_str("prop"), v8_num(3));
9244   env2->Global()->Set(v8_str("env1"), env1->Global());
9245
9246   // Change env2 to a different domain and set env1's global object
9247   // as the __proto__ of an object in env2 and enumerate properties
9248   // in for-in. It shouldn't enumerate properties on env1's global
9249   // object.
9250   env2->SetSecurityToken(bar);
9251   {
9252     Context::Scope scope_env2(env2);
9253     Local<Value> result = CompileRun(
9254         "(function() {"
9255         "  var obj = { '__proto__': env1 };"
9256         "  try {"
9257         "    for (var p in obj) {"
9258         "      if (p == 'prop') return false;"
9259         "    }"
9260         "    return false;"
9261         "  } catch (e) {"
9262         "    return true;"
9263         "  }"
9264         "})()");
9265     CHECK(result->IsTrue());
9266   }
9267 }
9268
9269
9270 TEST(ContextDetachGlobal) {
9271   LocalContext env1;
9272   v8::HandleScope handle_scope(env1->GetIsolate());
9273   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9274
9275   Local<v8::Object> global1 = env1->Global();
9276
9277   Local<Value> foo = v8_str("foo");
9278
9279   // Set to the same domain.
9280   env1->SetSecurityToken(foo);
9281   env2->SetSecurityToken(foo);
9282
9283   // Enter env2
9284   env2->Enter();
9285
9286   // Create a function in env2 and add a reference to it in env1.
9287   Local<v8::Object> global2 = env2->Global();
9288   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
9289   CompileRun("function getProp() {return prop;}");
9290
9291   env1->Global()->Set(v8_str("getProp"),
9292                       global2->Get(v8_str("getProp")));
9293
9294   // Detach env2's global, and reuse the global object of env2
9295   env2->Exit();
9296   env2->DetachGlobal();
9297
9298   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9299                                           0,
9300                                           v8::Handle<v8::ObjectTemplate>(),
9301                                           global2);
9302   env3->SetSecurityToken(v8_str("bar"));
9303   env3->Enter();
9304
9305   Local<v8::Object> global3 = env3->Global();
9306   CHECK_EQ(global2, global3);
9307   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
9308   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
9309   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
9310   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
9311   env3->Exit();
9312
9313   // Call getProp in env1, and it should return the value 1
9314   {
9315     Local<Value> get_prop = global1->Get(v8_str("getProp"));
9316     CHECK(get_prop->IsFunction());
9317     v8::TryCatch try_catch;
9318     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
9319     CHECK(!try_catch.HasCaught());
9320     CHECK_EQ(1, r->Int32Value());
9321   }
9322
9323   // Check that env3 is not accessible from env1
9324   {
9325     Local<Value> r = global3->Get(v8_str("prop2"));
9326     CHECK(r.IsEmpty());
9327   }
9328 }
9329
9330
9331 TEST(DetachGlobal) {
9332   LocalContext env1;
9333   v8::HandleScope scope(env1->GetIsolate());
9334
9335   // Create second environment.
9336   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9337
9338   Local<Value> foo = v8_str("foo");
9339
9340   // Set same security token for env1 and env2.
9341   env1->SetSecurityToken(foo);
9342   env2->SetSecurityToken(foo);
9343
9344   // Create a property on the global object in env2.
9345   {
9346     v8::Context::Scope scope(env2);
9347     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
9348   }
9349
9350   // Create a reference to env2 global from env1 global.
9351   env1->Global()->Set(v8_str("other"), env2->Global());
9352
9353   // Check that we have access to other.p in env2 from env1.
9354   Local<Value> result = CompileRun("other.p");
9355   CHECK(result->IsInt32());
9356   CHECK_EQ(42, result->Int32Value());
9357
9358   // Hold on to global from env2 and detach global from env2.
9359   Local<v8::Object> global2 = env2->Global();
9360   env2->DetachGlobal();
9361
9362   // Check that the global has been detached. No other.p property can
9363   // be found.
9364   result = CompileRun("other.p");
9365   CHECK(result.IsEmpty());
9366
9367   // Reuse global2 for env3.
9368   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9369                                           0,
9370                                           v8::Handle<v8::ObjectTemplate>(),
9371                                           global2);
9372   CHECK_EQ(global2, env3->Global());
9373
9374   // Start by using the same security token for env3 as for env1 and env2.
9375   env3->SetSecurityToken(foo);
9376
9377   // Create a property on the global object in env3.
9378   {
9379     v8::Context::Scope scope(env3);
9380     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
9381   }
9382
9383   // Check that other.p is now the property in env3 and that we have access.
9384   result = CompileRun("other.p");
9385   CHECK(result->IsInt32());
9386   CHECK_EQ(24, result->Int32Value());
9387
9388   // Change security token for env3 to something different from env1 and env2.
9389   env3->SetSecurityToken(v8_str("bar"));
9390
9391   // Check that we do not have access to other.p in env1. |other| is now
9392   // the global object for env3 which has a different security token,
9393   // so access should be blocked.
9394   result = CompileRun("other.p");
9395   CHECK(result.IsEmpty());
9396 }
9397
9398
9399 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9400   info.GetReturnValue().Set(
9401       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
9402 }
9403
9404
9405 TEST(DetachedAccesses) {
9406   LocalContext env1;
9407   v8::HandleScope scope(env1->GetIsolate());
9408
9409   // Create second environment.
9410   Local<ObjectTemplate> inner_global_template =
9411       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9412   inner_global_template ->SetAccessorProperty(
9413       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9414   v8::Local<Context> env2 =
9415       Context::New(env1->GetIsolate(), NULL, inner_global_template);
9416
9417   Local<Value> foo = v8_str("foo");
9418
9419   // Set same security token for env1 and env2.
9420   env1->SetSecurityToken(foo);
9421   env2->SetSecurityToken(foo);
9422
9423   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
9424
9425   {
9426     v8::Context::Scope scope(env2);
9427     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
9428     CompileRun(
9429         "function bound_x() { return x; }"
9430         "function get_x()   { return this.x; }"
9431         "function get_x_w() { return (function() {return this.x;})(); }");
9432     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
9433     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
9434     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
9435     env1->Global()->Set(
9436         v8_str("this_x"),
9437         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
9438   }
9439
9440   Local<Object> env2_global = env2->Global();
9441   env2_global->TurnOnAccessCheck();
9442   env2->DetachGlobal();
9443
9444   Local<Value> result;
9445   result = CompileRun("bound_x()");
9446   CHECK_EQ(v8_str("env2_x"), result);
9447   result = CompileRun("get_x()");
9448   CHECK(result.IsEmpty());
9449   result = CompileRun("get_x_w()");
9450   CHECK(result.IsEmpty());
9451   result = CompileRun("this_x()");
9452   CHECK_EQ(v8_str("env2_x"), result);
9453
9454   // Reattach env2's proxy
9455   env2 = Context::New(env1->GetIsolate(),
9456                       0,
9457                       v8::Handle<v8::ObjectTemplate>(),
9458                       env2_global);
9459   env2->SetSecurityToken(foo);
9460   {
9461     v8::Context::Scope scope(env2);
9462     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
9463     env2->Global()->Set(v8_str("env1"), env1->Global());
9464     result = CompileRun(
9465         "results = [];"
9466         "for (var i = 0; i < 4; i++ ) {"
9467         "  results.push(env1.bound_x());"
9468         "  results.push(env1.get_x());"
9469         "  results.push(env1.get_x_w());"
9470         "  results.push(env1.this_x());"
9471         "}"
9472         "results");
9473     Local<v8::Array> results = Local<v8::Array>::Cast(result);
9474     CHECK_EQ(16, results->Length());
9475     for (int i = 0; i < 16; i += 4) {
9476       CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9477       CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9478       CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9479       CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9480     }
9481   }
9482
9483   result = CompileRun(
9484       "results = [];"
9485       "for (var i = 0; i < 4; i++ ) {"
9486       "  results.push(bound_x());"
9487       "  results.push(get_x());"
9488       "  results.push(get_x_w());"
9489       "  results.push(this_x());"
9490       "}"
9491       "results");
9492   Local<v8::Array> results = Local<v8::Array>::Cast(result);
9493   CHECK_EQ(16, results->Length());
9494   for (int i = 0; i < 16; i += 4) {
9495     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9496     CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
9497     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9498     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9499   }
9500
9501   result = CompileRun(
9502       "results = [];"
9503       "for (var i = 0; i < 4; i++ ) {"
9504       "  results.push(this.bound_x());"
9505       "  results.push(this.get_x());"
9506       "  results.push(this.get_x_w());"
9507       "  results.push(this.this_x());"
9508       "}"
9509       "results");
9510   results = Local<v8::Array>::Cast(result);
9511   CHECK_EQ(16, results->Length());
9512   for (int i = 0; i < 16; i += 4) {
9513     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9514     CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9515     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9516     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9517   }
9518 }
9519
9520
9521 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9522 static bool NamedAccessBlocker(Local<v8::Object> global,
9523                                Local<Value> name,
9524                                v8::AccessType type,
9525                                Local<Value> data) {
9526   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9527       allowed_access_type[type];
9528 }
9529
9530
9531 static bool IndexedAccessBlocker(Local<v8::Object> global,
9532                                  uint32_t key,
9533                                  v8::AccessType type,
9534                                  Local<Value> data) {
9535   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9536       allowed_access_type[type];
9537 }
9538
9539
9540 static int g_echo_value = -1;
9541
9542
9543 static void EchoGetter(
9544     Local<String> name,
9545     const v8::PropertyCallbackInfo<v8::Value>& info) {
9546   info.GetReturnValue().Set(v8_num(g_echo_value));
9547 }
9548
9549
9550 static void EchoSetter(Local<String> name,
9551                        Local<Value> value,
9552                        const v8::PropertyCallbackInfo<void>&) {
9553   if (value->IsNumber())
9554     g_echo_value = value->Int32Value();
9555 }
9556
9557
9558 static void UnreachableGetter(
9559     Local<String> name,
9560     const v8::PropertyCallbackInfo<v8::Value>& info) {
9561   CHECK(false);  // This function should not be called..
9562 }
9563
9564
9565 static void UnreachableSetter(Local<String>,
9566                               Local<Value>,
9567                               const v8::PropertyCallbackInfo<void>&) {
9568   CHECK(false);  // This function should nto be called.
9569 }
9570
9571
9572 static void UnreachableFunction(
9573     const v8::FunctionCallbackInfo<v8::Value>& info) {
9574   CHECK(false);  // This function should not be called..
9575 }
9576
9577
9578 TEST(AccessControl) {
9579   v8::Isolate* isolate = CcTest::isolate();
9580   v8::HandleScope handle_scope(isolate);
9581   v8::Handle<v8::ObjectTemplate> global_template =
9582       v8::ObjectTemplate::New(isolate);
9583
9584   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9585                                            IndexedAccessBlocker);
9586
9587   // Add an accessor accessible by cross-domain JS code.
9588   global_template->SetAccessor(
9589       v8_str("accessible_prop"),
9590       EchoGetter, EchoSetter,
9591       v8::Handle<Value>(),
9592       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9593
9594
9595   // Add an accessor that is not accessible by cross-domain JS code.
9596   global_template->SetAccessor(v8_str("blocked_prop"),
9597                                UnreachableGetter, UnreachableSetter,
9598                                v8::Handle<Value>(),
9599                                v8::DEFAULT);
9600
9601   global_template->SetAccessorProperty(
9602       v8_str("blocked_js_prop"),
9603       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9604       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9605       v8::None,
9606       v8::DEFAULT);
9607
9608   // Create an environment
9609   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9610   context0->Enter();
9611
9612   v8::Handle<v8::Object> global0 = context0->Global();
9613
9614   // Define a property with JS getter and setter.
9615   CompileRun(
9616       "function getter() { return 'getter'; };\n"
9617       "function setter() { return 'setter'; }\n"
9618       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9619
9620   Local<Value> getter = global0->Get(v8_str("getter"));
9621   Local<Value> setter = global0->Get(v8_str("setter"));
9622
9623   // And define normal element.
9624   global0->Set(239, v8_str("239"));
9625
9626   // Define an element with JS getter and setter.
9627   CompileRun(
9628       "function el_getter() { return 'el_getter'; };\n"
9629       "function el_setter() { return 'el_setter'; };\n"
9630       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9631
9632   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9633   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9634
9635   v8::HandleScope scope1(isolate);
9636
9637   v8::Local<Context> context1 = Context::New(isolate);
9638   context1->Enter();
9639
9640   v8::Handle<v8::Object> global1 = context1->Global();
9641   global1->Set(v8_str("other"), global0);
9642
9643   // Access blocked property.
9644   CompileRun("other.blocked_prop = 1");
9645
9646   CHECK(CompileRun("other.blocked_prop").IsEmpty());
9647   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9648             .IsEmpty());
9649   CHECK(
9650       CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
9651
9652   // Access blocked element.
9653   CHECK(CompileRun("other[239] = 1").IsEmpty());
9654
9655   CHECK(CompileRun("other[239]").IsEmpty());
9656   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
9657   CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
9658
9659   // Enable ACCESS_HAS
9660   allowed_access_type[v8::ACCESS_HAS] = true;
9661   CHECK(CompileRun("other[239]").IsEmpty());
9662   // ... and now we can get the descriptor...
9663   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
9664             .IsEmpty());
9665   // ... and enumerate the property.
9666   ExpectTrue("propertyIsEnumerable.call(other, '239')");
9667   allowed_access_type[v8::ACCESS_HAS] = false;
9668
9669   // Access a property with JS accessor.
9670   CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
9671
9672   CHECK(CompileRun("other.js_accessor_p").IsEmpty());
9673   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
9674             .IsEmpty());
9675
9676   // Enable both ACCESS_HAS and ACCESS_GET.
9677   allowed_access_type[v8::ACCESS_HAS] = true;
9678   allowed_access_type[v8::ACCESS_GET] = true;
9679
9680   ExpectString("other.js_accessor_p", "getter");
9681   ExpectObject(
9682       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9683   ExpectObject(
9684       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9685   ExpectUndefined(
9686       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9687
9688   allowed_access_type[v8::ACCESS_HAS] = false;
9689   allowed_access_type[v8::ACCESS_GET] = false;
9690
9691   // Access an element with JS accessor.
9692   CHECK(CompileRun("other[42] = 2").IsEmpty());
9693
9694   CHECK(CompileRun("other[42]").IsEmpty());
9695   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
9696
9697   // Enable both ACCESS_HAS and ACCESS_GET.
9698   allowed_access_type[v8::ACCESS_HAS] = true;
9699   allowed_access_type[v8::ACCESS_GET] = true;
9700
9701   ExpectString("other[42]", "el_getter");
9702   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9703   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9704   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9705
9706   allowed_access_type[v8::ACCESS_HAS] = false;
9707   allowed_access_type[v8::ACCESS_GET] = false;
9708
9709   v8::Handle<Value> value;
9710
9711   // Access accessible property
9712   value = CompileRun("other.accessible_prop = 3");
9713   CHECK(value->IsNumber());
9714   CHECK_EQ(3, value->Int32Value());
9715   CHECK_EQ(3, g_echo_value);
9716
9717   value = CompileRun("other.accessible_prop");
9718   CHECK(value->IsNumber());
9719   CHECK_EQ(3, value->Int32Value());
9720
9721   value = CompileRun(
9722       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9723   CHECK(value->IsNumber());
9724   CHECK_EQ(3, value->Int32Value());
9725
9726   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9727   CHECK(value->IsTrue());
9728
9729   // Enumeration doesn't enumerate accessors from inaccessible objects in
9730   // the prototype chain even if the accessors are in themselves accessible.
9731   value = CompileRun(
9732       "(function() {"
9733       "  var obj = { '__proto__': other };"
9734       "  try {"
9735       "    for (var p in obj) {"
9736       "      if (p == 'accessible_prop' ||"
9737       "          p == 'blocked_js_prop' ||"
9738       "          p == 'blocked_js_prop') {"
9739       "        return false;"
9740       "      }"
9741       "    }"
9742       "    return false;"
9743       "  } catch (e) {"
9744       "    return true;"
9745       "  }"
9746       "})()");
9747   CHECK(value->IsTrue());
9748
9749   context1->Exit();
9750   context0->Exit();
9751 }
9752
9753
9754 TEST(AccessControlES5) {
9755   v8::Isolate* isolate = CcTest::isolate();
9756   v8::HandleScope handle_scope(isolate);
9757   v8::Handle<v8::ObjectTemplate> global_template =
9758       v8::ObjectTemplate::New(isolate);
9759
9760   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9761                                            IndexedAccessBlocker);
9762
9763   // Add accessible accessor.
9764   global_template->SetAccessor(
9765       v8_str("accessible_prop"),
9766       EchoGetter, EchoSetter,
9767       v8::Handle<Value>(),
9768       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9769
9770
9771   // Add an accessor that is not accessible by cross-domain JS code.
9772   global_template->SetAccessor(v8_str("blocked_prop"),
9773                                UnreachableGetter, UnreachableSetter,
9774                                v8::Handle<Value>(),
9775                                v8::DEFAULT);
9776
9777   // Create an environment
9778   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9779   context0->Enter();
9780
9781   v8::Handle<v8::Object> global0 = context0->Global();
9782
9783   v8::Local<Context> context1 = Context::New(isolate);
9784   context1->Enter();
9785   v8::Handle<v8::Object> global1 = context1->Global();
9786   global1->Set(v8_str("other"), global0);
9787
9788   // Regression test for issue 1154.
9789   CHECK(CompileRun("Object.keys(other)").IsEmpty());
9790   CHECK(CompileRun("other.blocked_prop").IsEmpty());
9791
9792   // Regression test for issue 1027.
9793   CompileRun("Object.defineProperty(\n"
9794              "  other, 'blocked_prop', {configurable: false})");
9795   CHECK(CompileRun("other.blocked_prop").IsEmpty());
9796   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9797             .IsEmpty());
9798
9799   // Regression test for issue 1171.
9800   ExpectTrue("Object.isExtensible(other)");
9801   CompileRun("Object.preventExtensions(other)");
9802   ExpectTrue("Object.isExtensible(other)");
9803
9804   // Object.seal and Object.freeze.
9805   CompileRun("Object.freeze(other)");
9806   ExpectTrue("Object.isExtensible(other)");
9807
9808   CompileRun("Object.seal(other)");
9809   ExpectTrue("Object.isExtensible(other)");
9810
9811   // Regression test for issue 1250.
9812   // Make sure that we can set the accessible accessors value using normal
9813   // assignment.
9814   CompileRun("other.accessible_prop = 42");
9815   CHECK_EQ(42, g_echo_value);
9816
9817   v8::Handle<Value> value;
9818   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9819   value = CompileRun("other.accessible_prop == 42");
9820   CHECK(value->IsTrue());
9821 }
9822
9823
9824 static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
9825                                  v8::AccessType type, Local<Value> data) {
9826   return false;
9827 }
9828
9829
9830 static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
9831                                    v8::AccessType type, Local<Value> data) {
9832   return false;
9833 }
9834
9835
9836 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9837   v8::Isolate* isolate = CcTest::isolate();
9838   v8::HandleScope handle_scope(isolate);
9839   v8::Handle<v8::ObjectTemplate> obj_template =
9840       v8::ObjectTemplate::New(isolate);
9841
9842   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9843   obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9844                                         BlockEverythingIndexed);
9845
9846   // Create an environment
9847   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9848   context0->Enter();
9849
9850   v8::Handle<v8::Object> global0 = context0->Global();
9851
9852   v8::HandleScope scope1(CcTest::isolate());
9853
9854   v8::Local<Context> context1 = Context::New(isolate);
9855   context1->Enter();
9856
9857   v8::Handle<v8::Object> global1 = context1->Global();
9858   global1->Set(v8_str("other"), global0);
9859   global1->Set(v8_str("object"), obj_template->NewInstance());
9860
9861   v8::Handle<Value> value;
9862
9863   // Attempt to get the property names of the other global object and
9864   // of an object that requires access checks.  Accessing the other
9865   // global object should be blocked by access checks on the global
9866   // proxy object.  Accessing the object that requires access checks
9867   // is blocked by the access checks on the object itself.
9868   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9869   CHECK(value.IsEmpty());
9870
9871   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9872   CHECK(value.IsEmpty());
9873
9874   context1->Exit();
9875   context0->Exit();
9876 }
9877
9878
9879 TEST(SuperAccessControl) {
9880   i::FLAG_harmony_classes = true;
9881   v8::Isolate* isolate = CcTest::isolate();
9882   v8::HandleScope handle_scope(isolate);
9883   v8::Handle<v8::ObjectTemplate> obj_template =
9884       v8::ObjectTemplate::New(isolate);
9885   obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9886                                         BlockEverythingIndexed);
9887   LocalContext env;
9888   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
9889
9890   {
9891     v8::TryCatch try_catch;
9892     CompileRun(
9893         "function f() { return super.hasOwnProperty; };"
9894         "var m = f.toMethod(prohibited);"
9895         "m();");
9896     CHECK(try_catch.HasCaught());
9897   }
9898
9899   {
9900     v8::TryCatch try_catch;
9901     CompileRun(
9902         "function f() { return super[42]; };"
9903         "var m = f.toMethod(prohibited);"
9904         "m();");
9905     CHECK(try_catch.HasCaught());
9906   }
9907
9908   {
9909     v8::TryCatch try_catch;
9910     CompileRun(
9911         "function f() { super.hasOwnProperty = function () {}; };"
9912         "var m = f.toMethod(prohibited);"
9913         "m();");
9914     CHECK(try_catch.HasCaught());
9915   }
9916
9917   {
9918     v8::TryCatch try_catch;
9919     CompileRun(
9920         "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
9921         "function f() { "
9922         "     'use strict';"
9923         "     super.x = function () {}; "
9924         "};"
9925         "var m = f.toMethod(prohibited);"
9926         "m();");
9927     CHECK(try_catch.HasCaught());
9928   }
9929 }
9930
9931
9932 static void IndexedPropertyEnumerator(
9933     const v8::PropertyCallbackInfo<v8::Array>& info) {
9934   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9935   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9936   result->Set(1, v8::Object::New(info.GetIsolate()));
9937   info.GetReturnValue().Set(result);
9938 }
9939
9940
9941 static void NamedPropertyEnumerator(
9942     const v8::PropertyCallbackInfo<v8::Array>& info) {
9943   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9944   result->Set(0, v8_str("x"));
9945   result->Set(1, v8::Object::New(info.GetIsolate()));
9946   info.GetReturnValue().Set(result);
9947 }
9948
9949
9950 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9951   v8::Isolate* isolate = CcTest::isolate();
9952   v8::HandleScope handle_scope(isolate);
9953   v8::Handle<v8::ObjectTemplate> obj_template =
9954       v8::ObjectTemplate::New(isolate);
9955
9956   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9957   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9958   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9959                                           IndexedPropertyEnumerator);
9960   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9961                                         NamedPropertyEnumerator);
9962
9963   LocalContext context;
9964   v8::Handle<v8::Object> global = context->Global();
9965   global->Set(v8_str("object"), obj_template->NewInstance());
9966
9967   v8::Handle<v8::Value> result =
9968       CompileRun("Object.getOwnPropertyNames(object)");
9969   CHECK(result->IsArray());
9970   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9971   CHECK_EQ(3, result_array->Length());
9972   CHECK(result_array->Get(0)->IsString());
9973   CHECK(result_array->Get(1)->IsString());
9974   CHECK(result_array->Get(2)->IsString());
9975   CHECK_EQ(v8_str("7"), result_array->Get(0));
9976   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9977   CHECK_EQ(v8_str("x"), result_array->Get(2));
9978 }
9979
9980
9981 static void ConstTenGetter(Local<String> name,
9982                            const v8::PropertyCallbackInfo<v8::Value>& info) {
9983   info.GetReturnValue().Set(v8_num(10));
9984 }
9985
9986
9987 THREADED_TEST(CrossDomainAccessors) {
9988   v8::Isolate* isolate = CcTest::isolate();
9989   v8::HandleScope handle_scope(isolate);
9990
9991   v8::Handle<v8::FunctionTemplate> func_template =
9992       v8::FunctionTemplate::New(isolate);
9993
9994   v8::Handle<v8::ObjectTemplate> global_template =
9995       func_template->InstanceTemplate();
9996
9997   v8::Handle<v8::ObjectTemplate> proto_template =
9998       func_template->PrototypeTemplate();
9999
10000   // Add an accessor to proto that's accessible by cross-domain JS code.
10001   proto_template->SetAccessor(v8_str("accessible"),
10002                               ConstTenGetter, 0,
10003                               v8::Handle<Value>(),
10004                               v8::ALL_CAN_READ);
10005
10006   // Add an accessor that is not accessible by cross-domain JS code.
10007   global_template->SetAccessor(v8_str("unreachable"),
10008                                UnreachableGetter, 0,
10009                                v8::Handle<Value>(),
10010                                v8::DEFAULT);
10011
10012   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
10013   context0->Enter();
10014
10015   Local<v8::Object> global = context0->Global();
10016   // Add a normal property that shadows 'accessible'
10017   global->Set(v8_str("accessible"), v8_num(11));
10018
10019   // Enter a new context.
10020   v8::HandleScope scope1(CcTest::isolate());
10021   v8::Local<Context> context1 = Context::New(isolate);
10022   context1->Enter();
10023
10024   v8::Handle<v8::Object> global1 = context1->Global();
10025   global1->Set(v8_str("other"), global);
10026
10027   // Should return 10, instead of 11
10028   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
10029   CHECK(value->IsNumber());
10030   CHECK_EQ(10, value->Int32Value());
10031
10032   value = v8_compile("other.unreachable")->Run();
10033   CHECK(value.IsEmpty());
10034
10035   context1->Exit();
10036   context0->Exit();
10037 }
10038
10039
10040 static int named_access_count = 0;
10041 static int indexed_access_count = 0;
10042
10043 static bool NamedAccessCounter(Local<v8::Object> global,
10044                                Local<Value> name,
10045                                v8::AccessType type,
10046                                Local<Value> data) {
10047   named_access_count++;
10048   return true;
10049 }
10050
10051
10052 static bool IndexedAccessCounter(Local<v8::Object> global,
10053                                  uint32_t key,
10054                                  v8::AccessType type,
10055                                  Local<Value> data) {
10056   indexed_access_count++;
10057   return true;
10058 }
10059
10060
10061 // This one is too easily disturbed by other tests.
10062 TEST(AccessControlIC) {
10063   named_access_count = 0;
10064   indexed_access_count = 0;
10065
10066   v8::Isolate* isolate = CcTest::isolate();
10067   v8::HandleScope handle_scope(isolate);
10068
10069   // Create an environment.
10070   v8::Local<Context> context0 = Context::New(isolate);
10071   context0->Enter();
10072
10073   // Create an object that requires access-check functions to be
10074   // called for cross-domain access.
10075   v8::Handle<v8::ObjectTemplate> object_template =
10076       v8::ObjectTemplate::New(isolate);
10077   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10078                                            IndexedAccessCounter);
10079   Local<v8::Object> object = object_template->NewInstance();
10080
10081   v8::HandleScope scope1(isolate);
10082
10083   // Create another environment.
10084   v8::Local<Context> context1 = Context::New(isolate);
10085   context1->Enter();
10086
10087   // Make easy access to the object from the other environment.
10088   v8::Handle<v8::Object> global1 = context1->Global();
10089   global1->Set(v8_str("obj"), object);
10090
10091   v8::Handle<Value> value;
10092
10093   // Check that the named access-control function is called every time.
10094   CompileRun("function testProp(obj) {"
10095              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
10096              "  for (var j = 0; j < 10; j++) obj.prop;"
10097              "  return obj.prop"
10098              "}");
10099   value = CompileRun("testProp(obj)");
10100   CHECK(value->IsNumber());
10101   CHECK_EQ(1, value->Int32Value());
10102   CHECK_EQ(21, named_access_count);
10103
10104   // Check that the named access-control function is called every time.
10105   CompileRun("var p = 'prop';"
10106              "function testKeyed(obj) {"
10107              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
10108              "  for (var j = 0; j < 10; j++) obj[p];"
10109              "  return obj[p];"
10110              "}");
10111   // Use obj which requires access checks.  No inline caching is used
10112   // in that case.
10113   value = CompileRun("testKeyed(obj)");
10114   CHECK(value->IsNumber());
10115   CHECK_EQ(1, value->Int32Value());
10116   CHECK_EQ(42, named_access_count);
10117   // Force the inline caches into generic state and try again.
10118   CompileRun("testKeyed({ a: 0 })");
10119   CompileRun("testKeyed({ b: 0 })");
10120   value = CompileRun("testKeyed(obj)");
10121   CHECK(value->IsNumber());
10122   CHECK_EQ(1, value->Int32Value());
10123   CHECK_EQ(63, named_access_count);
10124
10125   // Check that the indexed access-control function is called every time.
10126   CompileRun("function testIndexed(obj) {"
10127              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
10128              "  for (var j = 0; j < 10; j++) obj[0];"
10129              "  return obj[0]"
10130              "}");
10131   value = CompileRun("testIndexed(obj)");
10132   CHECK(value->IsNumber());
10133   CHECK_EQ(1, value->Int32Value());
10134   CHECK_EQ(21, indexed_access_count);
10135   // Force the inline caches into generic state.
10136   CompileRun("testIndexed(new Array(1))");
10137   // Test that the indexed access check is called.
10138   value = CompileRun("testIndexed(obj)");
10139   CHECK(value->IsNumber());
10140   CHECK_EQ(1, value->Int32Value());
10141   CHECK_EQ(42, indexed_access_count);
10142
10143   // Check that the named access check is called when invoking
10144   // functions on an object that requires access checks.
10145   CompileRun("obj.f = function() {}");
10146   CompileRun("function testCallNormal(obj) {"
10147              "  for (var i = 0; i < 10; i++) obj.f();"
10148              "}");
10149   CompileRun("testCallNormal(obj)");
10150   CHECK_EQ(74, named_access_count);
10151
10152   // Force obj into slow case.
10153   value = CompileRun("delete obj.prop");
10154   CHECK(value->BooleanValue());
10155   // Force inline caches into dictionary probing mode.
10156   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
10157   // Test that the named access check is called.
10158   value = CompileRun("testProp(obj);");
10159   CHECK(value->IsNumber());
10160   CHECK_EQ(1, value->Int32Value());
10161   CHECK_EQ(96, named_access_count);
10162
10163   // Force the call inline cache into dictionary probing mode.
10164   CompileRun("o.f = function() {}; testCallNormal(o)");
10165   // Test that the named access check is still called for each
10166   // invocation of the function.
10167   value = CompileRun("testCallNormal(obj)");
10168   CHECK_EQ(106, named_access_count);
10169
10170   context1->Exit();
10171   context0->Exit();
10172 }
10173
10174
10175 static bool NamedAccessFlatten(Local<v8::Object> global,
10176                                Local<Value> name,
10177                                v8::AccessType type,
10178                                Local<Value> data) {
10179   char buf[100];
10180   int len;
10181
10182   CHECK(name->IsString());
10183
10184   memset(buf, 0x1, sizeof(buf));
10185   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
10186   CHECK_EQ(4, len);
10187
10188   uint16_t buf2[100];
10189
10190   memset(buf, 0x1, sizeof(buf));
10191   len = name.As<String>()->Write(buf2);
10192   CHECK_EQ(4, len);
10193
10194   return true;
10195 }
10196
10197
10198 static bool IndexedAccessFlatten(Local<v8::Object> global,
10199                                  uint32_t key,
10200                                  v8::AccessType type,
10201                                  Local<Value> data) {
10202   return true;
10203 }
10204
10205
10206 // Regression test.  In access checks, operations that may cause
10207 // garbage collection are not allowed.  It used to be the case that
10208 // using the Write operation on a string could cause a garbage
10209 // collection due to flattening of the string.  This is no longer the
10210 // case.
10211 THREADED_TEST(AccessControlFlatten) {
10212   named_access_count = 0;
10213   indexed_access_count = 0;
10214
10215   v8::Isolate* isolate = CcTest::isolate();
10216   v8::HandleScope handle_scope(isolate);
10217
10218   // Create an environment.
10219   v8::Local<Context> context0 = Context::New(isolate);
10220   context0->Enter();
10221
10222   // Create an object that requires access-check functions to be
10223   // called for cross-domain access.
10224   v8::Handle<v8::ObjectTemplate> object_template =
10225       v8::ObjectTemplate::New(isolate);
10226   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
10227                                            IndexedAccessFlatten);
10228   Local<v8::Object> object = object_template->NewInstance();
10229
10230   v8::HandleScope scope1(isolate);
10231
10232   // Create another environment.
10233   v8::Local<Context> context1 = Context::New(isolate);
10234   context1->Enter();
10235
10236   // Make easy access to the object from the other environment.
10237   v8::Handle<v8::Object> global1 = context1->Global();
10238   global1->Set(v8_str("obj"), object);
10239
10240   v8::Handle<Value> value;
10241
10242   value = v8_compile("var p = 'as' + 'df';")->Run();
10243   value = v8_compile("obj[p];")->Run();
10244
10245   context1->Exit();
10246   context0->Exit();
10247 }
10248
10249
10250 static void AccessControlNamedGetter(
10251     Local<String>,
10252     const v8::PropertyCallbackInfo<v8::Value>& info) {
10253   info.GetReturnValue().Set(42);
10254 }
10255
10256
10257 static void AccessControlNamedSetter(
10258     Local<String>,
10259     Local<Value> value,
10260     const v8::PropertyCallbackInfo<v8::Value>& info) {
10261   info.GetReturnValue().Set(value);
10262 }
10263
10264
10265 static void AccessControlIndexedGetter(
10266       uint32_t index,
10267       const v8::PropertyCallbackInfo<v8::Value>& info) {
10268   info.GetReturnValue().Set(v8_num(42));
10269 }
10270
10271
10272 static void AccessControlIndexedSetter(
10273     uint32_t,
10274     Local<Value> value,
10275     const v8::PropertyCallbackInfo<v8::Value>& info) {
10276   info.GetReturnValue().Set(value);
10277 }
10278
10279
10280 THREADED_TEST(AccessControlInterceptorIC) {
10281   named_access_count = 0;
10282   indexed_access_count = 0;
10283
10284   v8::Isolate* isolate = CcTest::isolate();
10285   v8::HandleScope handle_scope(isolate);
10286
10287   // Create an environment.
10288   v8::Local<Context> context0 = Context::New(isolate);
10289   context0->Enter();
10290
10291   // Create an object that requires access-check functions to be
10292   // called for cross-domain access.  The object also has interceptors
10293   // interceptor.
10294   v8::Handle<v8::ObjectTemplate> object_template =
10295       v8::ObjectTemplate::New(isolate);
10296   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10297                                            IndexedAccessCounter);
10298   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
10299                                            AccessControlNamedSetter);
10300   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
10301                                              AccessControlIndexedSetter);
10302   Local<v8::Object> object = object_template->NewInstance();
10303
10304   v8::HandleScope scope1(isolate);
10305
10306   // Create another environment.
10307   v8::Local<Context> context1 = Context::New(isolate);
10308   context1->Enter();
10309
10310   // Make easy access to the object from the other environment.
10311   v8::Handle<v8::Object> global1 = context1->Global();
10312   global1->Set(v8_str("obj"), object);
10313
10314   v8::Handle<Value> value;
10315
10316   // Check that the named access-control function is called every time
10317   // eventhough there is an interceptor on the object.
10318   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
10319   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
10320                      "obj.x")->Run();
10321   CHECK(value->IsNumber());
10322   CHECK_EQ(42, value->Int32Value());
10323   CHECK_EQ(21, named_access_count);
10324
10325   value = v8_compile("var p = 'x';")->Run();
10326   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
10327   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
10328                      "obj[p]")->Run();
10329   CHECK(value->IsNumber());
10330   CHECK_EQ(42, value->Int32Value());
10331   CHECK_EQ(42, named_access_count);
10332
10333   // Check that the indexed access-control function is called every
10334   // time eventhough there is an interceptor on the object.
10335   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
10336   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
10337                      "obj[0]")->Run();
10338   CHECK(value->IsNumber());
10339   CHECK_EQ(42, value->Int32Value());
10340   CHECK_EQ(21, indexed_access_count);
10341
10342   context1->Exit();
10343   context0->Exit();
10344 }
10345
10346
10347 THREADED_TEST(Version) {
10348   v8::V8::GetVersion();
10349 }
10350
10351
10352 static void InstanceFunctionCallback(
10353     const v8::FunctionCallbackInfo<v8::Value>& args) {
10354   ApiTestFuzzer::Fuzz();
10355   args.GetReturnValue().Set(v8_num(12));
10356 }
10357
10358
10359 THREADED_TEST(InstanceProperties) {
10360   LocalContext context;
10361   v8::Isolate* isolate = context->GetIsolate();
10362   v8::HandleScope handle_scope(isolate);
10363
10364   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10365   Local<ObjectTemplate> instance = t->InstanceTemplate();
10366
10367   instance->Set(v8_str("x"), v8_num(42));
10368   instance->Set(v8_str("f"),
10369                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10370
10371   Local<Value> o = t->GetFunction()->NewInstance();
10372
10373   context->Global()->Set(v8_str("i"), o);
10374   Local<Value> value = CompileRun("i.x");
10375   CHECK_EQ(42, value->Int32Value());
10376
10377   value = CompileRun("i.f()");
10378   CHECK_EQ(12, value->Int32Value());
10379 }
10380
10381
10382 static void GlobalObjectInstancePropertiesGet(
10383     Local<String> key,
10384     const v8::PropertyCallbackInfo<v8::Value>&) {
10385   ApiTestFuzzer::Fuzz();
10386 }
10387
10388
10389 THREADED_TEST(GlobalObjectInstanceProperties) {
10390   v8::Isolate* isolate = CcTest::isolate();
10391   v8::HandleScope handle_scope(isolate);
10392
10393   Local<Value> global_object;
10394
10395   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10396   t->InstanceTemplate()->SetNamedPropertyHandler(
10397       GlobalObjectInstancePropertiesGet);
10398   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10399   instance_template->Set(v8_str("x"), v8_num(42));
10400   instance_template->Set(v8_str("f"),
10401                          v8::FunctionTemplate::New(isolate,
10402                                                    InstanceFunctionCallback));
10403
10404   // The script to check how Crankshaft compiles missing global function
10405   // invocations.  function g is not defined and should throw on call.
10406   const char* script =
10407       "function wrapper(call) {"
10408       "  var x = 0, y = 1;"
10409       "  for (var i = 0; i < 1000; i++) {"
10410       "    x += i * 100;"
10411       "    y += i * 100;"
10412       "  }"
10413       "  if (call) g();"
10414       "}"
10415       "for (var i = 0; i < 17; i++) wrapper(false);"
10416       "var thrown = 0;"
10417       "try { wrapper(true); } catch (e) { thrown = 1; };"
10418       "thrown";
10419
10420   {
10421     LocalContext env(NULL, instance_template);
10422     // Hold on to the global object so it can be used again in another
10423     // environment initialization.
10424     global_object = env->Global();
10425
10426     Local<Value> value = CompileRun("x");
10427     CHECK_EQ(42, value->Int32Value());
10428     value = CompileRun("f()");
10429     CHECK_EQ(12, value->Int32Value());
10430     value = CompileRun(script);
10431     CHECK_EQ(1, value->Int32Value());
10432   }
10433
10434   {
10435     // Create new environment reusing the global object.
10436     LocalContext env(NULL, instance_template, global_object);
10437     Local<Value> value = CompileRun("x");
10438     CHECK_EQ(42, value->Int32Value());
10439     value = CompileRun("f()");
10440     CHECK_EQ(12, value->Int32Value());
10441     value = CompileRun(script);
10442     CHECK_EQ(1, value->Int32Value());
10443   }
10444 }
10445
10446
10447 THREADED_TEST(CallKnownGlobalReceiver) {
10448   v8::Isolate* isolate = CcTest::isolate();
10449   v8::HandleScope handle_scope(isolate);
10450
10451   Local<Value> global_object;
10452
10453   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10454   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10455
10456   // The script to check that we leave global object not
10457   // global object proxy on stack when we deoptimize from inside
10458   // arguments evaluation.
10459   // To provoke error we need to both force deoptimization
10460   // from arguments evaluation and to force CallIC to take
10461   // CallIC_Miss code path that can't cope with global proxy.
10462   const char* script =
10463       "function bar(x, y) { try { } finally { } }"
10464       "function baz(x) { try { } finally { } }"
10465       "function bom(x) { try { } finally { } }"
10466       "function foo(x) { bar([x], bom(2)); }"
10467       "for (var i = 0; i < 10000; i++) foo(1);"
10468       "foo";
10469
10470   Local<Value> foo;
10471   {
10472     LocalContext env(NULL, instance_template);
10473     // Hold on to the global object so it can be used again in another
10474     // environment initialization.
10475     global_object = env->Global();
10476     foo = CompileRun(script);
10477   }
10478
10479   {
10480     // Create new environment reusing the global object.
10481     LocalContext env(NULL, instance_template, global_object);
10482     env->Global()->Set(v8_str("foo"), foo);
10483     CompileRun("foo()");
10484   }
10485 }
10486
10487
10488 static void ShadowFunctionCallback(
10489     const v8::FunctionCallbackInfo<v8::Value>& args) {
10490   ApiTestFuzzer::Fuzz();
10491   args.GetReturnValue().Set(v8_num(42));
10492 }
10493
10494
10495 static int shadow_y;
10496 static int shadow_y_setter_call_count;
10497 static int shadow_y_getter_call_count;
10498
10499
10500 static void ShadowYSetter(Local<String>,
10501                           Local<Value>,
10502                           const v8::PropertyCallbackInfo<void>&) {
10503   shadow_y_setter_call_count++;
10504   shadow_y = 42;
10505 }
10506
10507
10508 static void ShadowYGetter(Local<String> name,
10509                           const v8::PropertyCallbackInfo<v8::Value>& info) {
10510   ApiTestFuzzer::Fuzz();
10511   shadow_y_getter_call_count++;
10512   info.GetReturnValue().Set(v8_num(shadow_y));
10513 }
10514
10515
10516 static void ShadowIndexedGet(uint32_t index,
10517                              const v8::PropertyCallbackInfo<v8::Value>&) {
10518 }
10519
10520
10521 static void ShadowNamedGet(Local<String> key,
10522                            const v8::PropertyCallbackInfo<v8::Value>&) {
10523 }
10524
10525
10526 THREADED_TEST(ShadowObject) {
10527   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10528   v8::Isolate* isolate = CcTest::isolate();
10529   v8::HandleScope handle_scope(isolate);
10530
10531   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10532   LocalContext context(NULL, global_template);
10533
10534   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10535   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10536   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10537   Local<ObjectTemplate> proto = t->PrototypeTemplate();
10538   Local<ObjectTemplate> instance = t->InstanceTemplate();
10539
10540   proto->Set(v8_str("f"),
10541              v8::FunctionTemplate::New(isolate,
10542                                        ShadowFunctionCallback,
10543                                        Local<Value>()));
10544   proto->Set(v8_str("x"), v8_num(12));
10545
10546   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10547
10548   Local<Value> o = t->GetFunction()->NewInstance();
10549   context->Global()->Set(v8_str("__proto__"), o);
10550
10551   Local<Value> value =
10552       CompileRun("this.propertyIsEnumerable(0)");
10553   CHECK(value->IsBoolean());
10554   CHECK(!value->BooleanValue());
10555
10556   value = CompileRun("x");
10557   CHECK_EQ(12, value->Int32Value());
10558
10559   value = CompileRun("f()");
10560   CHECK_EQ(42, value->Int32Value());
10561
10562   CompileRun("y = 43");
10563   CHECK_EQ(1, shadow_y_setter_call_count);
10564   value = CompileRun("y");
10565   CHECK_EQ(1, shadow_y_getter_call_count);
10566   CHECK_EQ(42, value->Int32Value());
10567 }
10568
10569
10570 THREADED_TEST(HiddenPrototype) {
10571   LocalContext context;
10572   v8::Isolate* isolate = context->GetIsolate();
10573   v8::HandleScope handle_scope(isolate);
10574
10575   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10576   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10577   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10578   t1->SetHiddenPrototype(true);
10579   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10580   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10581   t2->SetHiddenPrototype(true);
10582   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10583   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10584   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10585
10586   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10587   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10588   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10589   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10590
10591   // Setting the prototype on an object skips hidden prototypes.
10592   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10593   o0->Set(v8_str("__proto__"), o1);
10594   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10595   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10596   o0->Set(v8_str("__proto__"), o2);
10597   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10598   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10599   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10600   o0->Set(v8_str("__proto__"), o3);
10601   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10602   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10603   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10604   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10605
10606   // Getting the prototype of o0 should get the first visible one
10607   // which is o3.  Therefore, z should not be defined on the prototype
10608   // object.
10609   Local<Value> proto = o0->Get(v8_str("__proto__"));
10610   CHECK(proto->IsObject());
10611   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10612 }
10613
10614
10615 THREADED_TEST(HiddenPrototypeSet) {
10616   LocalContext context;
10617   v8::Isolate* isolate = context->GetIsolate();
10618   v8::HandleScope handle_scope(isolate);
10619
10620   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10621   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10622   ht->SetHiddenPrototype(true);
10623   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10624   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10625
10626   Local<v8::Object> o = ot->GetFunction()->NewInstance();
10627   Local<v8::Object> h = ht->GetFunction()->NewInstance();
10628   Local<v8::Object> p = pt->GetFunction()->NewInstance();
10629   o->Set(v8_str("__proto__"), h);
10630   h->Set(v8_str("__proto__"), p);
10631
10632   // Setting a property that exists on the hidden prototype goes there.
10633   o->Set(v8_str("x"), v8_num(7));
10634   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10635   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10636   CHECK(p->Get(v8_str("x"))->IsUndefined());
10637
10638   // Setting a new property should not be forwarded to the hidden prototype.
10639   o->Set(v8_str("y"), v8_num(6));
10640   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10641   CHECK(h->Get(v8_str("y"))->IsUndefined());
10642   CHECK(p->Get(v8_str("y"))->IsUndefined());
10643
10644   // Setting a property that only exists on a prototype of the hidden prototype
10645   // is treated normally again.
10646   p->Set(v8_str("z"), v8_num(8));
10647   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10648   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10649   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10650   o->Set(v8_str("z"), v8_num(9));
10651   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10652   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10653   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10654 }
10655
10656
10657 // Regression test for issue 2457.
10658 THREADED_TEST(HiddenPrototypeIdentityHash) {
10659   LocalContext context;
10660   v8::HandleScope handle_scope(context->GetIsolate());
10661
10662   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10663   t->SetHiddenPrototype(true);
10664   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10665   Handle<Object> p = t->GetFunction()->NewInstance();
10666   Handle<Object> o = Object::New(context->GetIsolate());
10667   o->SetPrototype(p);
10668
10669   int hash = o->GetIdentityHash();
10670   USE(hash);
10671   o->Set(v8_str("foo"), v8_num(42));
10672   DCHECK_EQ(hash, o->GetIdentityHash());
10673 }
10674
10675
10676 THREADED_TEST(SetPrototype) {
10677   LocalContext context;
10678   v8::Isolate* isolate = context->GetIsolate();
10679   v8::HandleScope handle_scope(isolate);
10680
10681   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10682   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10683   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10684   t1->SetHiddenPrototype(true);
10685   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10686   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10687   t2->SetHiddenPrototype(true);
10688   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10689   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10690   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10691
10692   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10693   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10694   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10695   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10696
10697   // Setting the prototype on an object does not skip hidden prototypes.
10698   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10699   CHECK(o0->SetPrototype(o1));
10700   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10701   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10702   CHECK(o1->SetPrototype(o2));
10703   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10704   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10705   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10706   CHECK(o2->SetPrototype(o3));
10707   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10708   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10709   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10710   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10711
10712   // Getting the prototype of o0 should get the first visible one
10713   // which is o3.  Therefore, z should not be defined on the prototype
10714   // object.
10715   Local<Value> proto = o0->Get(v8_str("__proto__"));
10716   CHECK(proto->IsObject());
10717   CHECK_EQ(proto.As<v8::Object>(), o3);
10718
10719   // However, Object::GetPrototype ignores hidden prototype.
10720   Local<Value> proto0 = o0->GetPrototype();
10721   CHECK(proto0->IsObject());
10722   CHECK_EQ(proto0.As<v8::Object>(), o1);
10723
10724   Local<Value> proto1 = o1->GetPrototype();
10725   CHECK(proto1->IsObject());
10726   CHECK_EQ(proto1.As<v8::Object>(), o2);
10727
10728   Local<Value> proto2 = o2->GetPrototype();
10729   CHECK(proto2->IsObject());
10730   CHECK_EQ(proto2.As<v8::Object>(), o3);
10731 }
10732
10733
10734 // Getting property names of an object with a prototype chain that
10735 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
10736 // crash the runtime.
10737 THREADED_TEST(Regress91517) {
10738   i::FLAG_allow_natives_syntax = true;
10739   LocalContext context;
10740   v8::Isolate* isolate = context->GetIsolate();
10741   v8::HandleScope handle_scope(isolate);
10742
10743   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10744   t1->SetHiddenPrototype(true);
10745   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10746   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10747   t2->SetHiddenPrototype(true);
10748   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10749   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10750   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10751   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10752   t3->SetHiddenPrototype(true);
10753   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10754   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10755   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10756
10757   // Force dictionary-based properties.
10758   i::ScopedVector<char> name_buf(1024);
10759   for (int i = 1; i <= 1000; i++) {
10760     i::SNPrintF(name_buf, "sdf%d", i);
10761     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10762   }
10763
10764   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10765   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10766   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10767   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10768
10769   // Create prototype chain of hidden prototypes.
10770   CHECK(o4->SetPrototype(o3));
10771   CHECK(o3->SetPrototype(o2));
10772   CHECK(o2->SetPrototype(o1));
10773
10774   // Call the runtime version of GetOwnPropertyNames() on the natively
10775   // created object through JavaScript.
10776   context->Global()->Set(v8_str("obj"), o4);
10777   // PROPERTY_ATTRIBUTES_NONE = 0
10778   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10779
10780   ExpectInt32("names.length", 1006);
10781   ExpectTrue("names.indexOf(\"baz\") >= 0");
10782   ExpectTrue("names.indexOf(\"boo\") >= 0");
10783   ExpectTrue("names.indexOf(\"foo\") >= 0");
10784   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10785   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10786   ExpectFalse("names[1005] == undefined");
10787 }
10788
10789
10790 // Getting property names of an object with a hidden and inherited
10791 // prototype should not duplicate the accessor properties inherited.
10792 THREADED_TEST(Regress269562) {
10793   i::FLAG_allow_natives_syntax = true;
10794   LocalContext context;
10795   v8::HandleScope handle_scope(context->GetIsolate());
10796
10797   Local<v8::FunctionTemplate> t1 =
10798       v8::FunctionTemplate::New(context->GetIsolate());
10799   t1->SetHiddenPrototype(true);
10800
10801   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10802   i1->SetAccessor(v8_str("foo"),
10803                   SimpleAccessorGetter, SimpleAccessorSetter);
10804   i1->SetAccessor(v8_str("bar"),
10805                   SimpleAccessorGetter, SimpleAccessorSetter);
10806   i1->SetAccessor(v8_str("baz"),
10807                   SimpleAccessorGetter, SimpleAccessorSetter);
10808   i1->Set(v8_str("n1"), v8_num(1));
10809   i1->Set(v8_str("n2"), v8_num(2));
10810
10811   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10812   Local<v8::FunctionTemplate> t2 =
10813       v8::FunctionTemplate::New(context->GetIsolate());
10814   t2->SetHiddenPrototype(true);
10815
10816   // Inherit from t1 and mark prototype as hidden.
10817   t2->Inherit(t1);
10818   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10819
10820   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10821   CHECK(o2->SetPrototype(o1));
10822
10823   v8::Local<v8::Symbol> sym =
10824       v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10825   o1->Set(sym, v8_num(3));
10826   o1->SetHiddenValue(
10827       v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10828
10829   // Call the runtime version of GetOwnPropertyNames() on
10830   // the natively created object through JavaScript.
10831   context->Global()->Set(v8_str("obj"), o2);
10832   context->Global()->Set(v8_str("sym"), sym);
10833   // PROPERTY_ATTRIBUTES_NONE = 0
10834   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10835
10836   ExpectInt32("names.length", 7);
10837   ExpectTrue("names.indexOf(\"foo\") >= 0");
10838   ExpectTrue("names.indexOf(\"bar\") >= 0");
10839   ExpectTrue("names.indexOf(\"baz\") >= 0");
10840   ExpectTrue("names.indexOf(\"n1\") >= 0");
10841   ExpectTrue("names.indexOf(\"n2\") >= 0");
10842   ExpectTrue("names.indexOf(sym) >= 0");
10843   ExpectTrue("names.indexOf(\"mine\") >= 0");
10844 }
10845
10846
10847 THREADED_TEST(FunctionReadOnlyPrototype) {
10848   LocalContext context;
10849   v8::Isolate* isolate = context->GetIsolate();
10850   v8::HandleScope handle_scope(isolate);
10851
10852   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10853   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10854   t1->ReadOnlyPrototype();
10855   context->Global()->Set(v8_str("func1"), t1->GetFunction());
10856   // Configured value of ReadOnly flag.
10857   CHECK(CompileRun(
10858       "(function() {"
10859       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10860       "  return (descriptor['writable'] == false);"
10861       "})()")->BooleanValue());
10862   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10863   CHECK_EQ(42,
10864            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10865
10866   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10867   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10868   context->Global()->Set(v8_str("func2"), t2->GetFunction());
10869   // Default value of ReadOnly flag.
10870   CHECK(CompileRun(
10871       "(function() {"
10872       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10873       "  return (descriptor['writable'] == true);"
10874       "})()")->BooleanValue());
10875   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10876 }
10877
10878
10879 THREADED_TEST(SetPrototypeThrows) {
10880   LocalContext context;
10881   v8::Isolate* isolate = context->GetIsolate();
10882   v8::HandleScope handle_scope(isolate);
10883
10884   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10885
10886   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10887   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10888
10889   CHECK(o0->SetPrototype(o1));
10890   // If setting the prototype leads to the cycle, SetPrototype should
10891   // return false and keep VM in sane state.
10892   v8::TryCatch try_catch;
10893   CHECK(!o1->SetPrototype(o0));
10894   CHECK(!try_catch.HasCaught());
10895   DCHECK(!CcTest::i_isolate()->has_pending_exception());
10896
10897   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10898 }
10899
10900
10901 THREADED_TEST(FunctionRemovePrototype) {
10902   LocalContext context;
10903   v8::Isolate* isolate = context->GetIsolate();
10904   v8::HandleScope handle_scope(isolate);
10905
10906   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10907   t1->RemovePrototype();
10908   Local<v8::Function> fun = t1->GetFunction();
10909   context->Global()->Set(v8_str("fun"), fun);
10910   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10911
10912   v8::TryCatch try_catch;
10913   CompileRun("new fun()");
10914   CHECK(try_catch.HasCaught());
10915
10916   try_catch.Reset();
10917   fun->NewInstance();
10918   CHECK(try_catch.HasCaught());
10919 }
10920
10921
10922 THREADED_TEST(GetterSetterExceptions) {
10923   LocalContext context;
10924   v8::Isolate* isolate = context->GetIsolate();
10925   v8::HandleScope handle_scope(isolate);
10926   CompileRun(
10927     "function Foo() { };"
10928     "function Throw() { throw 5; };"
10929     "var x = { };"
10930     "x.__defineSetter__('set', Throw);"
10931     "x.__defineGetter__('get', Throw);");
10932   Local<v8::Object> x =
10933       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10934   v8::TryCatch try_catch;
10935   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10936   x->Get(v8_str("get"));
10937   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10938   x->Get(v8_str("get"));
10939   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10940   x->Get(v8_str("get"));
10941   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10942   x->Get(v8_str("get"));
10943 }
10944
10945
10946 THREADED_TEST(Constructor) {
10947   LocalContext context;
10948   v8::Isolate* isolate = context->GetIsolate();
10949   v8::HandleScope handle_scope(isolate);
10950   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10951   templ->SetClassName(v8_str("Fun"));
10952   Local<Function> cons = templ->GetFunction();
10953   context->Global()->Set(v8_str("Fun"), cons);
10954   Local<v8::Object> inst = cons->NewInstance();
10955   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10956   CHECK(obj->IsJSObject());
10957   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10958   CHECK(value->BooleanValue());
10959 }
10960
10961
10962 static void ConstructorCallback(
10963     const v8::FunctionCallbackInfo<v8::Value>& args) {
10964   ApiTestFuzzer::Fuzz();
10965   Local<Object> This;
10966
10967   if (args.IsConstructCall()) {
10968     Local<Object> Holder = args.Holder();
10969     This = Object::New(args.GetIsolate());
10970     Local<Value> proto = Holder->GetPrototype();
10971     if (proto->IsObject()) {
10972       This->SetPrototype(proto);
10973     }
10974   } else {
10975     This = args.This();
10976   }
10977
10978   This->Set(v8_str("a"), args[0]);
10979   args.GetReturnValue().Set(This);
10980 }
10981
10982
10983 static void FakeConstructorCallback(
10984     const v8::FunctionCallbackInfo<v8::Value>& args) {
10985   ApiTestFuzzer::Fuzz();
10986   args.GetReturnValue().Set(args[0]);
10987 }
10988
10989
10990 THREADED_TEST(ConstructorForObject) {
10991   LocalContext context;
10992   v8::Isolate* isolate = context->GetIsolate();
10993   v8::HandleScope handle_scope(isolate);
10994
10995   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10996     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10997     Local<Object> instance = instance_template->NewInstance();
10998     context->Global()->Set(v8_str("obj"), instance);
10999     v8::TryCatch try_catch;
11000     Local<Value> value;
11001     CHECK(!try_catch.HasCaught());
11002
11003     // Call the Object's constructor with a 32-bit signed integer.
11004     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
11005     CHECK(!try_catch.HasCaught());
11006     CHECK(value->IsInt32());
11007     CHECK_EQ(28, value->Int32Value());
11008
11009     Local<Value> args1[] = { v8_num(28) };
11010     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
11011     CHECK(value_obj1->IsObject());
11012     Local<Object> object1 = Local<Object>::Cast(value_obj1);
11013     value = object1->Get(v8_str("a"));
11014     CHECK(value->IsInt32());
11015     CHECK(!try_catch.HasCaught());
11016     CHECK_EQ(28, value->Int32Value());
11017
11018     // Call the Object's constructor with a String.
11019     value = CompileRun(
11020         "(function() { var o = new obj('tipli'); return o.a; })()");
11021     CHECK(!try_catch.HasCaught());
11022     CHECK(value->IsString());
11023     String::Utf8Value string_value1(value->ToString());
11024     CHECK_EQ("tipli", *string_value1);
11025
11026     Local<Value> args2[] = { v8_str("tipli") };
11027     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
11028     CHECK(value_obj2->IsObject());
11029     Local<Object> object2 = Local<Object>::Cast(value_obj2);
11030     value = object2->Get(v8_str("a"));
11031     CHECK(!try_catch.HasCaught());
11032     CHECK(value->IsString());
11033     String::Utf8Value string_value2(value->ToString());
11034     CHECK_EQ("tipli", *string_value2);
11035
11036     // Call the Object's constructor with a Boolean.
11037     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
11038     CHECK(!try_catch.HasCaught());
11039     CHECK(value->IsBoolean());
11040     CHECK_EQ(true, value->BooleanValue());
11041
11042     Handle<Value> args3[] = { v8::True(isolate) };
11043     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
11044     CHECK(value_obj3->IsObject());
11045     Local<Object> object3 = Local<Object>::Cast(value_obj3);
11046     value = object3->Get(v8_str("a"));
11047     CHECK(!try_catch.HasCaught());
11048     CHECK(value->IsBoolean());
11049     CHECK_EQ(true, value->BooleanValue());
11050
11051     // Call the Object's constructor with undefined.
11052     Handle<Value> args4[] = { v8::Undefined(isolate) };
11053     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
11054     CHECK(value_obj4->IsObject());
11055     Local<Object> object4 = Local<Object>::Cast(value_obj4);
11056     value = object4->Get(v8_str("a"));
11057     CHECK(!try_catch.HasCaught());
11058     CHECK(value->IsUndefined());
11059
11060     // Call the Object's constructor with null.
11061     Handle<Value> args5[] = { v8::Null(isolate) };
11062     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
11063     CHECK(value_obj5->IsObject());
11064     Local<Object> object5 = Local<Object>::Cast(value_obj5);
11065     value = object5->Get(v8_str("a"));
11066     CHECK(!try_catch.HasCaught());
11067     CHECK(value->IsNull());
11068   }
11069
11070   // Check exception handling when there is no constructor set for the Object.
11071   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11072     Local<Object> instance = instance_template->NewInstance();
11073     context->Global()->Set(v8_str("obj2"), instance);
11074     v8::TryCatch try_catch;
11075     Local<Value> value;
11076     CHECK(!try_catch.HasCaught());
11077
11078     value = CompileRun("new obj2(28)");
11079     CHECK(try_catch.HasCaught());
11080     String::Utf8Value exception_value1(try_catch.Exception());
11081     CHECK_EQ("TypeError: object is not a function", *exception_value1);
11082     try_catch.Reset();
11083
11084     Local<Value> args[] = { v8_num(29) };
11085     value = instance->CallAsConstructor(1, args);
11086     CHECK(try_catch.HasCaught());
11087     String::Utf8Value exception_value2(try_catch.Exception());
11088     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
11089     try_catch.Reset();
11090   }
11091
11092   // Check the case when constructor throws exception.
11093   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11094     instance_template->SetCallAsFunctionHandler(ThrowValue);
11095     Local<Object> instance = instance_template->NewInstance();
11096     context->Global()->Set(v8_str("obj3"), instance);
11097     v8::TryCatch try_catch;
11098     Local<Value> value;
11099     CHECK(!try_catch.HasCaught());
11100
11101     value = CompileRun("new obj3(22)");
11102     CHECK(try_catch.HasCaught());
11103     String::Utf8Value exception_value1(try_catch.Exception());
11104     CHECK_EQ("22", *exception_value1);
11105     try_catch.Reset();
11106
11107     Local<Value> args[] = { v8_num(23) };
11108     value = instance->CallAsConstructor(1, args);
11109     CHECK(try_catch.HasCaught());
11110     String::Utf8Value exception_value2(try_catch.Exception());
11111     CHECK_EQ("23", *exception_value2);
11112     try_catch.Reset();
11113   }
11114
11115   // Check whether constructor returns with an object or non-object.
11116   { Local<FunctionTemplate> function_template =
11117         FunctionTemplate::New(isolate, FakeConstructorCallback);
11118     Local<Function> function = function_template->GetFunction();
11119     Local<Object> instance1 = function;
11120     context->Global()->Set(v8_str("obj4"), instance1);
11121     v8::TryCatch try_catch;
11122     Local<Value> value;
11123     CHECK(!try_catch.HasCaught());
11124
11125     CHECK(instance1->IsObject());
11126     CHECK(instance1->IsFunction());
11127
11128     value = CompileRun("new obj4(28)");
11129     CHECK(!try_catch.HasCaught());
11130     CHECK(value->IsObject());
11131
11132     Local<Value> args1[] = { v8_num(28) };
11133     value = instance1->CallAsConstructor(1, args1);
11134     CHECK(!try_catch.HasCaught());
11135     CHECK(value->IsObject());
11136
11137     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11138     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
11139     Local<Object> instance2 = instance_template->NewInstance();
11140     context->Global()->Set(v8_str("obj5"), instance2);
11141     CHECK(!try_catch.HasCaught());
11142
11143     CHECK(instance2->IsObject());
11144     CHECK(!instance2->IsFunction());
11145
11146     value = CompileRun("new obj5(28)");
11147     CHECK(!try_catch.HasCaught());
11148     CHECK(!value->IsObject());
11149
11150     Local<Value> args2[] = { v8_num(28) };
11151     value = instance2->CallAsConstructor(1, args2);
11152     CHECK(!try_catch.HasCaught());
11153     CHECK(!value->IsObject());
11154   }
11155 }
11156
11157
11158 THREADED_TEST(FunctionDescriptorException) {
11159   LocalContext context;
11160   v8::Isolate* isolate = context->GetIsolate();
11161   v8::HandleScope handle_scope(isolate);
11162   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11163   templ->SetClassName(v8_str("Fun"));
11164   Local<Function> cons = templ->GetFunction();
11165   context->Global()->Set(v8_str("Fun"), cons);
11166   Local<Value> value = CompileRun(
11167     "function test() {"
11168     "  try {"
11169     "    (new Fun()).blah()"
11170     "  } catch (e) {"
11171     "    var str = String(e);"
11172     // "    if (str.indexOf('TypeError') == -1) return 1;"
11173     // "    if (str.indexOf('[object Fun]') != -1) return 2;"
11174     // "    if (str.indexOf('#<Fun>') == -1) return 3;"
11175     "    return 0;"
11176     "  }"
11177     "  return 4;"
11178     "}"
11179     "test();");
11180   CHECK_EQ(0, value->Int32Value());
11181 }
11182
11183
11184 THREADED_TEST(EvalAliasedDynamic) {
11185   LocalContext current;
11186   v8::HandleScope scope(current->GetIsolate());
11187
11188   // Tests where aliased eval can only be resolved dynamically.
11189   Local<Script> script = v8_compile(
11190       "function f(x) { "
11191       "  var foo = 2;"
11192       "  with (x) { return eval('foo'); }"
11193       "}"
11194       "foo = 0;"
11195       "result1 = f(new Object());"
11196       "result2 = f(this);"
11197       "var x = new Object();"
11198       "x.eval = function(x) { return 1; };"
11199       "result3 = f(x);");
11200   script->Run();
11201   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
11202   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
11203   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
11204
11205   v8::TryCatch try_catch;
11206   script = v8_compile(
11207       "function f(x) { "
11208       "  var bar = 2;"
11209       "  with (x) { return eval('bar'); }"
11210       "}"
11211       "result4 = f(this)");
11212   script->Run();
11213   CHECK(!try_catch.HasCaught());
11214   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
11215
11216   try_catch.Reset();
11217 }
11218
11219
11220 THREADED_TEST(CrossEval) {
11221   v8::HandleScope scope(CcTest::isolate());
11222   LocalContext other;
11223   LocalContext current;
11224
11225   Local<String> token = v8_str("<security token>");
11226   other->SetSecurityToken(token);
11227   current->SetSecurityToken(token);
11228
11229   // Set up reference from current to other.
11230   current->Global()->Set(v8_str("other"), other->Global());
11231
11232   // Check that new variables are introduced in other context.
11233   Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11234   script->Run();
11235   Local<Value> foo = other->Global()->Get(v8_str("foo"));
11236   CHECK_EQ(1234, foo->Int32Value());
11237   CHECK(!current->Global()->Has(v8_str("foo")));
11238
11239   // Check that writing to non-existing properties introduces them in
11240   // the other context.
11241   script = v8_compile("other.eval('na = 1234')");
11242   script->Run();
11243   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
11244   CHECK(!current->Global()->Has(v8_str("na")));
11245
11246   // Check that global variables in current context are not visible in other
11247   // context.
11248   v8::TryCatch try_catch;
11249   script = v8_compile("var bar = 42; other.eval('bar');");
11250   Local<Value> result = script->Run();
11251   CHECK(try_catch.HasCaught());
11252   try_catch.Reset();
11253
11254   // Check that local variables in current context are not visible in other
11255   // context.
11256   script = v8_compile(
11257       "(function() { "
11258       "  var baz = 87;"
11259       "  return other.eval('baz');"
11260       "})();");
11261   result = script->Run();
11262   CHECK(try_catch.HasCaught());
11263   try_catch.Reset();
11264
11265   // Check that global variables in the other environment are visible
11266   // when evaluting code.
11267   other->Global()->Set(v8_str("bis"), v8_num(1234));
11268   script = v8_compile("other.eval('bis')");
11269   CHECK_EQ(1234, script->Run()->Int32Value());
11270   CHECK(!try_catch.HasCaught());
11271
11272   // Check that the 'this' pointer points to the global object evaluating
11273   // code.
11274   other->Global()->Set(v8_str("t"), other->Global());
11275   script = v8_compile("other.eval('this == t')");
11276   result = script->Run();
11277   CHECK(result->IsTrue());
11278   CHECK(!try_catch.HasCaught());
11279
11280   // Check that variables introduced in with-statement are not visible in
11281   // other context.
11282   script = v8_compile("with({x:2}){other.eval('x')}");
11283   result = script->Run();
11284   CHECK(try_catch.HasCaught());
11285   try_catch.Reset();
11286
11287   // Check that you cannot use 'eval.call' with another object than the
11288   // current global object.
11289   script = v8_compile("other.y = 1; eval.call(other, 'y')");
11290   result = script->Run();
11291   CHECK(try_catch.HasCaught());
11292 }
11293
11294
11295 // Test that calling eval in a context which has been detached from
11296 // its global throws an exception.  This behavior is consistent with
11297 // other JavaScript implementations.
11298 THREADED_TEST(EvalInDetachedGlobal) {
11299   v8::Isolate* isolate = CcTest::isolate();
11300   v8::HandleScope scope(isolate);
11301
11302   v8::Local<Context> context0 = Context::New(isolate);
11303   v8::Local<Context> context1 = Context::New(isolate);
11304
11305   // Set up function in context0 that uses eval from context0.
11306   context0->Enter();
11307   v8::Handle<v8::Value> fun =
11308       CompileRun("var x = 42;"
11309                  "(function() {"
11310                  "  var e = eval;"
11311                  "  return function(s) { return e(s); }"
11312                  "})()");
11313   context0->Exit();
11314
11315   // Put the function into context1 and call it before and after
11316   // detaching the global.  Before detaching, the call succeeds and
11317   // after detaching and exception is thrown.
11318   context1->Enter();
11319   context1->Global()->Set(v8_str("fun"), fun);
11320   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
11321   CHECK_EQ(42, x_value->Int32Value());
11322   context0->DetachGlobal();
11323   v8::TryCatch catcher;
11324   x_value = CompileRun("fun('x')");
11325   CHECK(x_value.IsEmpty());
11326   CHECK(catcher.HasCaught());
11327   context1->Exit();
11328 }
11329
11330
11331 THREADED_TEST(CrossLazyLoad) {
11332   v8::HandleScope scope(CcTest::isolate());
11333   LocalContext other;
11334   LocalContext current;
11335
11336   Local<String> token = v8_str("<security token>");
11337   other->SetSecurityToken(token);
11338   current->SetSecurityToken(token);
11339
11340   // Set up reference from current to other.
11341   current->Global()->Set(v8_str("other"), other->Global());
11342
11343   // Trigger lazy loading in other context.
11344   Local<Script> script = v8_compile("other.eval('new Date(42)')");
11345   Local<Value> value = script->Run();
11346   CHECK_EQ(42.0, value->NumberValue());
11347 }
11348
11349
11350 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11351   ApiTestFuzzer::Fuzz();
11352   if (args.IsConstructCall()) {
11353     if (args[0]->IsInt32()) {
11354       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
11355       return;
11356     }
11357   }
11358
11359   args.GetReturnValue().Set(args[0]);
11360 }
11361
11362
11363 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
11364   args.GetReturnValue().Set(args.This());
11365 }
11366
11367
11368 // Test that a call handler can be set for objects which will allow
11369 // non-function objects created through the API to be called as
11370 // functions.
11371 THREADED_TEST(CallAsFunction) {
11372   LocalContext context;
11373   v8::Isolate* isolate = context->GetIsolate();
11374   v8::HandleScope scope(isolate);
11375
11376   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11377     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11378     instance_template->SetCallAsFunctionHandler(call_as_function);
11379     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11380     context->Global()->Set(v8_str("obj"), instance);
11381     v8::TryCatch try_catch;
11382     Local<Value> value;
11383     CHECK(!try_catch.HasCaught());
11384
11385     value = CompileRun("obj(42)");
11386     CHECK(!try_catch.HasCaught());
11387     CHECK_EQ(42, value->Int32Value());
11388
11389     value = CompileRun("(function(o){return o(49)})(obj)");
11390     CHECK(!try_catch.HasCaught());
11391     CHECK_EQ(49, value->Int32Value());
11392
11393     // test special case of call as function
11394     value = CompileRun("[obj]['0'](45)");
11395     CHECK(!try_catch.HasCaught());
11396     CHECK_EQ(45, value->Int32Value());
11397
11398     value = CompileRun("obj.call = Function.prototype.call;"
11399                        "obj.call(null, 87)");
11400     CHECK(!try_catch.HasCaught());
11401     CHECK_EQ(87, value->Int32Value());
11402
11403     // Regression tests for bug #1116356: Calling call through call/apply
11404     // must work for non-function receivers.
11405     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11406     value = CompileRun(apply_99);
11407     CHECK(!try_catch.HasCaught());
11408     CHECK_EQ(99, value->Int32Value());
11409
11410     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11411     value = CompileRun(call_17);
11412     CHECK(!try_catch.HasCaught());
11413     CHECK_EQ(17, value->Int32Value());
11414
11415     // Check that the call-as-function handler can be called through
11416     // new.
11417     value = CompileRun("new obj(43)");
11418     CHECK(!try_catch.HasCaught());
11419     CHECK_EQ(-43, value->Int32Value());
11420
11421     // Check that the call-as-function handler can be called through
11422     // the API.
11423     v8::Handle<Value> args[] = { v8_num(28) };
11424     value = instance->CallAsFunction(instance, 1, args);
11425     CHECK(!try_catch.HasCaught());
11426     CHECK_EQ(28, value->Int32Value());
11427   }
11428
11429   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11430     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11431     USE(instance_template);
11432     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11433     context->Global()->Set(v8_str("obj2"), instance);
11434     v8::TryCatch try_catch;
11435     Local<Value> value;
11436     CHECK(!try_catch.HasCaught());
11437
11438     // Call an object without call-as-function handler through the JS
11439     value = CompileRun("obj2(28)");
11440     CHECK(value.IsEmpty());
11441     CHECK(try_catch.HasCaught());
11442     String::Utf8Value exception_value1(try_catch.Exception());
11443     // TODO(verwaest): Better message
11444     CHECK_EQ("TypeError: object is not a function",
11445              *exception_value1);
11446     try_catch.Reset();
11447
11448     // Call an object without call-as-function handler through the API
11449     value = CompileRun("obj2(28)");
11450     v8::Handle<Value> args[] = { v8_num(28) };
11451     value = instance->CallAsFunction(instance, 1, args);
11452     CHECK(value.IsEmpty());
11453     CHECK(try_catch.HasCaught());
11454     String::Utf8Value exception_value2(try_catch.Exception());
11455     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11456     try_catch.Reset();
11457   }
11458
11459   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11460     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11461     instance_template->SetCallAsFunctionHandler(ThrowValue);
11462     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11463     context->Global()->Set(v8_str("obj3"), instance);
11464     v8::TryCatch try_catch;
11465     Local<Value> value;
11466     CHECK(!try_catch.HasCaught());
11467
11468     // Catch the exception which is thrown by call-as-function handler
11469     value = CompileRun("obj3(22)");
11470     CHECK(try_catch.HasCaught());
11471     String::Utf8Value exception_value1(try_catch.Exception());
11472     CHECK_EQ("22", *exception_value1);
11473     try_catch.Reset();
11474
11475     v8::Handle<Value> args[] = { v8_num(23) };
11476     value = instance->CallAsFunction(instance, 1, args);
11477     CHECK(try_catch.HasCaught());
11478     String::Utf8Value exception_value2(try_catch.Exception());
11479     CHECK_EQ("23", *exception_value2);
11480     try_catch.Reset();
11481   }
11482
11483   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11484     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11485     instance_template->SetCallAsFunctionHandler(ReturnThis);
11486     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11487
11488     Local<v8::Value> a1 =
11489         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11490     CHECK(a1->StrictEquals(instance));
11491     Local<v8::Value> a2 =
11492         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11493     CHECK(a2->StrictEquals(instance));
11494     Local<v8::Value> a3 =
11495         instance->CallAsFunction(v8_num(42), 0, NULL);
11496     CHECK(a3->StrictEquals(instance));
11497     Local<v8::Value> a4 =
11498         instance->CallAsFunction(v8_str("hello"), 0, NULL);
11499     CHECK(a4->StrictEquals(instance));
11500     Local<v8::Value> a5 =
11501         instance->CallAsFunction(v8::True(isolate), 0, NULL);
11502     CHECK(a5->StrictEquals(instance));
11503   }
11504
11505   { CompileRun(
11506       "function ReturnThisSloppy() {"
11507       "  return this;"
11508       "}"
11509       "function ReturnThisStrict() {"
11510       "  'use strict';"
11511       "  return this;"
11512       "}");
11513     Local<Function> ReturnThisSloppy =
11514         Local<Function>::Cast(
11515             context->Global()->Get(v8_str("ReturnThisSloppy")));
11516     Local<Function> ReturnThisStrict =
11517         Local<Function>::Cast(
11518             context->Global()->Get(v8_str("ReturnThisStrict")));
11519
11520     Local<v8::Value> a1 =
11521         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11522     CHECK(a1->StrictEquals(context->Global()));
11523     Local<v8::Value> a2 =
11524         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11525     CHECK(a2->StrictEquals(context->Global()));
11526     Local<v8::Value> a3 =
11527         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11528     CHECK(a3->IsNumberObject());
11529     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11530     Local<v8::Value> a4 =
11531         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11532     CHECK(a4->IsStringObject());
11533     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11534     Local<v8::Value> a5 =
11535         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11536     CHECK(a5->IsBooleanObject());
11537     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11538
11539     Local<v8::Value> a6 =
11540         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11541     CHECK(a6->IsUndefined());
11542     Local<v8::Value> a7 =
11543         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11544     CHECK(a7->IsNull());
11545     Local<v8::Value> a8 =
11546         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11547     CHECK(a8->StrictEquals(v8_num(42)));
11548     Local<v8::Value> a9 =
11549         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11550     CHECK(a9->StrictEquals(v8_str("hello")));
11551     Local<v8::Value> a10 =
11552         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11553     CHECK(a10->StrictEquals(v8::True(isolate)));
11554   }
11555 }
11556
11557
11558 // Check whether a non-function object is callable.
11559 THREADED_TEST(CallableObject) {
11560   LocalContext context;
11561   v8::Isolate* isolate = context->GetIsolate();
11562   v8::HandleScope scope(isolate);
11563
11564   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11565     instance_template->SetCallAsFunctionHandler(call_as_function);
11566     Local<Object> instance = instance_template->NewInstance();
11567     v8::TryCatch try_catch;
11568
11569     CHECK(instance->IsCallable());
11570     CHECK(!try_catch.HasCaught());
11571   }
11572
11573   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11574     Local<Object> instance = instance_template->NewInstance();
11575     v8::TryCatch try_catch;
11576
11577     CHECK(!instance->IsCallable());
11578     CHECK(!try_catch.HasCaught());
11579   }
11580
11581   { Local<FunctionTemplate> function_template =
11582         FunctionTemplate::New(isolate, call_as_function);
11583     Local<Function> function = function_template->GetFunction();
11584     Local<Object> instance = function;
11585     v8::TryCatch try_catch;
11586
11587     CHECK(instance->IsCallable());
11588     CHECK(!try_catch.HasCaught());
11589   }
11590
11591   { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11592     Local<Function> function = function_template->GetFunction();
11593     Local<Object> instance = function;
11594     v8::TryCatch try_catch;
11595
11596     CHECK(instance->IsCallable());
11597     CHECK(!try_catch.HasCaught());
11598   }
11599 }
11600
11601
11602 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11603   v8::HandleScope scope(isolate);
11604   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11605   for (int i = 0; i < iterations; i++) {
11606     Local<v8::Number> n(v8::Integer::New(isolate, 42));
11607   }
11608   return Recurse(isolate, depth - 1, iterations);
11609 }
11610
11611
11612 THREADED_TEST(HandleIteration) {
11613   static const int kIterations = 500;
11614   static const int kNesting = 200;
11615   LocalContext context;
11616   v8::Isolate* isolate = context->GetIsolate();
11617   v8::HandleScope scope0(isolate);
11618   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11619   {
11620     v8::HandleScope scope1(isolate);
11621     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11622     for (int i = 0; i < kIterations; i++) {
11623       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11624       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11625     }
11626
11627     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11628     {
11629       v8::HandleScope scope2(CcTest::isolate());
11630       for (int j = 0; j < kIterations; j++) {
11631         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11632         CHECK_EQ(j + 1 + kIterations,
11633                  v8::HandleScope::NumberOfHandles(isolate));
11634       }
11635     }
11636     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11637   }
11638   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11639   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11640 }
11641
11642
11643 static void InterceptorHasOwnPropertyGetter(
11644     Local<String> name,
11645     const v8::PropertyCallbackInfo<v8::Value>& info) {
11646   ApiTestFuzzer::Fuzz();
11647 }
11648
11649
11650 THREADED_TEST(InterceptorHasOwnProperty) {
11651   LocalContext context;
11652   v8::Isolate* isolate = context->GetIsolate();
11653   v8::HandleScope scope(isolate);
11654   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11655   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11656   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11657   Local<Function> function = fun_templ->GetFunction();
11658   context->Global()->Set(v8_str("constructor"), function);
11659   v8::Handle<Value> value = CompileRun(
11660       "var o = new constructor();"
11661       "o.hasOwnProperty('ostehaps');");
11662   CHECK_EQ(false, value->BooleanValue());
11663   value = CompileRun(
11664       "o.ostehaps = 42;"
11665       "o.hasOwnProperty('ostehaps');");
11666   CHECK_EQ(true, value->BooleanValue());
11667   value = CompileRun(
11668       "var p = new constructor();"
11669       "p.hasOwnProperty('ostehaps');");
11670   CHECK_EQ(false, value->BooleanValue());
11671 }
11672
11673
11674 static void InterceptorHasOwnPropertyGetterGC(
11675     Local<String> name,
11676     const v8::PropertyCallbackInfo<v8::Value>& info) {
11677   ApiTestFuzzer::Fuzz();
11678   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11679 }
11680
11681
11682 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11683   LocalContext context;
11684   v8::Isolate* isolate = context->GetIsolate();
11685   v8::HandleScope scope(isolate);
11686   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11687   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11688   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11689   Local<Function> function = fun_templ->GetFunction();
11690   context->Global()->Set(v8_str("constructor"), function);
11691   // Let's first make some stuff so we can be sure to get a good GC.
11692   CompileRun(
11693       "function makestr(size) {"
11694       "  switch (size) {"
11695       "    case 1: return 'f';"
11696       "    case 2: return 'fo';"
11697       "    case 3: return 'foo';"
11698       "  }"
11699       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
11700       "}"
11701       "var x = makestr(12345);"
11702       "x = makestr(31415);"
11703       "x = makestr(23456);");
11704   v8::Handle<Value> value = CompileRun(
11705       "var o = new constructor();"
11706       "o.__proto__ = new String(x);"
11707       "o.hasOwnProperty('ostehaps');");
11708   CHECK_EQ(false, value->BooleanValue());
11709 }
11710
11711
11712 typedef void (*NamedPropertyGetter)(
11713     Local<String> property,
11714     const v8::PropertyCallbackInfo<v8::Value>& info);
11715
11716
11717 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11718                                    const char* source,
11719                                    int expected) {
11720   v8::Isolate* isolate = CcTest::isolate();
11721   v8::HandleScope scope(isolate);
11722   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11723   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11724   LocalContext context;
11725   context->Global()->Set(v8_str("o"), templ->NewInstance());
11726   v8::Handle<Value> value = CompileRun(source);
11727   CHECK_EQ(expected, value->Int32Value());
11728 }
11729
11730
11731 static void InterceptorLoadICGetter(
11732     Local<String> name,
11733     const v8::PropertyCallbackInfo<v8::Value>& info) {
11734   ApiTestFuzzer::Fuzz();
11735   v8::Isolate* isolate = CcTest::isolate();
11736   CHECK_EQ(isolate, info.GetIsolate());
11737   CHECK_EQ(v8_str("data"), info.Data());
11738   CHECK_EQ(v8_str("x"), name);
11739   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11740 }
11741
11742
11743 // This test should hit the load IC for the interceptor case.
11744 THREADED_TEST(InterceptorLoadIC) {
11745   CheckInterceptorLoadIC(InterceptorLoadICGetter,
11746     "var result = 0;"
11747     "for (var i = 0; i < 1000; i++) {"
11748     "  result = o.x;"
11749     "}",
11750     42);
11751 }
11752
11753
11754 // Below go several tests which verify that JITing for various
11755 // configurations of interceptor and explicit fields works fine
11756 // (those cases are special cased to get better performance).
11757
11758 static void InterceptorLoadXICGetter(
11759     Local<String> name,
11760     const v8::PropertyCallbackInfo<v8::Value>& info) {
11761   ApiTestFuzzer::Fuzz();
11762   info.GetReturnValue().Set(
11763       v8_str("x")->Equals(name) ?
11764           v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11765           v8::Handle<v8::Value>());
11766 }
11767
11768
11769 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11770   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11771     "var result = 0;"
11772     "o.y = 239;"
11773     "for (var i = 0; i < 1000; i++) {"
11774     "  result = o.y;"
11775     "}",
11776     239);
11777 }
11778
11779
11780 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11781   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11782     "var result = 0;"
11783     "o.__proto__ = { 'y': 239 };"
11784     "for (var i = 0; i < 1000; i++) {"
11785     "  result = o.y + o.x;"
11786     "}",
11787     239 + 42);
11788 }
11789
11790
11791 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11792   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11793     "var result = 0;"
11794     "o.__proto__.y = 239;"
11795     "for (var i = 0; i < 1000; i++) {"
11796     "  result = o.y + o.x;"
11797     "}",
11798     239 + 42);
11799 }
11800
11801
11802 THREADED_TEST(InterceptorLoadICUndefined) {
11803   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11804     "var result = 0;"
11805     "for (var i = 0; i < 1000; i++) {"
11806     "  result = (o.y == undefined) ? 239 : 42;"
11807     "}",
11808     239);
11809 }
11810
11811
11812 THREADED_TEST(InterceptorLoadICWithOverride) {
11813   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11814     "fst = new Object();  fst.__proto__ = o;"
11815     "snd = new Object();  snd.__proto__ = fst;"
11816     "var result1 = 0;"
11817     "for (var i = 0; i < 1000;  i++) {"
11818     "  result1 = snd.x;"
11819     "}"
11820     "fst.x = 239;"
11821     "var result = 0;"
11822     "for (var i = 0; i < 1000; i++) {"
11823     "  result = snd.x;"
11824     "}"
11825     "result + result1",
11826     239 + 42);
11827 }
11828
11829
11830 // Test the case when we stored field into
11831 // a stub, but interceptor produced value on its own.
11832 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11833   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11834     "proto = new Object();"
11835     "o.__proto__ = proto;"
11836     "proto.x = 239;"
11837     "for (var i = 0; i < 1000; i++) {"
11838     "  o.x;"
11839     // Now it should be ICed and keep a reference to x defined on proto
11840     "}"
11841     "var result = 0;"
11842     "for (var i = 0; i < 1000; i++) {"
11843     "  result += o.x;"
11844     "}"
11845     "result;",
11846     42 * 1000);
11847 }
11848
11849
11850 // Test the case when we stored field into
11851 // a stub, but it got invalidated later on.
11852 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11853   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11854     "proto1 = new Object();"
11855     "proto2 = new Object();"
11856     "o.__proto__ = proto1;"
11857     "proto1.__proto__ = proto2;"
11858     "proto2.y = 239;"
11859     "for (var i = 0; i < 1000; i++) {"
11860     "  o.y;"
11861     // Now it should be ICed and keep a reference to y defined on proto2
11862     "}"
11863     "proto1.y = 42;"
11864     "var result = 0;"
11865     "for (var i = 0; i < 1000; i++) {"
11866     "  result += o.y;"
11867     "}"
11868     "result;",
11869     42 * 1000);
11870 }
11871
11872
11873 static int interceptor_load_not_handled_calls = 0;
11874 static void InterceptorLoadNotHandled(
11875     Local<String> name,
11876     const v8::PropertyCallbackInfo<v8::Value>& info) {
11877   ++interceptor_load_not_handled_calls;
11878 }
11879
11880
11881 // Test how post-interceptor lookups are done in the non-cacheable
11882 // case: the interceptor should not be invoked during this lookup.
11883 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11884   interceptor_load_not_handled_calls = 0;
11885   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11886     "receiver = new Object();"
11887     "receiver.__proto__ = o;"
11888     "proto = new Object();"
11889     "/* Make proto a slow-case object. */"
11890     "for (var i = 0; i < 1000; i++) {"
11891     "  proto[\"xxxxxxxx\" + i] = [];"
11892     "}"
11893     "proto.x = 17;"
11894     "o.__proto__ = proto;"
11895     "var result = 0;"
11896     "for (var i = 0; i < 1000; i++) {"
11897     "  result += receiver.x;"
11898     "}"
11899     "result;",
11900     17 * 1000);
11901   CHECK_EQ(1000, interceptor_load_not_handled_calls);
11902 }
11903
11904
11905 // Test the case when we stored field into
11906 // a stub, but it got invalidated later on due to override on
11907 // global object which is between interceptor and fields' holders.
11908 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11909   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11910     "o.__proto__ = this;"  // set a global to be a proto of o.
11911     "this.__proto__.y = 239;"
11912     "for (var i = 0; i < 10; i++) {"
11913     "  if (o.y != 239) throw 'oops: ' + o.y;"
11914     // Now it should be ICed and keep a reference to y defined on field_holder.
11915     "}"
11916     "this.y = 42;"  // Assign on a global.
11917     "var result = 0;"
11918     "for (var i = 0; i < 10; i++) {"
11919     "  result += o.y;"
11920     "}"
11921     "result;",
11922     42 * 10);
11923 }
11924
11925
11926 static void SetOnThis(Local<String> name,
11927                       Local<Value> value,
11928                       const v8::PropertyCallbackInfo<void>& info) {
11929   Local<Object>::Cast(info.This())->ForceSet(name, value);
11930 }
11931
11932
11933 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11934   v8::Isolate* isolate = CcTest::isolate();
11935   v8::HandleScope scope(isolate);
11936   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11937   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11938   templ->SetAccessor(v8_str("y"), Return239Callback);
11939   LocalContext context;
11940   context->Global()->Set(v8_str("o"), templ->NewInstance());
11941
11942   // Check the case when receiver and interceptor's holder
11943   // are the same objects.
11944   v8::Handle<Value> value = CompileRun(
11945       "var result = 0;"
11946       "for (var i = 0; i < 7; i++) {"
11947       "  result = o.y;"
11948       "}");
11949   CHECK_EQ(239, value->Int32Value());
11950
11951   // Check the case when interceptor's holder is in proto chain
11952   // of receiver.
11953   value = CompileRun(
11954       "r = { __proto__: o };"
11955       "var result = 0;"
11956       "for (var i = 0; i < 7; i++) {"
11957       "  result = r.y;"
11958       "}");
11959   CHECK_EQ(239, value->Int32Value());
11960 }
11961
11962
11963 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11964   v8::Isolate* isolate = CcTest::isolate();
11965   v8::HandleScope scope(isolate);
11966   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11967   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11968   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11969   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11970
11971   LocalContext context;
11972   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11973   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11974
11975   // Check the case when receiver and interceptor's holder
11976   // are the same objects.
11977   v8::Handle<Value> value = CompileRun(
11978       "o.__proto__ = p;"
11979       "var result = 0;"
11980       "for (var i = 0; i < 7; i++) {"
11981       "  result = o.x + o.y;"
11982       "}");
11983   CHECK_EQ(239 + 42, value->Int32Value());
11984
11985   // Check the case when interceptor's holder is in proto chain
11986   // of receiver.
11987   value = CompileRun(
11988       "r = { __proto__: o };"
11989       "var result = 0;"
11990       "for (var i = 0; i < 7; i++) {"
11991       "  result = r.x + r.y;"
11992       "}");
11993   CHECK_EQ(239 + 42, value->Int32Value());
11994 }
11995
11996
11997 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11998   v8::Isolate* isolate = CcTest::isolate();
11999   v8::HandleScope scope(isolate);
12000   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12001   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12002   templ->SetAccessor(v8_str("y"), Return239Callback);
12003
12004   LocalContext context;
12005   context->Global()->Set(v8_str("o"), templ->NewInstance());
12006
12007   v8::Handle<Value> value = CompileRun(
12008     "fst = new Object();  fst.__proto__ = o;"
12009     "snd = new Object();  snd.__proto__ = fst;"
12010     "var result1 = 0;"
12011     "for (var i = 0; i < 7;  i++) {"
12012     "  result1 = snd.x;"
12013     "}"
12014     "fst.x = 239;"
12015     "var result = 0;"
12016     "for (var i = 0; i < 7; i++) {"
12017     "  result = snd.x;"
12018     "}"
12019     "result + result1");
12020   CHECK_EQ(239 + 42, value->Int32Value());
12021 }
12022
12023
12024 // Test the case when we stored callback into
12025 // a stub, but interceptor produced value on its own.
12026 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
12027   v8::Isolate* isolate = CcTest::isolate();
12028   v8::HandleScope scope(isolate);
12029   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12030   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12031   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12032   templ_p->SetAccessor(v8_str("y"), Return239Callback);
12033
12034   LocalContext context;
12035   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12036   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12037
12038   v8::Handle<Value> value = CompileRun(
12039     "o.__proto__ = p;"
12040     "for (var i = 0; i < 7; i++) {"
12041     "  o.x;"
12042     // Now it should be ICed and keep a reference to x defined on p
12043     "}"
12044     "var result = 0;"
12045     "for (var i = 0; i < 7; i++) {"
12046     "  result += o.x;"
12047     "}"
12048     "result");
12049   CHECK_EQ(42 * 7, value->Int32Value());
12050 }
12051
12052
12053 // Test the case when we stored callback into
12054 // a stub, but it got invalidated later on.
12055 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
12056   v8::Isolate* isolate = CcTest::isolate();
12057   v8::HandleScope scope(isolate);
12058   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12059   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12060   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12061   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
12062
12063   LocalContext context;
12064   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12065   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12066
12067   v8::Handle<Value> value = CompileRun(
12068     "inbetween = new Object();"
12069     "o.__proto__ = inbetween;"
12070     "inbetween.__proto__ = p;"
12071     "for (var i = 0; i < 10; i++) {"
12072     "  o.y;"
12073     // Now it should be ICed and keep a reference to y defined on p
12074     "}"
12075     "inbetween.y = 42;"
12076     "var result = 0;"
12077     "for (var i = 0; i < 10; i++) {"
12078     "  result += o.y;"
12079     "}"
12080     "result");
12081   CHECK_EQ(42 * 10, value->Int32Value());
12082 }
12083
12084
12085 // Test the case when we stored callback into
12086 // a stub, but it got invalidated later on due to override on
12087 // global object which is between interceptor and callbacks' holders.
12088 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
12089   v8::Isolate* isolate = CcTest::isolate();
12090   v8::HandleScope scope(isolate);
12091   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12092   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12093   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12094   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
12095
12096   LocalContext context;
12097   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12098   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12099
12100   v8::Handle<Value> value = CompileRun(
12101     "o.__proto__ = this;"
12102     "this.__proto__ = p;"
12103     "for (var i = 0; i < 10; i++) {"
12104     "  if (o.y != 239) throw 'oops: ' + o.y;"
12105     // Now it should be ICed and keep a reference to y defined on p
12106     "}"
12107     "this.y = 42;"
12108     "var result = 0;"
12109     "for (var i = 0; i < 10; i++) {"
12110     "  result += o.y;"
12111     "}"
12112     "result");
12113   CHECK_EQ(42 * 10, value->Int32Value());
12114 }
12115
12116
12117 static void InterceptorLoadICGetter0(
12118     Local<String> name,
12119     const v8::PropertyCallbackInfo<v8::Value>& info) {
12120   ApiTestFuzzer::Fuzz();
12121   CHECK(v8_str("x")->Equals(name));
12122   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
12123 }
12124
12125
12126 THREADED_TEST(InterceptorReturningZero) {
12127   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
12128      "o.x == undefined ? 1 : 0",
12129      0);
12130 }
12131
12132
12133 static void InterceptorStoreICSetter(
12134     Local<String> key,
12135     Local<Value> value,
12136     const v8::PropertyCallbackInfo<v8::Value>& info) {
12137   CHECK(v8_str("x")->Equals(key));
12138   CHECK_EQ(42, value->Int32Value());
12139   info.GetReturnValue().Set(value);
12140 }
12141
12142
12143 // This test should hit the store IC for the interceptor case.
12144 THREADED_TEST(InterceptorStoreIC) {
12145   v8::Isolate* isolate = CcTest::isolate();
12146   v8::HandleScope scope(isolate);
12147   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12148   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
12149                                  InterceptorStoreICSetter,
12150                                  0, 0, 0, v8_str("data"));
12151   LocalContext context;
12152   context->Global()->Set(v8_str("o"), templ->NewInstance());
12153   CompileRun(
12154       "for (var i = 0; i < 1000; i++) {"
12155       "  o.x = 42;"
12156       "}");
12157 }
12158
12159
12160 THREADED_TEST(InterceptorStoreICWithNoSetter) {
12161   v8::Isolate* isolate = CcTest::isolate();
12162   v8::HandleScope scope(isolate);
12163   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12164   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12165   LocalContext context;
12166   context->Global()->Set(v8_str("o"), templ->NewInstance());
12167   v8::Handle<Value> value = CompileRun(
12168     "for (var i = 0; i < 1000; i++) {"
12169     "  o.y = 239;"
12170     "}"
12171     "42 + o.y");
12172   CHECK_EQ(239 + 42, value->Int32Value());
12173 }
12174
12175
12176
12177
12178 v8::Handle<Value> call_ic_function;
12179 v8::Handle<Value> call_ic_function2;
12180 v8::Handle<Value> call_ic_function3;
12181
12182 static void InterceptorCallICGetter(
12183     Local<String> name,
12184     const v8::PropertyCallbackInfo<v8::Value>& info) {
12185   ApiTestFuzzer::Fuzz();
12186   CHECK(v8_str("x")->Equals(name));
12187   info.GetReturnValue().Set(call_ic_function);
12188 }
12189
12190
12191 // This test should hit the call IC for the interceptor case.
12192 THREADED_TEST(InterceptorCallIC) {
12193   v8::Isolate* isolate = CcTest::isolate();
12194   v8::HandleScope scope(isolate);
12195   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12196   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
12197   LocalContext context;
12198   context->Global()->Set(v8_str("o"), templ->NewInstance());
12199   call_ic_function =
12200       v8_compile("function f(x) { return x + 1; }; f")->Run();
12201   v8::Handle<Value> value = CompileRun(
12202     "var result = 0;"
12203     "for (var i = 0; i < 1000; i++) {"
12204     "  result = o.x(41);"
12205     "}");
12206   CHECK_EQ(42, value->Int32Value());
12207 }
12208
12209
12210 // This test checks that if interceptor doesn't provide
12211 // a value, we can fetch regular value.
12212 THREADED_TEST(InterceptorCallICSeesOthers) {
12213   v8::Isolate* isolate = CcTest::isolate();
12214   v8::HandleScope scope(isolate);
12215   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12216   templ->SetNamedPropertyHandler(NoBlockGetterX);
12217   LocalContext context;
12218   context->Global()->Set(v8_str("o"), templ->NewInstance());
12219   v8::Handle<Value> value = CompileRun(
12220     "o.x = function f(x) { return x + 1; };"
12221     "var result = 0;"
12222     "for (var i = 0; i < 7; i++) {"
12223     "  result = o.x(41);"
12224     "}");
12225   CHECK_EQ(42, value->Int32Value());
12226 }
12227
12228
12229 static v8::Handle<Value> call_ic_function4;
12230 static void InterceptorCallICGetter4(
12231     Local<String> name,
12232     const v8::PropertyCallbackInfo<v8::Value>& info) {
12233   ApiTestFuzzer::Fuzz();
12234   CHECK(v8_str("x")->Equals(name));
12235   info.GetReturnValue().Set(call_ic_function4);
12236 }
12237
12238
12239 // This test checks that if interceptor provides a function,
12240 // even if we cached shadowed variant, interceptor's function
12241 // is invoked
12242 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
12243   v8::Isolate* isolate = CcTest::isolate();
12244   v8::HandleScope scope(isolate);
12245   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12246   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
12247   LocalContext context;
12248   context->Global()->Set(v8_str("o"), templ->NewInstance());
12249   call_ic_function4 =
12250       v8_compile("function f(x) { return x - 1; }; f")->Run();
12251   v8::Handle<Value> value = CompileRun(
12252     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
12253     "var result = 0;"
12254     "for (var i = 0; i < 1000; i++) {"
12255     "  result = o.x(42);"
12256     "}");
12257   CHECK_EQ(41, value->Int32Value());
12258 }
12259
12260
12261 // Test the case when we stored cacheable lookup into
12262 // a stub, but it got invalidated later on
12263 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
12264   v8::Isolate* isolate = CcTest::isolate();
12265   v8::HandleScope scope(isolate);
12266   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12267   templ->SetNamedPropertyHandler(NoBlockGetterX);
12268   LocalContext context;
12269   context->Global()->Set(v8_str("o"), templ->NewInstance());
12270   v8::Handle<Value> value = CompileRun(
12271     "proto1 = new Object();"
12272     "proto2 = new Object();"
12273     "o.__proto__ = proto1;"
12274     "proto1.__proto__ = proto2;"
12275     "proto2.y = function(x) { return x + 1; };"
12276     // Invoke it many times to compile a stub
12277     "for (var i = 0; i < 7; i++) {"
12278     "  o.y(42);"
12279     "}"
12280     "proto1.y = function(x) { return x - 1; };"
12281     "var result = 0;"
12282     "for (var i = 0; i < 7; i++) {"
12283     "  result += o.y(42);"
12284     "}");
12285   CHECK_EQ(41 * 7, value->Int32Value());
12286 }
12287
12288
12289 // This test checks that if interceptor doesn't provide a function,
12290 // cached constant function is used
12291 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
12292   v8::Isolate* isolate = CcTest::isolate();
12293   v8::HandleScope scope(isolate);
12294   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12295   templ->SetNamedPropertyHandler(NoBlockGetterX);
12296   LocalContext context;
12297   context->Global()->Set(v8_str("o"), templ->NewInstance());
12298   v8::Handle<Value> value = CompileRun(
12299     "function inc(x) { return x + 1; };"
12300     "inc(1);"
12301     "o.x = inc;"
12302     "var result = 0;"
12303     "for (var i = 0; i < 1000; i++) {"
12304     "  result = o.x(42);"
12305     "}");
12306   CHECK_EQ(43, value->Int32Value());
12307 }
12308
12309
12310 static v8::Handle<Value> call_ic_function5;
12311 static void InterceptorCallICGetter5(
12312     Local<String> name,
12313     const v8::PropertyCallbackInfo<v8::Value>& info) {
12314   ApiTestFuzzer::Fuzz();
12315   if (v8_str("x")->Equals(name))
12316     info.GetReturnValue().Set(call_ic_function5);
12317 }
12318
12319
12320 // This test checks that if interceptor provides a function,
12321 // even if we cached constant function, interceptor's function
12322 // is invoked
12323 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
12324   v8::Isolate* isolate = CcTest::isolate();
12325   v8::HandleScope scope(isolate);
12326   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12327   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
12328   LocalContext context;
12329   context->Global()->Set(v8_str("o"), templ->NewInstance());
12330   call_ic_function5 =
12331       v8_compile("function f(x) { return x - 1; }; f")->Run();
12332   v8::Handle<Value> value = CompileRun(
12333     "function inc(x) { return x + 1; };"
12334     "inc(1);"
12335     "o.x = inc;"
12336     "var result = 0;"
12337     "for (var i = 0; i < 1000; i++) {"
12338     "  result = o.x(42);"
12339     "}");
12340   CHECK_EQ(41, value->Int32Value());
12341 }
12342
12343
12344 static v8::Handle<Value> call_ic_function6;
12345 static void InterceptorCallICGetter6(
12346     Local<String> name,
12347     const v8::PropertyCallbackInfo<v8::Value>& info) {
12348   ApiTestFuzzer::Fuzz();
12349   if (v8_str("x")->Equals(name))
12350     info.GetReturnValue().Set(call_ic_function6);
12351 }
12352
12353
12354 // Same test as above, except the code is wrapped in a function
12355 // to test the optimized compiler.
12356 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
12357   i::FLAG_allow_natives_syntax = true;
12358   v8::Isolate* isolate = CcTest::isolate();
12359   v8::HandleScope scope(isolate);
12360   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12361   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
12362   LocalContext context;
12363   context->Global()->Set(v8_str("o"), templ->NewInstance());
12364   call_ic_function6 =
12365       v8_compile("function f(x) { return x - 1; }; f")->Run();
12366   v8::Handle<Value> value = CompileRun(
12367     "function inc(x) { return x + 1; };"
12368     "inc(1);"
12369     "o.x = inc;"
12370     "function test() {"
12371     "  var result = 0;"
12372     "  for (var i = 0; i < 1000; i++) {"
12373     "    result = o.x(42);"
12374     "  }"
12375     "  return result;"
12376     "};"
12377     "test();"
12378     "test();"
12379     "test();"
12380     "%OptimizeFunctionOnNextCall(test);"
12381     "test()");
12382   CHECK_EQ(41, value->Int32Value());
12383 }
12384
12385
12386 // Test the case when we stored constant function into
12387 // a stub, but it got invalidated later on
12388 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
12389   v8::Isolate* isolate = CcTest::isolate();
12390   v8::HandleScope scope(isolate);
12391   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12392   templ->SetNamedPropertyHandler(NoBlockGetterX);
12393   LocalContext context;
12394   context->Global()->Set(v8_str("o"), templ->NewInstance());
12395   v8::Handle<Value> value = CompileRun(
12396     "function inc(x) { return x + 1; };"
12397     "inc(1);"
12398     "proto1 = new Object();"
12399     "proto2 = new Object();"
12400     "o.__proto__ = proto1;"
12401     "proto1.__proto__ = proto2;"
12402     "proto2.y = inc;"
12403     // Invoke it many times to compile a stub
12404     "for (var i = 0; i < 7; i++) {"
12405     "  o.y(42);"
12406     "}"
12407     "proto1.y = function(x) { return x - 1; };"
12408     "var result = 0;"
12409     "for (var i = 0; i < 7; i++) {"
12410     "  result += o.y(42);"
12411     "}");
12412   CHECK_EQ(41 * 7, value->Int32Value());
12413 }
12414
12415
12416 // Test the case when we stored constant function into
12417 // a stub, but it got invalidated later on due to override on
12418 // global object which is between interceptor and constant function' holders.
12419 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
12420   v8::Isolate* isolate = CcTest::isolate();
12421   v8::HandleScope scope(isolate);
12422   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12423   templ->SetNamedPropertyHandler(NoBlockGetterX);
12424   LocalContext context;
12425   context->Global()->Set(v8_str("o"), templ->NewInstance());
12426   v8::Handle<Value> value = CompileRun(
12427     "function inc(x) { return x + 1; };"
12428     "inc(1);"
12429     "o.__proto__ = this;"
12430     "this.__proto__.y = inc;"
12431     // Invoke it many times to compile a stub
12432     "for (var i = 0; i < 7; i++) {"
12433     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
12434     "}"
12435     "this.y = function(x) { return x - 1; };"
12436     "var result = 0;"
12437     "for (var i = 0; i < 7; i++) {"
12438     "  result += o.y(42);"
12439     "}");
12440   CHECK_EQ(41 * 7, value->Int32Value());
12441 }
12442
12443
12444 // Test the case when actual function to call sits on global object.
12445 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
12446   v8::Isolate* isolate = CcTest::isolate();
12447   v8::HandleScope scope(isolate);
12448   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12449   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12450
12451   LocalContext context;
12452   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12453
12454   v8::Handle<Value> value = CompileRun(
12455     "try {"
12456     "  o.__proto__ = this;"
12457     "  for (var i = 0; i < 10; i++) {"
12458     "    var v = o.parseFloat('239');"
12459     "    if (v != 239) throw v;"
12460       // Now it should be ICed and keep a reference to parseFloat.
12461     "  }"
12462     "  var result = 0;"
12463     "  for (var i = 0; i < 10; i++) {"
12464     "    result += o.parseFloat('239');"
12465     "  }"
12466     "  result"
12467     "} catch(e) {"
12468     "  e"
12469     "};");
12470   CHECK_EQ(239 * 10, value->Int32Value());
12471 }
12472
12473 static void InterceptorCallICFastApi(
12474     Local<String> name,
12475     const v8::PropertyCallbackInfo<v8::Value>& info) {
12476   ApiTestFuzzer::Fuzz();
12477   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12478   int* call_count =
12479       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12480   ++(*call_count);
12481   if ((*call_count) % 20 == 0) {
12482     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12483   }
12484 }
12485
12486 static void FastApiCallback_TrivialSignature(
12487     const v8::FunctionCallbackInfo<v8::Value>& args) {
12488   ApiTestFuzzer::Fuzz();
12489   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12490   v8::Isolate* isolate = CcTest::isolate();
12491   CHECK_EQ(isolate, args.GetIsolate());
12492   CHECK_EQ(args.This(), args.Holder());
12493   CHECK(args.Data()->Equals(v8_str("method_data")));
12494   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12495 }
12496
12497 static void FastApiCallback_SimpleSignature(
12498     const v8::FunctionCallbackInfo<v8::Value>& args) {
12499   ApiTestFuzzer::Fuzz();
12500   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12501   v8::Isolate* isolate = CcTest::isolate();
12502   CHECK_EQ(isolate, args.GetIsolate());
12503   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12504   CHECK(args.Data()->Equals(v8_str("method_data")));
12505   // Note, we're using HasRealNamedProperty instead of Has to avoid
12506   // invoking the interceptor again.
12507   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12508   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12509 }
12510
12511
12512 // Helper to maximize the odds of object moving.
12513 static void GenerateSomeGarbage() {
12514   CompileRun(
12515       "var garbage;"
12516       "for (var i = 0; i < 1000; i++) {"
12517       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12518       "}"
12519       "garbage = undefined;");
12520 }
12521
12522
12523 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12524   static int count = 0;
12525   if (count++ % 3 == 0) {
12526     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12527         // This should move the stub
12528     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
12529   }
12530 }
12531
12532
12533 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12534   LocalContext context;
12535   v8::Isolate* isolate = context->GetIsolate();
12536   v8::HandleScope scope(isolate);
12537   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12538       v8::ObjectTemplate::New(isolate);
12539   nativeobject_templ->Set(isolate, "callback",
12540                           v8::FunctionTemplate::New(isolate,
12541                                                     DirectApiCallback));
12542   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12543   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12544   // call the api function multiple times to ensure direct call stub creation.
12545   CompileRun(
12546         "function f() {"
12547         "  for (var i = 1; i <= 30; i++) {"
12548         "    nativeobject.callback();"
12549         "  }"
12550         "}"
12551         "f();");
12552 }
12553
12554
12555 void ThrowingDirectApiCallback(
12556     const v8::FunctionCallbackInfo<v8::Value>& args) {
12557   args.GetIsolate()->ThrowException(v8_str("g"));
12558 }
12559
12560
12561 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12562   LocalContext context;
12563   v8::Isolate* isolate = context->GetIsolate();
12564   v8::HandleScope scope(isolate);
12565   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12566       v8::ObjectTemplate::New(isolate);
12567   nativeobject_templ->Set(isolate, "callback",
12568                           v8::FunctionTemplate::New(isolate,
12569                                                     ThrowingDirectApiCallback));
12570   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12571   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12572   // call the api function multiple times to ensure direct call stub creation.
12573   v8::Handle<Value> result = CompileRun(
12574       "var result = '';"
12575       "function f() {"
12576       "  for (var i = 1; i <= 5; i++) {"
12577       "    try { nativeobject.callback(); } catch (e) { result += e; }"
12578       "  }"
12579       "}"
12580       "f(); result;");
12581   CHECK_EQ(v8_str("ggggg"), result);
12582 }
12583
12584
12585 static Handle<Value> DoDirectGetter() {
12586   if (++p_getter_count % 3 == 0) {
12587     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12588     GenerateSomeGarbage();
12589   }
12590   return v8_str("Direct Getter Result");
12591 }
12592
12593 static void DirectGetterCallback(
12594     Local<String> name,
12595     const v8::PropertyCallbackInfo<v8::Value>& info) {
12596   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12597   info.GetReturnValue().Set(DoDirectGetter());
12598 }
12599
12600
12601 template<typename Accessor>
12602 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12603   LocalContext context;
12604   v8::Isolate* isolate = context->GetIsolate();
12605   v8::HandleScope scope(isolate);
12606   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12607   obj->SetAccessor(v8_str("p1"), accessor);
12608   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12609   p_getter_count = 0;
12610   v8::Handle<v8::Value> result = CompileRun(
12611       "function f() {"
12612       "  for (var i = 0; i < 30; i++) o1.p1;"
12613       "  return o1.p1"
12614       "}"
12615       "f();");
12616   CHECK_EQ(v8_str("Direct Getter Result"), result);
12617   CHECK_EQ(31, p_getter_count);
12618 }
12619
12620
12621 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12622   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12623 }
12624
12625
12626 void ThrowingDirectGetterCallback(
12627     Local<String> name,
12628     const v8::PropertyCallbackInfo<v8::Value>& info) {
12629   info.GetIsolate()->ThrowException(v8_str("g"));
12630 }
12631
12632
12633 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12634   LocalContext context;
12635   v8::Isolate* isolate = context->GetIsolate();
12636   v8::HandleScope scope(isolate);
12637   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12638   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12639   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12640   v8::Handle<Value> result = CompileRun(
12641       "var result = '';"
12642       "for (var i = 0; i < 5; i++) {"
12643       "    try { o1.p1; } catch (e) { result += e; }"
12644       "}"
12645       "result;");
12646   CHECK_EQ(v8_str("ggggg"), result);
12647 }
12648
12649
12650 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12651   int interceptor_call_count = 0;
12652   v8::Isolate* isolate = CcTest::isolate();
12653   v8::HandleScope scope(isolate);
12654   v8::Handle<v8::FunctionTemplate> fun_templ =
12655       v8::FunctionTemplate::New(isolate);
12656   v8::Handle<v8::FunctionTemplate> method_templ =
12657       v8::FunctionTemplate::New(isolate,
12658                                 FastApiCallback_TrivialSignature,
12659                                 v8_str("method_data"),
12660                                 v8::Handle<v8::Signature>());
12661   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12662   proto_templ->Set(v8_str("method"), method_templ);
12663   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12664   templ->SetNamedPropertyHandler(
12665       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12666       v8::External::New(isolate, &interceptor_call_count));
12667   LocalContext context;
12668   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12669   GenerateSomeGarbage();
12670   context->Global()->Set(v8_str("o"), fun->NewInstance());
12671   CompileRun(
12672       "var result = 0;"
12673       "for (var i = 0; i < 100; i++) {"
12674       "  result = o.method(41);"
12675       "}");
12676   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12677   CHECK_EQ(100, interceptor_call_count);
12678 }
12679
12680
12681 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12682   int interceptor_call_count = 0;
12683   v8::Isolate* isolate = CcTest::isolate();
12684   v8::HandleScope scope(isolate);
12685   v8::Handle<v8::FunctionTemplate> fun_templ =
12686       v8::FunctionTemplate::New(isolate);
12687   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12688       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12689       v8::Signature::New(isolate, fun_templ));
12690   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12691   proto_templ->Set(v8_str("method"), method_templ);
12692   fun_templ->SetHiddenPrototype(true);
12693   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12694   templ->SetNamedPropertyHandler(
12695       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12696       v8::External::New(isolate, &interceptor_call_count));
12697   LocalContext context;
12698   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12699   GenerateSomeGarbage();
12700   context->Global()->Set(v8_str("o"), fun->NewInstance());
12701   CompileRun(
12702       "o.foo = 17;"
12703       "var receiver = {};"
12704       "receiver.__proto__ = o;"
12705       "var result = 0;"
12706       "for (var i = 0; i < 100; i++) {"
12707       "  result = receiver.method(41);"
12708       "}");
12709   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12710   CHECK_EQ(100, interceptor_call_count);
12711 }
12712
12713
12714 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12715   int interceptor_call_count = 0;
12716   v8::Isolate* isolate = CcTest::isolate();
12717   v8::HandleScope scope(isolate);
12718   v8::Handle<v8::FunctionTemplate> fun_templ =
12719       v8::FunctionTemplate::New(isolate);
12720   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12721       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12722       v8::Signature::New(isolate, fun_templ));
12723   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12724   proto_templ->Set(v8_str("method"), method_templ);
12725   fun_templ->SetHiddenPrototype(true);
12726   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12727   templ->SetNamedPropertyHandler(
12728       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12729       v8::External::New(isolate, &interceptor_call_count));
12730   LocalContext context;
12731   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12732   GenerateSomeGarbage();
12733   context->Global()->Set(v8_str("o"), fun->NewInstance());
12734   CompileRun(
12735       "o.foo = 17;"
12736       "var receiver = {};"
12737       "receiver.__proto__ = o;"
12738       "var result = 0;"
12739       "var saved_result = 0;"
12740       "for (var i = 0; i < 100; i++) {"
12741       "  result = receiver.method(41);"
12742       "  if (i == 50) {"
12743       "    saved_result = result;"
12744       "    receiver = {method: function(x) { return x - 1 }};"
12745       "  }"
12746       "}");
12747   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12748   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12749   CHECK_GE(interceptor_call_count, 50);
12750 }
12751
12752
12753 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12754   int interceptor_call_count = 0;
12755   v8::Isolate* isolate = CcTest::isolate();
12756   v8::HandleScope scope(isolate);
12757   v8::Handle<v8::FunctionTemplate> fun_templ =
12758       v8::FunctionTemplate::New(isolate);
12759   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12760       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12761       v8::Signature::New(isolate, fun_templ));
12762   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12763   proto_templ->Set(v8_str("method"), method_templ);
12764   fun_templ->SetHiddenPrototype(true);
12765   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12766   templ->SetNamedPropertyHandler(
12767       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12768       v8::External::New(isolate, &interceptor_call_count));
12769   LocalContext context;
12770   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12771   GenerateSomeGarbage();
12772   context->Global()->Set(v8_str("o"), fun->NewInstance());
12773   CompileRun(
12774       "o.foo = 17;"
12775       "var receiver = {};"
12776       "receiver.__proto__ = o;"
12777       "var result = 0;"
12778       "var saved_result = 0;"
12779       "for (var i = 0; i < 100; i++) {"
12780       "  result = receiver.method(41);"
12781       "  if (i == 50) {"
12782       "    saved_result = result;"
12783       "    o.method = function(x) { return x - 1 };"
12784       "  }"
12785       "}");
12786   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12787   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12788   CHECK_GE(interceptor_call_count, 50);
12789 }
12790
12791
12792 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12793   int interceptor_call_count = 0;
12794   v8::Isolate* isolate = CcTest::isolate();
12795   v8::HandleScope scope(isolate);
12796   v8::Handle<v8::FunctionTemplate> fun_templ =
12797       v8::FunctionTemplate::New(isolate);
12798   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12799       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12800       v8::Signature::New(isolate, fun_templ));
12801   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12802   proto_templ->Set(v8_str("method"), method_templ);
12803   fun_templ->SetHiddenPrototype(true);
12804   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12805   templ->SetNamedPropertyHandler(
12806       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12807       v8::External::New(isolate, &interceptor_call_count));
12808   LocalContext context;
12809   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12810   GenerateSomeGarbage();
12811   context->Global()->Set(v8_str("o"), fun->NewInstance());
12812   v8::TryCatch try_catch;
12813   CompileRun(
12814       "o.foo = 17;"
12815       "var receiver = {};"
12816       "receiver.__proto__ = o;"
12817       "var result = 0;"
12818       "var saved_result = 0;"
12819       "for (var i = 0; i < 100; i++) {"
12820       "  result = receiver.method(41);"
12821       "  if (i == 50) {"
12822       "    saved_result = result;"
12823       "    receiver = 333;"
12824       "  }"
12825       "}");
12826   CHECK(try_catch.HasCaught());
12827   // TODO(verwaest): Adjust message.
12828   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12829            try_catch.Exception()->ToString());
12830   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12831   CHECK_GE(interceptor_call_count, 50);
12832 }
12833
12834
12835 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12836   int interceptor_call_count = 0;
12837   v8::Isolate* isolate = CcTest::isolate();
12838   v8::HandleScope scope(isolate);
12839   v8::Handle<v8::FunctionTemplate> fun_templ =
12840       v8::FunctionTemplate::New(isolate);
12841   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12842       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12843       v8::Signature::New(isolate, fun_templ));
12844   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12845   proto_templ->Set(v8_str("method"), method_templ);
12846   fun_templ->SetHiddenPrototype(true);
12847   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12848   templ->SetNamedPropertyHandler(
12849       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12850       v8::External::New(isolate, &interceptor_call_count));
12851   LocalContext context;
12852   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12853   GenerateSomeGarbage();
12854   context->Global()->Set(v8_str("o"), fun->NewInstance());
12855   v8::TryCatch try_catch;
12856   CompileRun(
12857       "o.foo = 17;"
12858       "var receiver = {};"
12859       "receiver.__proto__ = o;"
12860       "var result = 0;"
12861       "var saved_result = 0;"
12862       "for (var i = 0; i < 100; i++) {"
12863       "  result = receiver.method(41);"
12864       "  if (i == 50) {"
12865       "    saved_result = result;"
12866       "    receiver = {method: receiver.method};"
12867       "  }"
12868       "}");
12869   CHECK(try_catch.HasCaught());
12870   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12871            try_catch.Exception()->ToString());
12872   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12873   CHECK_GE(interceptor_call_count, 50);
12874 }
12875
12876
12877 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12878   v8::Isolate* isolate = CcTest::isolate();
12879   v8::HandleScope scope(isolate);
12880   v8::Handle<v8::FunctionTemplate> fun_templ =
12881       v8::FunctionTemplate::New(isolate);
12882   v8::Handle<v8::FunctionTemplate> method_templ =
12883       v8::FunctionTemplate::New(isolate,
12884                                 FastApiCallback_TrivialSignature,
12885                                 v8_str("method_data"),
12886                                 v8::Handle<v8::Signature>());
12887   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12888   proto_templ->Set(v8_str("method"), method_templ);
12889   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12890   USE(templ);
12891   LocalContext context;
12892   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12893   GenerateSomeGarbage();
12894   context->Global()->Set(v8_str("o"), fun->NewInstance());
12895   CompileRun(
12896       "var result = 0;"
12897       "for (var i = 0; i < 100; i++) {"
12898       "  result = o.method(41);"
12899       "}");
12900
12901   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12902 }
12903
12904
12905 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12906   v8::Isolate* isolate = CcTest::isolate();
12907   v8::HandleScope scope(isolate);
12908   v8::Handle<v8::FunctionTemplate> fun_templ =
12909       v8::FunctionTemplate::New(isolate);
12910   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12911       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12912       v8::Signature::New(isolate, fun_templ));
12913   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12914   proto_templ->Set(v8_str("method"), method_templ);
12915   fun_templ->SetHiddenPrototype(true);
12916   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12917   CHECK(!templ.IsEmpty());
12918   LocalContext context;
12919   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12920   GenerateSomeGarbage();
12921   context->Global()->Set(v8_str("o"), fun->NewInstance());
12922   CompileRun(
12923       "o.foo = 17;"
12924       "var receiver = {};"
12925       "receiver.__proto__ = o;"
12926       "var result = 0;"
12927       "for (var i = 0; i < 100; i++) {"
12928       "  result = receiver.method(41);"
12929       "}");
12930
12931   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12932 }
12933
12934
12935 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12936   v8::Isolate* isolate = CcTest::isolate();
12937   v8::HandleScope scope(isolate);
12938   v8::Handle<v8::FunctionTemplate> fun_templ =
12939       v8::FunctionTemplate::New(isolate);
12940   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12941       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12942       v8::Signature::New(isolate, fun_templ));
12943   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12944   proto_templ->Set(v8_str("method"), method_templ);
12945   fun_templ->SetHiddenPrototype(true);
12946   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12947   CHECK(!templ.IsEmpty());
12948   LocalContext context;
12949   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12950   GenerateSomeGarbage();
12951   context->Global()->Set(v8_str("o"), fun->NewInstance());
12952   CompileRun(
12953       "o.foo = 17;"
12954       "var receiver = {};"
12955       "receiver.__proto__ = o;"
12956       "var result = 0;"
12957       "var saved_result = 0;"
12958       "for (var i = 0; i < 100; i++) {"
12959       "  result = receiver.method(41);"
12960       "  if (i == 50) {"
12961       "    saved_result = result;"
12962       "    receiver = {method: function(x) { return x - 1 }};"
12963       "  }"
12964       "}");
12965   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12966   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12967 }
12968
12969
12970 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12971   v8::Isolate* isolate = CcTest::isolate();
12972   v8::HandleScope scope(isolate);
12973   v8::Handle<v8::FunctionTemplate> fun_templ =
12974       v8::FunctionTemplate::New(isolate);
12975   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12976       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12977       v8::Signature::New(isolate, fun_templ));
12978   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12979   proto_templ->Set(v8_str("method"), method_templ);
12980   fun_templ->SetHiddenPrototype(true);
12981   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12982   CHECK(!templ.IsEmpty());
12983   LocalContext context;
12984   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12985   GenerateSomeGarbage();
12986   context->Global()->Set(v8_str("o"), fun->NewInstance());
12987   v8::TryCatch try_catch;
12988   CompileRun(
12989       "o.foo = 17;"
12990       "var receiver = {};"
12991       "receiver.__proto__ = o;"
12992       "var result = 0;"
12993       "var saved_result = 0;"
12994       "for (var i = 0; i < 100; i++) {"
12995       "  result = receiver.method(41);"
12996       "  if (i == 50) {"
12997       "    saved_result = result;"
12998       "    receiver = 333;"
12999       "  }"
13000       "}");
13001   CHECK(try_catch.HasCaught());
13002   // TODO(verwaest): Adjust message.
13003   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
13004            try_catch.Exception()->ToString());
13005   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13006 }
13007
13008
13009 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
13010   v8::Isolate* isolate = CcTest::isolate();
13011   v8::HandleScope scope(isolate);
13012   v8::Handle<v8::FunctionTemplate> fun_templ =
13013       v8::FunctionTemplate::New(isolate);
13014   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13015       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13016       v8::Signature::New(isolate, fun_templ));
13017   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13018   proto_templ->Set(v8_str("method"), method_templ);
13019   fun_templ->SetHiddenPrototype(true);
13020   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13021   CHECK(!templ.IsEmpty());
13022   LocalContext context;
13023   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13024   GenerateSomeGarbage();
13025   context->Global()->Set(v8_str("o"), fun->NewInstance());
13026   v8::TryCatch try_catch;
13027   CompileRun(
13028       "o.foo = 17;"
13029       "var receiver = {};"
13030       "receiver.__proto__ = o;"
13031       "var result = 0;"
13032       "var saved_result = 0;"
13033       "for (var i = 0; i < 100; i++) {"
13034       "  result = receiver.method(41);"
13035       "  if (i == 50) {"
13036       "    saved_result = result;"
13037       "    receiver = Object.create(receiver);"
13038       "  }"
13039       "}");
13040   CHECK(try_catch.HasCaught());
13041   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
13042            try_catch.Exception()->ToString());
13043   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13044 }
13045
13046
13047 v8::Handle<Value> keyed_call_ic_function;
13048
13049 static void InterceptorKeyedCallICGetter(
13050     Local<String> name,
13051     const v8::PropertyCallbackInfo<v8::Value>& info) {
13052   ApiTestFuzzer::Fuzz();
13053   if (v8_str("x")->Equals(name)) {
13054     info.GetReturnValue().Set(keyed_call_ic_function);
13055   }
13056 }
13057
13058
13059 // Test the case when we stored cacheable lookup into
13060 // a stub, but the function name changed (to another cacheable function).
13061 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
13062   v8::Isolate* isolate = CcTest::isolate();
13063   v8::HandleScope scope(isolate);
13064   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13065   templ->SetNamedPropertyHandler(NoBlockGetterX);
13066   LocalContext context;
13067   context->Global()->Set(v8_str("o"), templ->NewInstance());
13068   CompileRun(
13069     "proto = new Object();"
13070     "proto.y = function(x) { return x + 1; };"
13071     "proto.z = function(x) { return x - 1; };"
13072     "o.__proto__ = proto;"
13073     "var result = 0;"
13074     "var method = 'y';"
13075     "for (var i = 0; i < 10; i++) {"
13076     "  if (i == 5) { method = 'z'; };"
13077     "  result += o[method](41);"
13078     "}");
13079   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13080 }
13081
13082
13083 // Test the case when we stored cacheable lookup into
13084 // a stub, but the function name changed (and the new function is present
13085 // both before and after the interceptor in the prototype chain).
13086 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
13087   v8::Isolate* isolate = CcTest::isolate();
13088   v8::HandleScope scope(isolate);
13089   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13090   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
13091   LocalContext context;
13092   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
13093   keyed_call_ic_function =
13094       v8_compile("function f(x) { return x - 1; }; f")->Run();
13095   CompileRun(
13096     "o = new Object();"
13097     "proto2 = new Object();"
13098     "o.y = function(x) { return x + 1; };"
13099     "proto2.y = function(x) { return x + 2; };"
13100     "o.__proto__ = proto1;"
13101     "proto1.__proto__ = proto2;"
13102     "var result = 0;"
13103     "var method = 'x';"
13104     "for (var i = 0; i < 10; i++) {"
13105     "  if (i == 5) { method = 'y'; };"
13106     "  result += o[method](41);"
13107     "}");
13108   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13109 }
13110
13111
13112 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
13113 // on the global object.
13114 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
13115   v8::Isolate* isolate = CcTest::isolate();
13116   v8::HandleScope scope(isolate);
13117   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13118   templ->SetNamedPropertyHandler(NoBlockGetterX);
13119   LocalContext context;
13120   context->Global()->Set(v8_str("o"), templ->NewInstance());
13121   CompileRun(
13122     "function inc(x) { return x + 1; };"
13123     "inc(1);"
13124     "function dec(x) { return x - 1; };"
13125     "dec(1);"
13126     "o.__proto__ = this;"
13127     "this.__proto__.x = inc;"
13128     "this.__proto__.y = dec;"
13129     "var result = 0;"
13130     "var method = 'x';"
13131     "for (var i = 0; i < 10; i++) {"
13132     "  if (i == 5) { method = 'y'; };"
13133     "  result += o[method](41);"
13134     "}");
13135   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13136 }
13137
13138
13139 // Test the case when actual function to call sits on global object.
13140 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
13141   v8::Isolate* isolate = CcTest::isolate();
13142   v8::HandleScope scope(isolate);
13143   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13144   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
13145   LocalContext context;
13146   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
13147
13148   CompileRun(
13149     "function len(x) { return x.length; };"
13150     "o.__proto__ = this;"
13151     "var m = 'parseFloat';"
13152     "var result = 0;"
13153     "for (var i = 0; i < 10; i++) {"
13154     "  if (i == 5) {"
13155     "    m = 'len';"
13156     "    saved_result = result;"
13157     "  };"
13158     "  result = o[m]('239');"
13159     "}");
13160   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
13161   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13162 }
13163
13164
13165 // Test the map transition before the interceptor.
13166 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
13167   v8::Isolate* isolate = CcTest::isolate();
13168   v8::HandleScope scope(isolate);
13169   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13170   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
13171   LocalContext context;
13172   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
13173
13174   CompileRun(
13175     "var o = new Object();"
13176     "o.__proto__ = proto;"
13177     "o.method = function(x) { return x + 1; };"
13178     "var m = 'method';"
13179     "var result = 0;"
13180     "for (var i = 0; i < 10; i++) {"
13181     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
13182     "  result += o[m](41);"
13183     "}");
13184   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13185 }
13186
13187
13188 // Test the map transition after the interceptor.
13189 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
13190   v8::Isolate* isolate = CcTest::isolate();
13191   v8::HandleScope scope(isolate);
13192   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13193   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
13194   LocalContext context;
13195   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
13196
13197   CompileRun(
13198     "var proto = new Object();"
13199     "o.__proto__ = proto;"
13200     "proto.method = function(x) { return x + 1; };"
13201     "var m = 'method';"
13202     "var result = 0;"
13203     "for (var i = 0; i < 10; i++) {"
13204     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
13205     "  result += o[m](41);"
13206     "}");
13207   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13208 }
13209
13210
13211 static int interceptor_call_count = 0;
13212
13213 static void InterceptorICRefErrorGetter(
13214     Local<String> name,
13215     const v8::PropertyCallbackInfo<v8::Value>& info) {
13216   ApiTestFuzzer::Fuzz();
13217   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
13218     info.GetReturnValue().Set(call_ic_function2);
13219   }
13220 }
13221
13222
13223 // This test should hit load and call ICs for the interceptor case.
13224 // Once in a while, the interceptor will reply that a property was not
13225 // found in which case we should get a reference error.
13226 THREADED_TEST(InterceptorICReferenceErrors) {
13227   v8::Isolate* isolate = CcTest::isolate();
13228   v8::HandleScope scope(isolate);
13229   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13230   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
13231   LocalContext context(0, templ, v8::Handle<Value>());
13232   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
13233   v8::Handle<Value> value = CompileRun(
13234     "function f() {"
13235     "  for (var i = 0; i < 1000; i++) {"
13236     "    try { x; } catch(e) { return true; }"
13237     "  }"
13238     "  return false;"
13239     "};"
13240     "f();");
13241   CHECK_EQ(true, value->BooleanValue());
13242   interceptor_call_count = 0;
13243   value = CompileRun(
13244     "function g() {"
13245     "  for (var i = 0; i < 1000; i++) {"
13246     "    try { x(42); } catch(e) { return true; }"
13247     "  }"
13248     "  return false;"
13249     "};"
13250     "g();");
13251   CHECK_EQ(true, value->BooleanValue());
13252 }
13253
13254
13255 static int interceptor_ic_exception_get_count = 0;
13256
13257 static void InterceptorICExceptionGetter(
13258     Local<String> name,
13259     const v8::PropertyCallbackInfo<v8::Value>& info) {
13260   ApiTestFuzzer::Fuzz();
13261   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
13262     info.GetReturnValue().Set(call_ic_function3);
13263   }
13264   if (interceptor_ic_exception_get_count == 20) {
13265     info.GetIsolate()->ThrowException(v8_num(42));
13266     return;
13267   }
13268 }
13269
13270
13271 // Test interceptor load/call IC where the interceptor throws an
13272 // exception once in a while.
13273 THREADED_TEST(InterceptorICGetterExceptions) {
13274   interceptor_ic_exception_get_count = 0;
13275   v8::Isolate* isolate = CcTest::isolate();
13276   v8::HandleScope scope(isolate);
13277   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13278   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
13279   LocalContext context(0, templ, v8::Handle<Value>());
13280   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
13281   v8::Handle<Value> value = CompileRun(
13282     "function f() {"
13283     "  for (var i = 0; i < 100; i++) {"
13284     "    try { x; } catch(e) { return true; }"
13285     "  }"
13286     "  return false;"
13287     "};"
13288     "f();");
13289   CHECK_EQ(true, value->BooleanValue());
13290   interceptor_ic_exception_get_count = 0;
13291   value = CompileRun(
13292     "function f() {"
13293     "  for (var i = 0; i < 100; i++) {"
13294     "    try { x(42); } catch(e) { return true; }"
13295     "  }"
13296     "  return false;"
13297     "};"
13298     "f();");
13299   CHECK_EQ(true, value->BooleanValue());
13300 }
13301
13302
13303 static int interceptor_ic_exception_set_count = 0;
13304
13305 static void InterceptorICExceptionSetter(
13306       Local<String> key,
13307       Local<Value> value,
13308       const v8::PropertyCallbackInfo<v8::Value>& info) {
13309   ApiTestFuzzer::Fuzz();
13310   if (++interceptor_ic_exception_set_count > 20) {
13311     info.GetIsolate()->ThrowException(v8_num(42));
13312   }
13313 }
13314
13315
13316 // Test interceptor store IC where the interceptor throws an exception
13317 // once in a while.
13318 THREADED_TEST(InterceptorICSetterExceptions) {
13319   interceptor_ic_exception_set_count = 0;
13320   v8::Isolate* isolate = CcTest::isolate();
13321   v8::HandleScope scope(isolate);
13322   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13323   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
13324   LocalContext context(0, templ, v8::Handle<Value>());
13325   v8::Handle<Value> value = CompileRun(
13326     "function f() {"
13327     "  for (var i = 0; i < 100; i++) {"
13328     "    try { x = 42; } catch(e) { return true; }"
13329     "  }"
13330     "  return false;"
13331     "};"
13332     "f();");
13333   CHECK_EQ(true, value->BooleanValue());
13334 }
13335
13336
13337 // Test that we ignore null interceptors.
13338 THREADED_TEST(NullNamedInterceptor) {
13339   v8::Isolate* isolate = CcTest::isolate();
13340   v8::HandleScope scope(isolate);
13341   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13342   templ->SetNamedPropertyHandler(
13343       static_cast<v8::NamedPropertyGetterCallback>(0));
13344   LocalContext context;
13345   templ->Set(CcTest::isolate(), "x", v8_num(42));
13346   v8::Handle<v8::Object> obj = templ->NewInstance();
13347   context->Global()->Set(v8_str("obj"), obj);
13348   v8::Handle<Value> value = CompileRun("obj.x");
13349   CHECK(value->IsInt32());
13350   CHECK_EQ(42, value->Int32Value());
13351 }
13352
13353
13354 // Test that we ignore null interceptors.
13355 THREADED_TEST(NullIndexedInterceptor) {
13356   v8::Isolate* isolate = CcTest::isolate();
13357   v8::HandleScope scope(isolate);
13358   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13359   templ->SetIndexedPropertyHandler(
13360       static_cast<v8::IndexedPropertyGetterCallback>(0));
13361   LocalContext context;
13362   templ->Set(CcTest::isolate(), "42", v8_num(42));
13363   v8::Handle<v8::Object> obj = templ->NewInstance();
13364   context->Global()->Set(v8_str("obj"), obj);
13365   v8::Handle<Value> value = CompileRun("obj[42]");
13366   CHECK(value->IsInt32());
13367   CHECK_EQ(42, value->Int32Value());
13368 }
13369
13370
13371 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
13372   v8::Isolate* isolate = CcTest::isolate();
13373   v8::HandleScope scope(isolate);
13374   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13375   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
13376   LocalContext env;
13377   env->Global()->Set(v8_str("obj"),
13378                      templ->GetFunction()->NewInstance());
13379   ExpectTrue("obj.x === 42");
13380   ExpectTrue("!obj.propertyIsEnumerable('x')");
13381 }
13382
13383
13384 static void ThrowingGetter(Local<String> name,
13385                            const v8::PropertyCallbackInfo<v8::Value>& info) {
13386   ApiTestFuzzer::Fuzz();
13387   info.GetIsolate()->ThrowException(Handle<Value>());
13388   info.GetReturnValue().SetUndefined();
13389 }
13390
13391
13392 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
13393   LocalContext context;
13394   HandleScope scope(context->GetIsolate());
13395
13396   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
13397   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13398   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
13399
13400   Local<Object> instance = templ->GetFunction()->NewInstance();
13401
13402   Local<Object> another = Object::New(context->GetIsolate());
13403   another->SetPrototype(instance);
13404
13405   Local<Object> with_js_getter = CompileRun(
13406       "o = {};\n"
13407       "o.__defineGetter__('f', function() { throw undefined; });\n"
13408       "o\n").As<Object>();
13409   CHECK(!with_js_getter.IsEmpty());
13410
13411   TryCatch try_catch;
13412
13413   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
13414   CHECK(try_catch.HasCaught());
13415   try_catch.Reset();
13416   CHECK(result.IsEmpty());
13417
13418   result = another->GetRealNamedProperty(v8_str("f"));
13419   CHECK(try_catch.HasCaught());
13420   try_catch.Reset();
13421   CHECK(result.IsEmpty());
13422
13423   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
13424   CHECK(try_catch.HasCaught());
13425   try_catch.Reset();
13426   CHECK(result.IsEmpty());
13427
13428   result = another->Get(v8_str("f"));
13429   CHECK(try_catch.HasCaught());
13430   try_catch.Reset();
13431   CHECK(result.IsEmpty());
13432
13433   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
13434   CHECK(try_catch.HasCaught());
13435   try_catch.Reset();
13436   CHECK(result.IsEmpty());
13437
13438   result = with_js_getter->Get(v8_str("f"));
13439   CHECK(try_catch.HasCaught());
13440   try_catch.Reset();
13441   CHECK(result.IsEmpty());
13442 }
13443
13444
13445 static void ThrowingCallbackWithTryCatch(
13446     const v8::FunctionCallbackInfo<v8::Value>& args) {
13447   TryCatch try_catch;
13448   // Verboseness is important: it triggers message delivery which can call into
13449   // external code.
13450   try_catch.SetVerbose(true);
13451   CompileRun("throw 'from JS';");
13452   CHECK(try_catch.HasCaught());
13453   CHECK(!CcTest::i_isolate()->has_pending_exception());
13454   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13455 }
13456
13457
13458 static int call_depth;
13459
13460
13461 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13462   TryCatch try_catch;
13463 }
13464
13465
13466 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13467   if (--call_depth) CompileRun("throw 'ThrowInJS';");
13468 }
13469
13470
13471 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13472   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13473 }
13474
13475
13476 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13477   Handle<String> errorMessageString = message->Get();
13478   CHECK(!errorMessageString.IsEmpty());
13479   message->GetStackTrace();
13480   message->GetScriptOrigin().ResourceName();
13481 }
13482
13483
13484 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13485   LocalContext context;
13486   v8::Isolate* isolate = context->GetIsolate();
13487   HandleScope scope(isolate);
13488
13489   Local<Function> func =
13490       FunctionTemplate::New(isolate,
13491                             ThrowingCallbackWithTryCatch)->GetFunction();
13492   context->Global()->Set(v8_str("func"), func);
13493
13494   MessageCallback callbacks[] =
13495       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13496   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13497     MessageCallback callback = callbacks[i];
13498     if (callback != NULL) {
13499       V8::AddMessageListener(callback);
13500     }
13501     // Some small number to control number of times message handler should
13502     // throw an exception.
13503     call_depth = 5;
13504     ExpectFalse(
13505         "var thrown = false;\n"
13506         "try { func(); } catch(e) { thrown = true; }\n"
13507         "thrown\n");
13508     if (callback != NULL) {
13509       V8::RemoveMessageListeners(callback);
13510     }
13511   }
13512 }
13513
13514
13515 static void ParentGetter(Local<String> name,
13516                          const v8::PropertyCallbackInfo<v8::Value>& info) {
13517   ApiTestFuzzer::Fuzz();
13518   info.GetReturnValue().Set(v8_num(1));
13519 }
13520
13521
13522 static void ChildGetter(Local<String> name,
13523                         const v8::PropertyCallbackInfo<v8::Value>& info) {
13524   ApiTestFuzzer::Fuzz();
13525   info.GetReturnValue().Set(v8_num(42));
13526 }
13527
13528
13529 THREADED_TEST(Overriding) {
13530   LocalContext context;
13531   v8::Isolate* isolate = context->GetIsolate();
13532   v8::HandleScope scope(isolate);
13533
13534   // Parent template.
13535   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13536   Local<ObjectTemplate> parent_instance_templ =
13537       parent_templ->InstanceTemplate();
13538   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13539
13540   // Template that inherits from the parent template.
13541   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13542   Local<ObjectTemplate> child_instance_templ =
13543       child_templ->InstanceTemplate();
13544   child_templ->Inherit(parent_templ);
13545   // Override 'f'.  The child version of 'f' should get called for child
13546   // instances.
13547   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13548   // Add 'g' twice.  The 'g' added last should get called for instances.
13549   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13550   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13551
13552   // Add 'h' as an accessor to the proto template with ReadOnly attributes
13553   // so 'h' can be shadowed on the instance object.
13554   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13555   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13556       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13557
13558   // Add 'i' as an accessor to the instance template with ReadOnly attributes
13559   // but the attribute does not have effect because it is duplicated with
13560   // NULL setter.
13561   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13562       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13563
13564
13565
13566   // Instantiate the child template.
13567   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13568
13569   // Check that the child function overrides the parent one.
13570   context->Global()->Set(v8_str("o"), instance);
13571   Local<Value> value = v8_compile("o.f")->Run();
13572   // Check that the 'g' that was added last is hit.
13573   CHECK_EQ(42, value->Int32Value());
13574   value = v8_compile("o.g")->Run();
13575   CHECK_EQ(42, value->Int32Value());
13576
13577   // Check that 'h' cannot be shadowed.
13578   value = v8_compile("o.h = 3; o.h")->Run();
13579   CHECK_EQ(1, value->Int32Value());
13580
13581   // Check that 'i' cannot be shadowed or changed.
13582   value = v8_compile("o.i = 3; o.i")->Run();
13583   CHECK_EQ(42, value->Int32Value());
13584 }
13585
13586
13587 static void IsConstructHandler(
13588     const v8::FunctionCallbackInfo<v8::Value>& args) {
13589   ApiTestFuzzer::Fuzz();
13590   args.GetReturnValue().Set(args.IsConstructCall());
13591 }
13592
13593
13594 THREADED_TEST(IsConstructCall) {
13595   v8::Isolate* isolate = CcTest::isolate();
13596   v8::HandleScope scope(isolate);
13597
13598   // Function template with call handler.
13599   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13600   templ->SetCallHandler(IsConstructHandler);
13601
13602   LocalContext context;
13603
13604   context->Global()->Set(v8_str("f"), templ->GetFunction());
13605   Local<Value> value = v8_compile("f()")->Run();
13606   CHECK(!value->BooleanValue());
13607   value = v8_compile("new f()")->Run();
13608   CHECK(value->BooleanValue());
13609 }
13610
13611
13612 THREADED_TEST(ObjectProtoToString) {
13613   v8::Isolate* isolate = CcTest::isolate();
13614   v8::HandleScope scope(isolate);
13615   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13616   templ->SetClassName(v8_str("MyClass"));
13617
13618   LocalContext context;
13619
13620   Local<String> customized_tostring = v8_str("customized toString");
13621
13622   // Replace Object.prototype.toString
13623   v8_compile("Object.prototype.toString = function() {"
13624                   "  return 'customized toString';"
13625                   "}")->Run();
13626
13627   // Normal ToString call should call replaced Object.prototype.toString
13628   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13629   Local<String> value = instance->ToString();
13630   CHECK(value->IsString() && value->Equals(customized_tostring));
13631
13632   // ObjectProtoToString should not call replace toString function.
13633   value = instance->ObjectProtoToString();
13634   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13635
13636   // Check global
13637   value = context->Global()->ObjectProtoToString();
13638   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13639
13640   // Check ordinary object
13641   Local<Value> object = v8_compile("new Object()")->Run();
13642   value = object.As<v8::Object>()->ObjectProtoToString();
13643   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13644 }
13645
13646
13647 TEST(ObjectProtoToStringES6) {
13648   // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
13649   i::FLAG_harmony_tostring = true;
13650   LocalContext context;
13651   v8::Isolate* isolate = CcTest::isolate();
13652   v8::HandleScope scope(isolate);
13653   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13654   templ->SetClassName(v8_str("MyClass"));
13655
13656   Local<String> customized_tostring = v8_str("customized toString");
13657
13658   // Replace Object.prototype.toString
13659   CompileRun(
13660       "Object.prototype.toString = function() {"
13661       "  return 'customized toString';"
13662       "}");
13663
13664   // Normal ToString call should call replaced Object.prototype.toString
13665   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13666   Local<String> value = instance->ToString();
13667   CHECK(value->IsString() && value->Equals(customized_tostring));
13668
13669   // ObjectProtoToString should not call replace toString function.
13670   value = instance->ObjectProtoToString();
13671   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13672
13673   // Check global
13674   value = context->Global()->ObjectProtoToString();
13675   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13676
13677   // Check ordinary object
13678   Local<Value> object = CompileRun("new Object()");
13679   value = object.As<v8::Object>()->ObjectProtoToString();
13680   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13681
13682   // Check that ES6 semantics using @@toStringTag work
13683   Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
13684
13685 #define TEST_TOSTRINGTAG(type, tag, expected)                \
13686   do {                                                       \
13687     object = CompileRun("new " #type "()");                  \
13688     object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
13689     value = object.As<v8::Object>()->ObjectProtoToString();  \
13690     CHECK(value->IsString() &&                               \
13691           value->Equals(v8_str("[object " #expected "]")));  \
13692   } while (0)
13693
13694   TEST_TOSTRINGTAG(Array, Object, Object);
13695   TEST_TOSTRINGTAG(Object, Arguments, ~Arguments);
13696   TEST_TOSTRINGTAG(Object, Array, ~Array);
13697   TEST_TOSTRINGTAG(Object, Boolean, ~Boolean);
13698   TEST_TOSTRINGTAG(Object, Date, ~Date);
13699   TEST_TOSTRINGTAG(Object, Error, ~Error);
13700   TEST_TOSTRINGTAG(Object, Function, ~Function);
13701   TEST_TOSTRINGTAG(Object, Number, ~Number);
13702   TEST_TOSTRINGTAG(Object, RegExp, ~RegExp);
13703   TEST_TOSTRINGTAG(Object, String, ~String);
13704   TEST_TOSTRINGTAG(Object, Foo, Foo);
13705
13706 #undef TEST_TOSTRINGTAG
13707
13708   // @@toStringTag getter throws
13709   Local<Value> obj = v8::Object::New(isolate);
13710   obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
13711   {
13712     TryCatch try_catch;
13713     value = obj.As<v8::Object>()->ObjectProtoToString();
13714     CHECK(value.IsEmpty());
13715     CHECK(try_catch.HasCaught());
13716   }
13717
13718   // @@toStringTag getter does not throw
13719   obj = v8::Object::New(isolate);
13720   obj.As<v8::Object>()->SetAccessor(
13721       toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
13722   {
13723     TryCatch try_catch;
13724     value = obj.As<v8::Object>()->ObjectProtoToString();
13725     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
13726     CHECK(!try_catch.HasCaught());
13727   }
13728
13729   // JS @@toStringTag value
13730   obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
13731   {
13732     TryCatch try_catch;
13733     value = obj.As<v8::Object>()->ObjectProtoToString();
13734     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
13735     CHECK(!try_catch.HasCaught());
13736   }
13737
13738   // JS @@toStringTag getter throws
13739   obj = CompileRun(
13740       "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13741       "  get: function() { throw 'Test'; }"
13742       "}); obj");
13743   {
13744     TryCatch try_catch;
13745     value = obj.As<v8::Object>()->ObjectProtoToString();
13746     CHECK(value.IsEmpty());
13747     CHECK(try_catch.HasCaught());
13748   }
13749
13750   // JS @@toStringTag getter does not throw
13751   obj = CompileRun(
13752       "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13753       "  get: function() { return 'Test'; }"
13754       "}); obj");
13755   {
13756     TryCatch try_catch;
13757     value = obj.As<v8::Object>()->ObjectProtoToString();
13758     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
13759     CHECK(!try_catch.HasCaught());
13760   }
13761 }
13762
13763
13764 THREADED_TEST(ObjectGetConstructorName) {
13765   LocalContext context;
13766   v8::HandleScope scope(context->GetIsolate());
13767   v8_compile("function Parent() {};"
13768              "function Child() {};"
13769              "Child.prototype = new Parent();"
13770              "var outer = { inner: function() { } };"
13771              "var p = new Parent();"
13772              "var c = new Child();"
13773              "var x = new outer.inner();")->Run();
13774
13775   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13776   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13777       v8_str("Parent")));
13778
13779   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13780   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13781       v8_str("Child")));
13782
13783   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13784   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13785       v8_str("outer.inner")));
13786 }
13787
13788
13789 bool ApiTestFuzzer::fuzzing_ = false;
13790 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13791 int ApiTestFuzzer::active_tests_;
13792 int ApiTestFuzzer::tests_being_run_;
13793 int ApiTestFuzzer::current_;
13794
13795
13796 // We are in a callback and want to switch to another thread (if we
13797 // are currently running the thread fuzzing test).
13798 void ApiTestFuzzer::Fuzz() {
13799   if (!fuzzing_) return;
13800   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13801   test->ContextSwitch();
13802 }
13803
13804
13805 // Let the next thread go.  Since it is also waiting on the V8 lock it may
13806 // not start immediately.
13807 bool ApiTestFuzzer::NextThread() {
13808   int test_position = GetNextTestNumber();
13809   const char* test_name = RegisterThreadedTest::nth(current_)->name();
13810   if (test_position == current_) {
13811     if (kLogThreading)
13812       printf("Stay with %s\n", test_name);
13813     return false;
13814   }
13815   if (kLogThreading) {
13816     printf("Switch from %s to %s\n",
13817            test_name,
13818            RegisterThreadedTest::nth(test_position)->name());
13819   }
13820   current_ = test_position;
13821   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13822   return true;
13823 }
13824
13825
13826 void ApiTestFuzzer::Run() {
13827   // When it is our turn...
13828   gate_.Wait();
13829   {
13830     // ... get the V8 lock and start running the test.
13831     v8::Locker locker(CcTest::isolate());
13832     CallTest();
13833   }
13834   // This test finished.
13835   active_ = false;
13836   active_tests_--;
13837   // If it was the last then signal that fact.
13838   if (active_tests_ == 0) {
13839     all_tests_done_.Signal();
13840   } else {
13841     // Otherwise select a new test and start that.
13842     NextThread();
13843   }
13844 }
13845
13846
13847 static unsigned linear_congruential_generator;
13848
13849
13850 void ApiTestFuzzer::SetUp(PartOfTest part) {
13851   linear_congruential_generator = i::FLAG_testing_prng_seed;
13852   fuzzing_ = true;
13853   int count = RegisterThreadedTest::count();
13854   int start =  count * part / (LAST_PART + 1);
13855   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13856   active_tests_ = tests_being_run_ = end - start + 1;
13857   for (int i = 0; i < tests_being_run_; i++) {
13858     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13859   }
13860   for (int i = 0; i < active_tests_; i++) {
13861     RegisterThreadedTest::nth(i)->fuzzer_->Start();
13862   }
13863 }
13864
13865
13866 static void CallTestNumber(int test_number) {
13867   (RegisterThreadedTest::nth(test_number)->callback())();
13868 }
13869
13870
13871 void ApiTestFuzzer::RunAllTests() {
13872   // Set off the first test.
13873   current_ = -1;
13874   NextThread();
13875   // Wait till they are all done.
13876   all_tests_done_.Wait();
13877 }
13878
13879
13880 int ApiTestFuzzer::GetNextTestNumber() {
13881   int next_test;
13882   do {
13883     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13884     linear_congruential_generator *= 1664525u;
13885     linear_congruential_generator += 1013904223u;
13886   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13887   return next_test;
13888 }
13889
13890
13891 void ApiTestFuzzer::ContextSwitch() {
13892   // If the new thread is the same as the current thread there is nothing to do.
13893   if (NextThread()) {
13894     // Now it can start.
13895     v8::Unlocker unlocker(CcTest::isolate());
13896     // Wait till someone starts us again.
13897     gate_.Wait();
13898     // And we're off.
13899   }
13900 }
13901
13902
13903 void ApiTestFuzzer::TearDown() {
13904   fuzzing_ = false;
13905   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13906     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13907     if (fuzzer != NULL) fuzzer->Join();
13908   }
13909 }
13910
13911
13912 // Lets not be needlessly self-referential.
13913 TEST(Threading1) {
13914   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13915   ApiTestFuzzer::RunAllTests();
13916   ApiTestFuzzer::TearDown();
13917 }
13918
13919
13920 TEST(Threading2) {
13921   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13922   ApiTestFuzzer::RunAllTests();
13923   ApiTestFuzzer::TearDown();
13924 }
13925
13926
13927 TEST(Threading3) {
13928   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13929   ApiTestFuzzer::RunAllTests();
13930   ApiTestFuzzer::TearDown();
13931 }
13932
13933
13934 TEST(Threading4) {
13935   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13936   ApiTestFuzzer::RunAllTests();
13937   ApiTestFuzzer::TearDown();
13938 }
13939
13940
13941 void ApiTestFuzzer::CallTest() {
13942   v8::Isolate::Scope scope(CcTest::isolate());
13943   if (kLogThreading)
13944     printf("Start test %d\n", test_number_);
13945   CallTestNumber(test_number_);
13946   if (kLogThreading)
13947     printf("End test %d\n", test_number_);
13948 }
13949
13950
13951 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13952   v8::Isolate* isolate = args.GetIsolate();
13953   CHECK(v8::Locker::IsLocked(isolate));
13954   ApiTestFuzzer::Fuzz();
13955   v8::Unlocker unlocker(isolate);
13956   const char* code = "throw 7;";
13957   {
13958     v8::Locker nested_locker(isolate);
13959     v8::HandleScope scope(isolate);
13960     v8::Handle<Value> exception;
13961     { v8::TryCatch try_catch;
13962       v8::Handle<Value> value = CompileRun(code);
13963       CHECK(value.IsEmpty());
13964       CHECK(try_catch.HasCaught());
13965       // Make sure to wrap the exception in a new handle because
13966       // the handle returned from the TryCatch is destroyed
13967       // when the TryCatch is destroyed.
13968       exception = Local<Value>::New(isolate, try_catch.Exception());
13969     }
13970     args.GetIsolate()->ThrowException(exception);
13971   }
13972 }
13973
13974
13975 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13976   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13977   ApiTestFuzzer::Fuzz();
13978   v8::Unlocker unlocker(CcTest::isolate());
13979   const char* code = "throw 7;";
13980   {
13981     v8::Locker nested_locker(CcTest::isolate());
13982     v8::HandleScope scope(args.GetIsolate());
13983     v8::Handle<Value> value = CompileRun(code);
13984     CHECK(value.IsEmpty());
13985     args.GetReturnValue().Set(v8_str("foo"));
13986   }
13987 }
13988
13989
13990 // These are locking tests that don't need to be run again
13991 // as part of the locking aggregation tests.
13992 TEST(NestedLockers) {
13993   v8::Isolate* isolate = CcTest::isolate();
13994   v8::Locker locker(isolate);
13995   CHECK(v8::Locker::IsLocked(isolate));
13996   LocalContext env;
13997   v8::HandleScope scope(env->GetIsolate());
13998   Local<v8::FunctionTemplate> fun_templ =
13999       v8::FunctionTemplate::New(isolate, ThrowInJS);
14000   Local<Function> fun = fun_templ->GetFunction();
14001   env->Global()->Set(v8_str("throw_in_js"), fun);
14002   Local<Script> script = v8_compile("(function () {"
14003                                     "  try {"
14004                                     "    throw_in_js();"
14005                                     "    return 42;"
14006                                     "  } catch (e) {"
14007                                     "    return e * 13;"
14008                                     "  }"
14009                                     "})();");
14010   CHECK_EQ(91, script->Run()->Int32Value());
14011 }
14012
14013
14014 // These are locking tests that don't need to be run again
14015 // as part of the locking aggregation tests.
14016 TEST(NestedLockersNoTryCatch) {
14017   v8::Locker locker(CcTest::isolate());
14018   LocalContext env;
14019   v8::HandleScope scope(env->GetIsolate());
14020   Local<v8::FunctionTemplate> fun_templ =
14021       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
14022   Local<Function> fun = fun_templ->GetFunction();
14023   env->Global()->Set(v8_str("throw_in_js"), fun);
14024   Local<Script> script = v8_compile("(function () {"
14025                                     "  try {"
14026                                     "    throw_in_js();"
14027                                     "    return 42;"
14028                                     "  } catch (e) {"
14029                                     "    return e * 13;"
14030                                     "  }"
14031                                     "})();");
14032   CHECK_EQ(91, script->Run()->Int32Value());
14033 }
14034
14035
14036 THREADED_TEST(RecursiveLocking) {
14037   v8::Locker locker(CcTest::isolate());
14038   {
14039     v8::Locker locker2(CcTest::isolate());
14040     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
14041   }
14042 }
14043
14044
14045 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
14046   ApiTestFuzzer::Fuzz();
14047   v8::Unlocker unlocker(CcTest::isolate());
14048 }
14049
14050
14051 THREADED_TEST(LockUnlockLock) {
14052   {
14053     v8::Locker locker(CcTest::isolate());
14054     v8::HandleScope scope(CcTest::isolate());
14055     LocalContext env;
14056     Local<v8::FunctionTemplate> fun_templ =
14057         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
14058     Local<Function> fun = fun_templ->GetFunction();
14059     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
14060     Local<Script> script = v8_compile("(function () {"
14061                                       "  unlock_for_a_moment();"
14062                                       "  return 42;"
14063                                       "})();");
14064     CHECK_EQ(42, script->Run()->Int32Value());
14065   }
14066   {
14067     v8::Locker locker(CcTest::isolate());
14068     v8::HandleScope scope(CcTest::isolate());
14069     LocalContext env;
14070     Local<v8::FunctionTemplate> fun_templ =
14071         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
14072     Local<Function> fun = fun_templ->GetFunction();
14073     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
14074     Local<Script> script = v8_compile("(function () {"
14075                                       "  unlock_for_a_moment();"
14076                                       "  return 42;"
14077                                       "})();");
14078     CHECK_EQ(42, script->Run()->Int32Value());
14079   }
14080 }
14081
14082
14083 static int GetGlobalObjectsCount() {
14084   int count = 0;
14085   i::HeapIterator it(CcTest::heap());
14086   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
14087     if (object->IsJSGlobalObject()) count++;
14088   return count;
14089 }
14090
14091
14092 static void CheckSurvivingGlobalObjectsCount(int expected) {
14093   // We need to collect all garbage twice to be sure that everything
14094   // has been collected.  This is because inline caches are cleared in
14095   // the first garbage collection but some of the maps have already
14096   // been marked at that point.  Therefore some of the maps are not
14097   // collected until the second garbage collection.
14098   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14099   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
14100   int count = GetGlobalObjectsCount();
14101 #ifdef DEBUG
14102   if (count != expected) CcTest::heap()->TracePathToGlobal();
14103 #endif
14104   CHECK_EQ(expected, count);
14105 }
14106
14107
14108 TEST(DontLeakGlobalObjects) {
14109   // Regression test for issues 1139850 and 1174891.
14110
14111   i::FLAG_expose_gc = true;
14112   v8::V8::Initialize();
14113
14114   for (int i = 0; i < 5; i++) {
14115     { v8::HandleScope scope(CcTest::isolate());
14116       LocalContext context;
14117     }
14118     CcTest::isolate()->ContextDisposedNotification();
14119     CheckSurvivingGlobalObjectsCount(0);
14120
14121     { v8::HandleScope scope(CcTest::isolate());
14122       LocalContext context;
14123       v8_compile("Date")->Run();
14124     }
14125     CcTest::isolate()->ContextDisposedNotification();
14126     CheckSurvivingGlobalObjectsCount(0);
14127
14128     { v8::HandleScope scope(CcTest::isolate());
14129       LocalContext context;
14130       v8_compile("/aaa/")->Run();
14131     }
14132     CcTest::isolate()->ContextDisposedNotification();
14133     CheckSurvivingGlobalObjectsCount(0);
14134
14135     { v8::HandleScope scope(CcTest::isolate());
14136       const char* extension_list[] = { "v8/gc" };
14137       v8::ExtensionConfiguration extensions(1, extension_list);
14138       LocalContext context(&extensions);
14139       v8_compile("gc();")->Run();
14140     }
14141     CcTest::isolate()->ContextDisposedNotification();
14142     CheckSurvivingGlobalObjectsCount(0);
14143   }
14144 }
14145
14146
14147 TEST(CopyablePersistent) {
14148   LocalContext context;
14149   v8::Isolate* isolate = context->GetIsolate();
14150   i::GlobalHandles* globals =
14151       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14152   int initial_handles = globals->global_handles_count();
14153   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
14154       CopyableObject;
14155   {
14156     CopyableObject handle1;
14157     {
14158       v8::HandleScope scope(isolate);
14159       handle1.Reset(isolate, v8::Object::New(isolate));
14160     }
14161     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
14162     CopyableObject  handle2;
14163     handle2 = handle1;
14164     CHECK(handle1 == handle2);
14165     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
14166     CopyableObject handle3(handle2);
14167     CHECK(handle1 == handle3);
14168     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
14169   }
14170   // Verify autodispose
14171   CHECK_EQ(initial_handles, globals->global_handles_count());
14172 }
14173
14174
14175 static void WeakApiCallback(
14176     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
14177   Local<Value> value = data.GetValue()->Get(v8_str("key"));
14178   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
14179   data.GetParameter()->Reset();
14180   delete data.GetParameter();
14181 }
14182
14183
14184 TEST(WeakCallbackApi) {
14185   LocalContext context;
14186   v8::Isolate* isolate = context->GetIsolate();
14187   i::GlobalHandles* globals =
14188       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14189   int initial_handles = globals->global_handles_count();
14190   {
14191     v8::HandleScope scope(isolate);
14192     v8::Local<v8::Object> obj = v8::Object::New(isolate);
14193     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
14194     v8::Persistent<v8::Object>* handle =
14195         new v8::Persistent<v8::Object>(isolate, obj);
14196     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
14197                                                              WeakApiCallback);
14198   }
14199   reinterpret_cast<i::Isolate*>(isolate)->heap()->
14200       CollectAllGarbage(i::Heap::kNoGCFlags);
14201   // Verify disposed.
14202   CHECK_EQ(initial_handles, globals->global_handles_count());
14203 }
14204
14205
14206 v8::Persistent<v8::Object> some_object;
14207 v8::Persistent<v8::Object> bad_handle;
14208
14209 void NewPersistentHandleCallback(
14210     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14211   v8::HandleScope scope(data.GetIsolate());
14212   bad_handle.Reset(data.GetIsolate(), some_object);
14213   data.GetParameter()->Reset();
14214 }
14215
14216
14217 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
14218   LocalContext context;
14219   v8::Isolate* isolate = context->GetIsolate();
14220
14221   v8::Persistent<v8::Object> handle1, handle2;
14222   {
14223     v8::HandleScope scope(isolate);
14224     some_object.Reset(isolate, v8::Object::New(isolate));
14225     handle1.Reset(isolate, v8::Object::New(isolate));
14226     handle2.Reset(isolate, v8::Object::New(isolate));
14227   }
14228   // Note: order is implementation dependent alas: currently
14229   // global handle nodes are processed by PostGarbageCollectionProcessing
14230   // in reverse allocation order, so if second allocated handle is deleted,
14231   // weak callback of the first handle would be able to 'reallocate' it.
14232   handle1.SetWeak(&handle1, NewPersistentHandleCallback);
14233   handle2.Reset();
14234   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14235 }
14236
14237
14238 v8::Persistent<v8::Object> to_be_disposed;
14239
14240 void DisposeAndForceGcCallback(
14241     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14242   to_be_disposed.Reset();
14243   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14244   data.GetParameter()->Reset();
14245 }
14246
14247
14248 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
14249   LocalContext context;
14250   v8::Isolate* isolate = context->GetIsolate();
14251
14252   v8::Persistent<v8::Object> handle1, handle2;
14253   {
14254     v8::HandleScope scope(isolate);
14255     handle1.Reset(isolate, v8::Object::New(isolate));
14256     handle2.Reset(isolate, v8::Object::New(isolate));
14257   }
14258   handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
14259   to_be_disposed.Reset(isolate, handle2);
14260   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14261 }
14262
14263 void DisposingCallback(
14264     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14265   data.GetParameter()->Reset();
14266 }
14267
14268 void HandleCreatingCallback(
14269     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14270   v8::HandleScope scope(data.GetIsolate());
14271   v8::Persistent<v8::Object>(data.GetIsolate(),
14272                              v8::Object::New(data.GetIsolate()));
14273   data.GetParameter()->Reset();
14274 }
14275
14276
14277 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
14278   LocalContext context;
14279   v8::Isolate* isolate = context->GetIsolate();
14280
14281   v8::Persistent<v8::Object> handle1, handle2, handle3;
14282   {
14283     v8::HandleScope scope(isolate);
14284     handle3.Reset(isolate, v8::Object::New(isolate));
14285     handle2.Reset(isolate, v8::Object::New(isolate));
14286     handle1.Reset(isolate, v8::Object::New(isolate));
14287   }
14288   handle2.SetWeak(&handle2, DisposingCallback);
14289   handle3.SetWeak(&handle3, HandleCreatingCallback);
14290   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14291 }
14292
14293
14294 THREADED_TEST(CheckForCrossContextObjectLiterals) {
14295   v8::V8::Initialize();
14296
14297   const int nof = 2;
14298   const char* sources[nof] = {
14299     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
14300     "Object()"
14301   };
14302
14303   for (int i = 0; i < nof; i++) {
14304     const char* source = sources[i];
14305     { v8::HandleScope scope(CcTest::isolate());
14306       LocalContext context;
14307       CompileRun(source);
14308     }
14309     { v8::HandleScope scope(CcTest::isolate());
14310       LocalContext context;
14311       CompileRun(source);
14312     }
14313   }
14314 }
14315
14316
14317 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
14318   v8::EscapableHandleScope inner(env->GetIsolate());
14319   env->Enter();
14320   v8::Local<Value> three = v8_num(3);
14321   v8::Local<Value> value = inner.Escape(three);
14322   env->Exit();
14323   return value;
14324 }
14325
14326
14327 THREADED_TEST(NestedHandleScopeAndContexts) {
14328   v8::Isolate* isolate = CcTest::isolate();
14329   v8::HandleScope outer(isolate);
14330   v8::Local<Context> env = Context::New(isolate);
14331   env->Enter();
14332   v8::Handle<Value> value = NestedScope(env);
14333   v8::Handle<String> str(value->ToString());
14334   CHECK(!str.IsEmpty());
14335   env->Exit();
14336 }
14337
14338
14339 static bool MatchPointers(void* key1, void* key2) {
14340   return key1 == key2;
14341 }
14342
14343
14344 struct SymbolInfo {
14345   size_t id;
14346   size_t size;
14347   std::string name;
14348 };
14349
14350
14351 class SetFunctionEntryHookTest {
14352  public:
14353   SetFunctionEntryHookTest() {
14354     CHECK(instance_ == NULL);
14355     instance_ = this;
14356   }
14357   ~SetFunctionEntryHookTest() {
14358     CHECK(instance_ == this);
14359     instance_ = NULL;
14360   }
14361   void Reset() {
14362     symbols_.clear();
14363     symbol_locations_.clear();
14364     invocations_.clear();
14365   }
14366   void RunTest();
14367   void OnJitEvent(const v8::JitCodeEvent* event);
14368   static void JitEvent(const v8::JitCodeEvent* event) {
14369     CHECK(instance_ != NULL);
14370     instance_->OnJitEvent(event);
14371   }
14372
14373   void OnEntryHook(uintptr_t function,
14374                    uintptr_t return_addr_location);
14375   static void EntryHook(uintptr_t function,
14376                         uintptr_t return_addr_location) {
14377     CHECK(instance_ != NULL);
14378     instance_->OnEntryHook(function, return_addr_location);
14379   }
14380
14381   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
14382     CHECK(instance_ != NULL);
14383     args.GetReturnValue().Set(v8_num(42));
14384   }
14385   void RunLoopInNewEnv(v8::Isolate* isolate);
14386
14387   // Records addr as location of symbol.
14388   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
14389
14390   // Finds the symbol containing addr
14391   SymbolInfo* FindSymbolForAddr(i::Address addr);
14392   // Returns the number of invocations where the caller name contains
14393   // \p caller_name and the function name contains \p function_name.
14394   int CountInvocations(const char* caller_name,
14395                        const char* function_name);
14396
14397   i::Handle<i::JSFunction> foo_func_;
14398   i::Handle<i::JSFunction> bar_func_;
14399
14400   typedef std::map<size_t, SymbolInfo> SymbolMap;
14401   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
14402   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
14403   SymbolMap symbols_;
14404   SymbolLocationMap symbol_locations_;
14405   InvocationMap invocations_;
14406
14407   static SetFunctionEntryHookTest* instance_;
14408 };
14409 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
14410
14411
14412 // Returns true if addr is in the range [start, start+len).
14413 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
14414   if (start <= addr && start + len > addr)
14415     return true;
14416
14417   return false;
14418 }
14419
14420 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
14421                                               SymbolInfo* symbol) {
14422   // Insert the symbol at the new location.
14423   SymbolLocationMap::iterator it =
14424       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
14425   // Now erase symbols to the left and right that overlap this one.
14426   while (it != symbol_locations_.begin()) {
14427     SymbolLocationMap::iterator left = it;
14428     --left;
14429     if (!Overlaps(left->first, left->second->size, addr))
14430       break;
14431     symbol_locations_.erase(left);
14432   }
14433
14434   // Now erase symbols to the left and right that overlap this one.
14435   while (true) {
14436     SymbolLocationMap::iterator right = it;
14437     ++right;
14438     if (right == symbol_locations_.end())
14439         break;
14440     if (!Overlaps(addr, symbol->size, right->first))
14441       break;
14442     symbol_locations_.erase(right);
14443   }
14444 }
14445
14446
14447 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
14448   switch (event->type) {
14449     case v8::JitCodeEvent::CODE_ADDED: {
14450         CHECK(event->code_start != NULL);
14451         CHECK_NE(0, static_cast<int>(event->code_len));
14452         CHECK(event->name.str != NULL);
14453         size_t symbol_id = symbols_.size();
14454
14455         // Record the new symbol.
14456         SymbolInfo& info = symbols_[symbol_id];
14457         info.id = symbol_id;
14458         info.size = event->code_len;
14459         info.name.assign(event->name.str, event->name.str + event->name.len);
14460
14461         // And record it's location.
14462         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
14463       }
14464       break;
14465
14466     case v8::JitCodeEvent::CODE_MOVED: {
14467         // We would like to never see code move that we haven't seen before,
14468         // but the code creation event does not happen until the line endings
14469         // have been calculated (this is so that we can report the line in the
14470         // script at which the function source is found, see
14471         // Compiler::RecordFunctionCompilation) and the line endings
14472         // calculations can cause a GC, which can move the newly created code
14473         // before its existence can be logged.
14474         SymbolLocationMap::iterator it(
14475             symbol_locations_.find(
14476                 reinterpret_cast<i::Address>(event->code_start)));
14477         if (it != symbol_locations_.end()) {
14478           // Found a symbol at this location, move it.
14479           SymbolInfo* info = it->second;
14480           symbol_locations_.erase(it);
14481           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
14482                          info);
14483         }
14484       }
14485     default:
14486       break;
14487   }
14488 }
14489
14490 void SetFunctionEntryHookTest::OnEntryHook(
14491     uintptr_t function, uintptr_t return_addr_location) {
14492   // Get the function's code object.
14493   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
14494       reinterpret_cast<i::Address>(function));
14495   CHECK(function_code != NULL);
14496
14497   // Then try and look up the caller's code object.
14498   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
14499
14500   // Count the invocation.
14501   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
14502   SymbolInfo* function_symbol =
14503       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
14504   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
14505
14506   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
14507     // Check that we have a symbol for the "bar" function at the right location.
14508     SymbolLocationMap::iterator it(
14509         symbol_locations_.find(function_code->instruction_start()));
14510     CHECK(it != symbol_locations_.end());
14511   }
14512
14513   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
14514     // Check that we have a symbol for "foo" at the right location.
14515     SymbolLocationMap::iterator it(
14516         symbol_locations_.find(function_code->instruction_start()));
14517     CHECK(it != symbol_locations_.end());
14518   }
14519 }
14520
14521
14522 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
14523   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
14524   // Do we have a direct hit on a symbol?
14525   if (it != symbol_locations_.end()) {
14526     if (it->first == addr)
14527       return it->second;
14528   }
14529
14530   // If not a direct hit, it'll have to be the previous symbol.
14531   if (it == symbol_locations_.begin())
14532     return NULL;
14533
14534   --it;
14535   size_t offs = addr - it->first;
14536   if (offs < it->second->size)
14537     return it->second;
14538
14539   return NULL;
14540 }
14541
14542
14543 int SetFunctionEntryHookTest::CountInvocations(
14544     const char* caller_name, const char* function_name) {
14545   InvocationMap::iterator it(invocations_.begin());
14546   int invocations = 0;
14547   for (; it != invocations_.end(); ++it) {
14548     SymbolInfo* caller = it->first.first;
14549     SymbolInfo* function = it->first.second;
14550
14551     // Filter out non-matching functions.
14552     if (function_name != NULL) {
14553       if (function->name.find(function_name) == std::string::npos)
14554         continue;
14555     }
14556
14557     // Filter out non-matching callers.
14558     if (caller_name != NULL) {
14559       if (caller == NULL)
14560         continue;
14561       if (caller->name.find(caller_name) == std::string::npos)
14562         continue;
14563     }
14564
14565     // It matches add the invocation count to the tally.
14566     invocations += it->second;
14567   }
14568
14569   return invocations;
14570 }
14571
14572
14573 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14574   v8::HandleScope outer(isolate);
14575   v8::Local<Context> env = Context::New(isolate);
14576   env->Enter();
14577
14578   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14579   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14580   env->Global()->Set(v8_str("obj"), t->NewInstance());
14581
14582   const char* script =
14583       "function bar() {\n"
14584       "  var sum = 0;\n"
14585       "  for (i = 0; i < 100; ++i)\n"
14586       "    sum = foo(i);\n"
14587       "  return sum;\n"
14588       "}\n"
14589       "function foo(i) { return i * i; }\n"
14590       "// Invoke on the runtime function.\n"
14591       "obj.asdf()";
14592   CompileRun(script);
14593   bar_func_ = i::Handle<i::JSFunction>::cast(
14594           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14595   DCHECK(!bar_func_.is_null());
14596
14597   foo_func_ =
14598       i::Handle<i::JSFunction>::cast(
14599            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14600   DCHECK(!foo_func_.is_null());
14601
14602   v8::Handle<v8::Value> value = CompileRun("bar();");
14603   CHECK(value->IsNumber());
14604   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14605
14606   // Test the optimized codegen path.
14607   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14608                      "bar();");
14609   CHECK(value->IsNumber());
14610   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14611
14612   env->Exit();
14613 }
14614
14615
14616 void SetFunctionEntryHookTest::RunTest() {
14617   // Work in a new isolate throughout.
14618   v8::Isolate::CreateParams create_params;
14619   create_params.entry_hook = EntryHook;
14620   create_params.code_event_handler = JitEvent;
14621   v8::Isolate* isolate = v8::Isolate::New(create_params);
14622
14623   {
14624     v8::Isolate::Scope scope(isolate);
14625
14626     RunLoopInNewEnv(isolate);
14627
14628     // Check the exepected invocation counts.
14629     CHECK_EQ(2, CountInvocations(NULL, "bar"));
14630     CHECK_EQ(200, CountInvocations("bar", "foo"));
14631     CHECK_EQ(200, CountInvocations(NULL, "foo"));
14632
14633     // Verify that we have an entry hook on some specific stubs.
14634     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14635     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14636     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14637   }
14638   isolate->Dispose();
14639
14640   Reset();
14641
14642   // Make sure a second isolate is unaffected by the previous entry hook.
14643   isolate = v8::Isolate::New();
14644   {
14645     v8::Isolate::Scope scope(isolate);
14646
14647     // Reset the entry count to zero and set the entry hook.
14648     RunLoopInNewEnv(isolate);
14649
14650     // We should record no invocations in this isolate.
14651     CHECK_EQ(0, static_cast<int>(invocations_.size()));
14652   }
14653
14654   isolate->Dispose();
14655 }
14656
14657
14658 TEST(SetFunctionEntryHook) {
14659   // FunctionEntryHook does not work well with experimental natives.
14660   // Experimental natives are compiled during snapshot deserialization.
14661   // This test breaks because InstallGetter (function from snapshot that
14662   // only gets called from experimental natives) is compiled with entry hooks.
14663   i::FLAG_allow_natives_syntax = true;
14664   i::FLAG_use_inlining = false;
14665
14666   SetFunctionEntryHookTest test;
14667   test.RunTest();
14668 }
14669
14670
14671 static i::HashMap* code_map = NULL;
14672 static i::HashMap* jitcode_line_info = NULL;
14673 static int saw_bar = 0;
14674 static int move_events = 0;
14675
14676
14677 static bool FunctionNameIs(const char* expected,
14678                            const v8::JitCodeEvent* event) {
14679   // Log lines for functions are of the general form:
14680   // "LazyCompile:<type><function_name>", where the type is one of
14681   // "*", "~" or "".
14682   static const char kPreamble[] = "LazyCompile:";
14683   static size_t kPreambleLen = sizeof(kPreamble) - 1;
14684
14685   if (event->name.len < sizeof(kPreamble) - 1 ||
14686       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14687     return false;
14688   }
14689
14690   const char* tail = event->name.str + kPreambleLen;
14691   size_t tail_len = event->name.len - kPreambleLen;
14692   size_t expected_len = strlen(expected);
14693   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14694     --tail_len;
14695     ++tail;
14696   }
14697
14698   // Check for tails like 'bar :1'.
14699   if (tail_len > expected_len + 2 &&
14700       tail[expected_len] == ' ' &&
14701       tail[expected_len + 1] == ':' &&
14702       tail[expected_len + 2] &&
14703       !strncmp(tail, expected, expected_len)) {
14704     return true;
14705   }
14706
14707   if (tail_len != expected_len)
14708     return false;
14709
14710   return strncmp(tail, expected, expected_len) == 0;
14711 }
14712
14713
14714 static void event_handler(const v8::JitCodeEvent* event) {
14715   CHECK(event != NULL);
14716   CHECK(code_map != NULL);
14717   CHECK(jitcode_line_info != NULL);
14718
14719   class DummyJitCodeLineInfo {
14720   };
14721
14722   switch (event->type) {
14723     case v8::JitCodeEvent::CODE_ADDED: {
14724         CHECK(event->code_start != NULL);
14725         CHECK_NE(0, static_cast<int>(event->code_len));
14726         CHECK(event->name.str != NULL);
14727         i::HashMap::Entry* entry =
14728             code_map->Lookup(event->code_start,
14729                              i::ComputePointerHash(event->code_start),
14730                              true);
14731         entry->value = reinterpret_cast<void*>(event->code_len);
14732
14733         if (FunctionNameIs("bar", event)) {
14734           ++saw_bar;
14735         }
14736       }
14737       break;
14738
14739     case v8::JitCodeEvent::CODE_MOVED: {
14740         uint32_t hash = i::ComputePointerHash(event->code_start);
14741         // We would like to never see code move that we haven't seen before,
14742         // but the code creation event does not happen until the line endings
14743         // have been calculated (this is so that we can report the line in the
14744         // script at which the function source is found, see
14745         // Compiler::RecordFunctionCompilation) and the line endings
14746         // calculations can cause a GC, which can move the newly created code
14747         // before its existence can be logged.
14748         i::HashMap::Entry* entry =
14749             code_map->Lookup(event->code_start, hash, false);
14750         if (entry != NULL) {
14751           ++move_events;
14752
14753           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14754           code_map->Remove(event->code_start, hash);
14755
14756           entry = code_map->Lookup(event->new_code_start,
14757                                    i::ComputePointerHash(event->new_code_start),
14758                                    true);
14759           CHECK(entry != NULL);
14760           entry->value = reinterpret_cast<void*>(event->code_len);
14761         }
14762       }
14763       break;
14764
14765     case v8::JitCodeEvent::CODE_REMOVED:
14766       // Object/code removal events are currently not dispatched from the GC.
14767       CHECK(false);
14768       break;
14769
14770     // For CODE_START_LINE_INFO_RECORDING event, we will create one
14771     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14772     // record it in jitcode_line_info.
14773     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14774         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14775         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14776         temp_event->user_data = line_info;
14777         i::HashMap::Entry* entry =
14778             jitcode_line_info->Lookup(line_info,
14779                                       i::ComputePointerHash(line_info),
14780                                       true);
14781         entry->value = reinterpret_cast<void*>(line_info);
14782       }
14783       break;
14784     // For these two events, we will check whether the event->user_data
14785     // data structure is created before during CODE_START_LINE_INFO_RECORDING
14786     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14787     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14788         CHECK(event->user_data != NULL);
14789         uint32_t hash = i::ComputePointerHash(event->user_data);
14790         i::HashMap::Entry* entry =
14791             jitcode_line_info->Lookup(event->user_data, hash, false);
14792         CHECK(entry != NULL);
14793         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14794       }
14795       break;
14796
14797     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14798         CHECK(event->user_data != NULL);
14799         uint32_t hash = i::ComputePointerHash(event->user_data);
14800         i::HashMap::Entry* entry =
14801             jitcode_line_info->Lookup(event->user_data, hash, false);
14802         CHECK(entry != NULL);
14803       }
14804       break;
14805
14806     default:
14807       // Impossible event.
14808       CHECK(false);
14809       break;
14810   }
14811 }
14812
14813
14814 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14815   i::FLAG_stress_compaction = true;
14816   i::FLAG_incremental_marking = false;
14817   if (i::FLAG_never_compact) return;
14818   const char* script =
14819     "function bar() {"
14820     "  var sum = 0;"
14821     "  for (i = 0; i < 100; ++i)"
14822     "    sum = foo(i);"
14823     "  return sum;"
14824     "}"
14825     "function foo(i) { return i * i; };"
14826     "bar();";
14827
14828   // Run this test in a new isolate to make sure we don't
14829   // have remnants of state from other code.
14830   v8::Isolate* isolate = v8::Isolate::New();
14831   isolate->Enter();
14832   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14833   i::Heap* heap = i_isolate->heap();
14834
14835   {
14836     v8::HandleScope scope(isolate);
14837     i::HashMap code(MatchPointers);
14838     code_map = &code;
14839
14840     i::HashMap lineinfo(MatchPointers);
14841     jitcode_line_info = &lineinfo;
14842
14843     saw_bar = 0;
14844     move_events = 0;
14845
14846     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14847
14848     // Generate new code objects sparsely distributed across several
14849     // different fragmented code-space pages.
14850     const int kIterations = 10;
14851     for (int i = 0; i < kIterations; ++i) {
14852       LocalContext env(isolate);
14853       i::AlwaysAllocateScope always_allocate(i_isolate);
14854       SimulateFullSpace(heap->code_space());
14855       CompileRun(script);
14856
14857       // Keep a strong reference to the code object in the handle scope.
14858       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14859           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14860       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14861           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14862
14863       // Clear the compilation cache to get more wastage.
14864       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14865     }
14866
14867     // Force code movement.
14868     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14869
14870     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14871
14872     CHECK_LE(kIterations, saw_bar);
14873     CHECK_LT(0, move_events);
14874
14875     code_map = NULL;
14876     jitcode_line_info = NULL;
14877   }
14878
14879   isolate->Exit();
14880   isolate->Dispose();
14881
14882   // Do this in a new isolate.
14883   isolate = v8::Isolate::New();
14884   isolate->Enter();
14885
14886   // Verify that we get callbacks for existing code objects when we
14887   // request enumeration of existing code.
14888   {
14889     v8::HandleScope scope(isolate);
14890     LocalContext env(isolate);
14891     CompileRun(script);
14892
14893     // Now get code through initial iteration.
14894     i::HashMap code(MatchPointers);
14895     code_map = &code;
14896
14897     i::HashMap lineinfo(MatchPointers);
14898     jitcode_line_info = &lineinfo;
14899
14900     isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14901                                     event_handler);
14902     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14903
14904     jitcode_line_info = NULL;
14905     // We expect that we got some events. Note that if we could get code removal
14906     // notifications, we could compare two collections, one created by listening
14907     // from the time of creation of an isolate, and the other by subscribing
14908     // with EnumExisting.
14909     CHECK_LT(0, code.occupancy());
14910
14911     code_map = NULL;
14912   }
14913
14914   isolate->Exit();
14915   isolate->Dispose();
14916 }
14917
14918
14919 THREADED_TEST(ExternalAllocatedMemory) {
14920   v8::Isolate* isolate = CcTest::isolate();
14921   v8::HandleScope outer(isolate);
14922   v8::Local<Context> env(Context::New(isolate));
14923   CHECK(!env.IsEmpty());
14924   const int64_t kSize = 1024*1024;
14925   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14926   CHECK_EQ(baseline + kSize,
14927            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14928   CHECK_EQ(baseline,
14929            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14930 }
14931
14932
14933 // Regression test for issue 54, object templates with internal fields
14934 // but no accessors or interceptors did not get their internal field
14935 // count set on instances.
14936 THREADED_TEST(Regress54) {
14937   LocalContext context;
14938   v8::Isolate* isolate = context->GetIsolate();
14939   v8::HandleScope outer(isolate);
14940   static v8::Persistent<v8::ObjectTemplate> templ;
14941   if (templ.IsEmpty()) {
14942     v8::EscapableHandleScope inner(isolate);
14943     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14944     local->SetInternalFieldCount(1);
14945     templ.Reset(isolate, inner.Escape(local));
14946   }
14947   v8::Handle<v8::Object> result =
14948       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14949   CHECK_EQ(1, result->InternalFieldCount());
14950 }
14951
14952
14953 // If part of the threaded tests, this test makes ThreadingTest fail
14954 // on mac.
14955 TEST(CatchStackOverflow) {
14956   LocalContext context;
14957   v8::HandleScope scope(context->GetIsolate());
14958   v8::TryCatch try_catch;
14959   v8::Handle<v8::Value> result = CompileRun(
14960     "function f() {"
14961     "  return f();"
14962     "}"
14963     ""
14964     "f();");
14965   CHECK(result.IsEmpty());
14966 }
14967
14968
14969 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14970                                     const char* resource_name,
14971                                     int line_offset) {
14972   v8::HandleScope scope(CcTest::isolate());
14973   v8::TryCatch try_catch;
14974   v8::Handle<v8::Value> result = script->Run();
14975   CHECK(result.IsEmpty());
14976   CHECK(try_catch.HasCaught());
14977   v8::Handle<v8::Message> message = try_catch.Message();
14978   CHECK(!message.IsEmpty());
14979   CHECK_EQ(10 + line_offset, message->GetLineNumber());
14980   CHECK_EQ(91, message->GetStartPosition());
14981   CHECK_EQ(92, message->GetEndPosition());
14982   CHECK_EQ(2, message->GetStartColumn());
14983   CHECK_EQ(3, message->GetEndColumn());
14984   v8::String::Utf8Value line(message->GetSourceLine());
14985   CHECK_EQ("  throw 'nirk';", *line);
14986   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
14987   CHECK_EQ(resource_name, *name);
14988 }
14989
14990
14991 THREADED_TEST(TryCatchSourceInfo) {
14992   LocalContext context;
14993   v8::HandleScope scope(context->GetIsolate());
14994   v8::Local<v8::String> source = v8_str(
14995       "function Foo() {\n"
14996       "  return Bar();\n"
14997       "}\n"
14998       "\n"
14999       "function Bar() {\n"
15000       "  return Baz();\n"
15001       "}\n"
15002       "\n"
15003       "function Baz() {\n"
15004       "  throw 'nirk';\n"
15005       "}\n"
15006       "\n"
15007       "Foo();\n");
15008
15009   const char* resource_name;
15010   v8::Handle<v8::Script> script;
15011   resource_name = "test.js";
15012   script = CompileWithOrigin(source, resource_name);
15013   CheckTryCatchSourceInfo(script, resource_name, 0);
15014
15015   resource_name = "test1.js";
15016   v8::ScriptOrigin origin1(
15017       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
15018   script = v8::Script::Compile(source, &origin1);
15019   CheckTryCatchSourceInfo(script, resource_name, 0);
15020
15021   resource_name = "test2.js";
15022   v8::ScriptOrigin origin2(
15023       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
15024       v8::Integer::New(context->GetIsolate(), 7));
15025   script = v8::Script::Compile(source, &origin2);
15026   CheckTryCatchSourceInfo(script, resource_name, 7);
15027 }
15028
15029
15030 THREADED_TEST(CompilationCache) {
15031   LocalContext context;
15032   v8::HandleScope scope(context->GetIsolate());
15033   v8::Handle<v8::String> source0 =
15034       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
15035   v8::Handle<v8::String> source1 =
15036       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
15037   v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
15038   v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
15039   v8::Handle<v8::Script> script2 =
15040       v8::Script::Compile(source0);  // different origin
15041   CHECK_EQ(1234, script0->Run()->Int32Value());
15042   CHECK_EQ(1234, script1->Run()->Int32Value());
15043   CHECK_EQ(1234, script2->Run()->Int32Value());
15044 }
15045
15046
15047 static void FunctionNameCallback(
15048     const v8::FunctionCallbackInfo<v8::Value>& args) {
15049   ApiTestFuzzer::Fuzz();
15050   args.GetReturnValue().Set(v8_num(42));
15051 }
15052
15053
15054 THREADED_TEST(CallbackFunctionName) {
15055   LocalContext context;
15056   v8::Isolate* isolate = context->GetIsolate();
15057   v8::HandleScope scope(isolate);
15058   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
15059   t->Set(v8_str("asdf"),
15060          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
15061   context->Global()->Set(v8_str("obj"), t->NewInstance());
15062   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
15063   CHECK(value->IsString());
15064   v8::String::Utf8Value name(value);
15065   CHECK_EQ("asdf", *name);
15066 }
15067
15068
15069 THREADED_TEST(DateAccess) {
15070   LocalContext context;
15071   v8::HandleScope scope(context->GetIsolate());
15072   v8::Handle<v8::Value> date =
15073       v8::Date::New(context->GetIsolate(), 1224744689038.0);
15074   CHECK(date->IsDate());
15075   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
15076 }
15077
15078
15079 void CheckProperties(v8::Isolate* isolate,
15080                      v8::Handle<v8::Value> val,
15081                      int elmc,
15082                      const char* elmv[]) {
15083   v8::Handle<v8::Object> obj = val.As<v8::Object>();
15084   v8::Handle<v8::Array> props = obj->GetPropertyNames();
15085   CHECK_EQ(elmc, props->Length());
15086   for (int i = 0; i < elmc; i++) {
15087     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
15088     CHECK_EQ(elmv[i], *elm);
15089   }
15090 }
15091
15092
15093 void CheckOwnProperties(v8::Isolate* isolate,
15094                         v8::Handle<v8::Value> val,
15095                         int elmc,
15096                         const char* elmv[]) {
15097   v8::Handle<v8::Object> obj = val.As<v8::Object>();
15098   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
15099   CHECK_EQ(elmc, props->Length());
15100   for (int i = 0; i < elmc; i++) {
15101     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
15102     CHECK_EQ(elmv[i], *elm);
15103   }
15104 }
15105
15106
15107 THREADED_TEST(PropertyEnumeration) {
15108   LocalContext context;
15109   v8::Isolate* isolate = context->GetIsolate();
15110   v8::HandleScope scope(isolate);
15111   v8::Handle<v8::Value> obj = CompileRun(
15112       "var result = [];"
15113       "result[0] = {};"
15114       "result[1] = {a: 1, b: 2};"
15115       "result[2] = [1, 2, 3];"
15116       "var proto = {x: 1, y: 2, z: 3};"
15117       "var x = { __proto__: proto, w: 0, z: 1 };"
15118       "result[3] = x;"
15119       "result;");
15120   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
15121   CHECK_EQ(4, elms->Length());
15122   int elmc0 = 0;
15123   const char** elmv0 = NULL;
15124   CheckProperties(
15125       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15126   CheckOwnProperties(
15127       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15128   int elmc1 = 2;
15129   const char* elmv1[] = {"a", "b"};
15130   CheckProperties(
15131       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
15132   CheckOwnProperties(
15133       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
15134   int elmc2 = 3;
15135   const char* elmv2[] = {"0", "1", "2"};
15136   CheckProperties(
15137       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
15138   CheckOwnProperties(
15139       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
15140   int elmc3 = 4;
15141   const char* elmv3[] = {"w", "z", "x", "y"};
15142   CheckProperties(
15143       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
15144   int elmc4 = 2;
15145   const char* elmv4[] = {"w", "z"};
15146   CheckOwnProperties(
15147       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
15148 }
15149
15150
15151 THREADED_TEST(PropertyEnumeration2) {
15152   LocalContext context;
15153   v8::Isolate* isolate = context->GetIsolate();
15154   v8::HandleScope scope(isolate);
15155   v8::Handle<v8::Value> obj = CompileRun(
15156       "var result = [];"
15157       "result[0] = {};"
15158       "result[1] = {a: 1, b: 2};"
15159       "result[2] = [1, 2, 3];"
15160       "var proto = {x: 1, y: 2, z: 3};"
15161       "var x = { __proto__: proto, w: 0, z: 1 };"
15162       "result[3] = x;"
15163       "result;");
15164   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
15165   CHECK_EQ(4, elms->Length());
15166   int elmc0 = 0;
15167   const char** elmv0 = NULL;
15168   CheckProperties(isolate,
15169                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15170
15171   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
15172   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
15173   CHECK_EQ(0, props->Length());
15174   for (uint32_t i = 0; i < props->Length(); i++) {
15175     printf("p[%u]\n", i);
15176   }
15177 }
15178
15179 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
15180                                   Local<Value> name,
15181                                   v8::AccessType type,
15182                                   Local<Value> data) {
15183   return type != v8::ACCESS_SET;
15184 }
15185
15186
15187 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
15188                                     uint32_t key,
15189                                     v8::AccessType type,
15190                                     Local<Value> data) {
15191   return type != v8::ACCESS_SET;
15192 }
15193
15194
15195 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
15196   LocalContext context;
15197   v8::Isolate* isolate = context->GetIsolate();
15198   v8::HandleScope scope(isolate);
15199   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15200   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
15201                                  IndexedSetAccessBlocker);
15202   templ->Set(v8_str("x"), v8::True(isolate));
15203   Local<v8::Object> instance = templ->NewInstance();
15204   context->Global()->Set(v8_str("obj"), instance);
15205   Local<Value> value = CompileRun("obj.x");
15206   CHECK(value->BooleanValue());
15207 }
15208
15209
15210 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
15211                                   Local<Value> name,
15212                                   v8::AccessType type,
15213                                   Local<Value> data) {
15214   return false;
15215 }
15216
15217
15218 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
15219                                     uint32_t key,
15220                                     v8::AccessType type,
15221                                     Local<Value> data) {
15222   return false;
15223 }
15224
15225
15226
15227 THREADED_TEST(AccessChecksReenabledCorrectly) {
15228   LocalContext context;
15229   v8::Isolate* isolate = context->GetIsolate();
15230   v8::HandleScope scope(isolate);
15231   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15232   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15233                                  IndexedGetAccessBlocker);
15234   templ->Set(v8_str("a"), v8_str("a"));
15235   // Add more than 8 (see kMaxFastProperties) properties
15236   // so that the constructor will force copying map.
15237   // Cannot sprintf, gcc complains unsafety.
15238   char buf[4];
15239   for (char i = '0'; i <= '9' ; i++) {
15240     buf[0] = i;
15241     for (char j = '0'; j <= '9'; j++) {
15242       buf[1] = j;
15243       for (char k = '0'; k <= '9'; k++) {
15244         buf[2] = k;
15245         buf[3] = 0;
15246         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
15247       }
15248     }
15249   }
15250
15251   Local<v8::Object> instance_1 = templ->NewInstance();
15252   context->Global()->Set(v8_str("obj_1"), instance_1);
15253
15254   Local<Value> value_1 = CompileRun("obj_1.a");
15255   CHECK(value_1.IsEmpty());
15256
15257   Local<v8::Object> instance_2 = templ->NewInstance();
15258   context->Global()->Set(v8_str("obj_2"), instance_2);
15259
15260   Local<Value> value_2 = CompileRun("obj_2.a");
15261   CHECK(value_2.IsEmpty());
15262 }
15263
15264
15265 // This tests that access check information remains on the global
15266 // object template when creating contexts.
15267 THREADED_TEST(AccessControlRepeatedContextCreation) {
15268   v8::Isolate* isolate = CcTest::isolate();
15269   v8::HandleScope handle_scope(isolate);
15270   v8::Handle<v8::ObjectTemplate> global_template =
15271       v8::ObjectTemplate::New(isolate);
15272   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
15273                                            IndexedSetAccessBlocker);
15274   i::Handle<i::ObjectTemplateInfo> internal_template =
15275       v8::Utils::OpenHandle(*global_template);
15276   CHECK(!internal_template->constructor()->IsUndefined());
15277   i::Handle<i::FunctionTemplateInfo> constructor(
15278       i::FunctionTemplateInfo::cast(internal_template->constructor()));
15279   CHECK(!constructor->access_check_info()->IsUndefined());
15280   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
15281   CHECK(!context0.IsEmpty());
15282   CHECK(!constructor->access_check_info()->IsUndefined());
15283 }
15284
15285
15286 THREADED_TEST(TurnOnAccessCheck) {
15287   v8::Isolate* isolate = CcTest::isolate();
15288   v8::HandleScope handle_scope(isolate);
15289
15290   // Create an environment with access check to the global object disabled by
15291   // default.
15292   v8::Handle<v8::ObjectTemplate> global_template =
15293       v8::ObjectTemplate::New(isolate);
15294   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15295                                            IndexedGetAccessBlocker,
15296                                            v8::Handle<v8::Value>(),
15297                                            false);
15298   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
15299   Context::Scope context_scope(context);
15300
15301   // Set up a property and a number of functions.
15302   context->Global()->Set(v8_str("a"), v8_num(1));
15303   CompileRun("function f1() {return a;}"
15304              "function f2() {return a;}"
15305              "function g1() {return h();}"
15306              "function g2() {return h();}"
15307              "function h() {return 1;}");
15308   Local<Function> f1 =
15309       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15310   Local<Function> f2 =
15311       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15312   Local<Function> g1 =
15313       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15314   Local<Function> g2 =
15315       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15316   Local<Function> h =
15317       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15318
15319   // Get the global object.
15320   v8::Handle<v8::Object> global = context->Global();
15321
15322   // Call f1 one time and f2 a number of times. This will ensure that f1 still
15323   // uses the runtime system to retreive property a whereas f2 uses global load
15324   // inline cache.
15325   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15326   for (int i = 0; i < 4; i++) {
15327     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15328   }
15329
15330   // Same for g1 and g2.
15331   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15332   for (int i = 0; i < 4; i++) {
15333     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15334   }
15335
15336   // Detach the global and turn on access check.
15337   Local<Object> hidden_global = Local<Object>::Cast(
15338       context->Global()->GetPrototype());
15339   context->DetachGlobal();
15340   hidden_global->TurnOnAccessCheck();
15341
15342   // Failing access check results in exception.
15343   CHECK(f1->Call(global, 0, NULL).IsEmpty());
15344   CHECK(f2->Call(global, 0, NULL).IsEmpty());
15345   CHECK(g1->Call(global, 0, NULL).IsEmpty());
15346   CHECK(g2->Call(global, 0, NULL).IsEmpty());
15347
15348   // No failing access check when just returning a constant.
15349   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15350 }
15351
15352
15353 static const char* kPropertyA = "a";
15354 static const char* kPropertyH = "h";
15355
15356 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
15357                                        Local<Value> name,
15358                                        v8::AccessType type,
15359                                        Local<Value> data) {
15360   if (!name->IsString()) return false;
15361   i::Handle<i::String> name_handle =
15362       v8::Utils::OpenHandle(String::Cast(*name));
15363   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
15364       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
15365 }
15366
15367
15368 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
15369   v8::Isolate* isolate = CcTest::isolate();
15370   v8::HandleScope handle_scope(isolate);
15371
15372   // Create an environment with access check to the global object disabled by
15373   // default. When the registered access checker will block access to properties
15374   // a and h.
15375   v8::Handle<v8::ObjectTemplate> global_template =
15376      v8::ObjectTemplate::New(isolate);
15377   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
15378                                            IndexedGetAccessBlocker,
15379                                            v8::Handle<v8::Value>(),
15380                                            false);
15381   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
15382   Context::Scope context_scope(context);
15383
15384   // Set up a property and a number of functions.
15385   context->Global()->Set(v8_str("a"), v8_num(1));
15386   static const char* source = "function f1() {return a;}"
15387                               "function f2() {return a;}"
15388                               "function g1() {return h();}"
15389                               "function g2() {return h();}"
15390                               "function h() {return 1;}";
15391
15392   CompileRun(source);
15393   Local<Function> f1;
15394   Local<Function> f2;
15395   Local<Function> g1;
15396   Local<Function> g2;
15397   Local<Function> h;
15398   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15399   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15400   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15401   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15402   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15403
15404   // Get the global object.
15405   v8::Handle<v8::Object> global = context->Global();
15406
15407   // Call f1 one time and f2 a number of times. This will ensure that f1 still
15408   // uses the runtime system to retreive property a whereas f2 uses global load
15409   // inline cache.
15410   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15411   for (int i = 0; i < 4; i++) {
15412     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15413   }
15414
15415   // Same for g1 and g2.
15416   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15417   for (int i = 0; i < 4; i++) {
15418     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15419   }
15420
15421   // Detach the global and turn on access check now blocking access to property
15422   // a and function h.
15423   Local<Object> hidden_global = Local<Object>::Cast(
15424       context->Global()->GetPrototype());
15425   context->DetachGlobal();
15426   hidden_global->TurnOnAccessCheck();
15427
15428   // Failing access check results in exception.
15429   CHECK(f1->Call(global, 0, NULL).IsEmpty());
15430   CHECK(f2->Call(global, 0, NULL).IsEmpty());
15431   CHECK(g1->Call(global, 0, NULL).IsEmpty());
15432   CHECK(g2->Call(global, 0, NULL).IsEmpty());
15433
15434   // No failing access check when just returning a constant.
15435   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15436
15437   // Now compile the source again. And get the newly compiled functions, except
15438   // for h for which access is blocked.
15439   CompileRun(source);
15440   f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
15441   f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
15442   g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
15443   g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
15444   CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
15445
15446   // Failing access check results in exception.
15447   v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
15448   CHECK(result.IsEmpty());
15449   CHECK(f1->Call(global, 0, NULL).IsEmpty());
15450   CHECK(f2->Call(global, 0, NULL).IsEmpty());
15451   CHECK(g1->Call(global, 0, NULL).IsEmpty());
15452   CHECK(g2->Call(global, 0, NULL).IsEmpty());
15453 }
15454
15455
15456 // Tests that ScriptData can be serialized and deserialized.
15457 TEST(PreCompileSerialization) {
15458   v8::V8::Initialize();
15459   LocalContext env;
15460   v8::Isolate* isolate = env->GetIsolate();
15461   HandleScope handle_scope(isolate);
15462
15463   i::FLAG_min_preparse_length = 0;
15464   const char* script = "function foo(a) { return a+1; }";
15465   v8::ScriptCompiler::Source source(v8_str(script));
15466   v8::ScriptCompiler::Compile(isolate, &source,
15467                               v8::ScriptCompiler::kProduceParserCache);
15468   // Serialize.
15469   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
15470   i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
15471   i::MemCopy(serialized_data, cd->data, cd->length);
15472
15473   // Deserialize.
15474   i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
15475
15476   // Verify that the original is the same as the deserialized.
15477   CHECK_EQ(cd->length, deserialized->length());
15478   CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
15479
15480   delete deserialized;
15481   i::DeleteArray(serialized_data);
15482 }
15483
15484
15485 // This tests that we do not allow dictionary load/call inline caches
15486 // to use functions that have not yet been compiled.  The potential
15487 // problem of loading a function that has not yet been compiled can
15488 // arise because we share code between contexts via the compilation
15489 // cache.
15490 THREADED_TEST(DictionaryICLoadedFunction) {
15491   v8::HandleScope scope(CcTest::isolate());
15492   // Test LoadIC.
15493   for (int i = 0; i < 2; i++) {
15494     LocalContext context;
15495     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15496     context->Global()->Delete(v8_str("tmp"));
15497     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15498   }
15499   // Test CallIC.
15500   for (int i = 0; i < 2; i++) {
15501     LocalContext context;
15502     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15503     context->Global()->Delete(v8_str("tmp"));
15504     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15505   }
15506 }
15507
15508
15509 // Test that cross-context new calls use the context of the callee to
15510 // create the new JavaScript object.
15511 THREADED_TEST(CrossContextNew) {
15512   v8::Isolate* isolate = CcTest::isolate();
15513   v8::HandleScope scope(isolate);
15514   v8::Local<Context> context0 = Context::New(isolate);
15515   v8::Local<Context> context1 = Context::New(isolate);
15516
15517   // Allow cross-domain access.
15518   Local<String> token = v8_str("<security token>");
15519   context0->SetSecurityToken(token);
15520   context1->SetSecurityToken(token);
15521
15522   // Set an 'x' property on the Object prototype and define a
15523   // constructor function in context0.
15524   context0->Enter();
15525   CompileRun("Object.prototype.x = 42; function C() {};");
15526   context0->Exit();
15527
15528   // Call the constructor function from context0 and check that the
15529   // result has the 'x' property.
15530   context1->Enter();
15531   context1->Global()->Set(v8_str("other"), context0->Global());
15532   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15533   CHECK(value->IsInt32());
15534   CHECK_EQ(42, value->Int32Value());
15535   context1->Exit();
15536 }
15537
15538
15539 // Verify that we can clone an object
15540 TEST(ObjectClone) {
15541   LocalContext env;
15542   v8::Isolate* isolate = env->GetIsolate();
15543   v8::HandleScope scope(isolate);
15544
15545   const char* sample =
15546     "var rv = {};"      \
15547     "rv.alpha = 'hello';" \
15548     "rv.beta = 123;"     \
15549     "rv;";
15550
15551   // Create an object, verify basics.
15552   Local<Value> val = CompileRun(sample);
15553   CHECK(val->IsObject());
15554   Local<v8::Object> obj = val.As<v8::Object>();
15555   obj->Set(v8_str("gamma"), v8_str("cloneme"));
15556
15557   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15558   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15559   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15560
15561   // Clone it.
15562   Local<v8::Object> clone = obj->Clone();
15563   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15564   CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15565   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15566
15567   // Set a property on the clone, verify each object.
15568   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15569   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15570   CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15571 }
15572
15573
15574 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
15575  public:
15576   explicit OneByteVectorResource(i::Vector<const char> vector)
15577       : data_(vector) {}
15578   virtual ~OneByteVectorResource() {}
15579   virtual size_t length() const { return data_.length(); }
15580   virtual const char* data() const { return data_.start(); }
15581  private:
15582   i::Vector<const char> data_;
15583 };
15584
15585
15586 class UC16VectorResource : public v8::String::ExternalStringResource {
15587  public:
15588   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15589       : data_(vector) {}
15590   virtual ~UC16VectorResource() {}
15591   virtual size_t length() const { return data_.length(); }
15592   virtual const i::uc16* data() const { return data_.start(); }
15593  private:
15594   i::Vector<const i::uc16> data_;
15595 };
15596
15597
15598 static void MorphAString(i::String* string,
15599                          OneByteVectorResource* one_byte_resource,
15600                          UC16VectorResource* uc16_resource) {
15601   CHECK(i::StringShape(string).IsExternal());
15602   if (string->IsOneByteRepresentation()) {
15603     // Check old map is not internalized or long.
15604     CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
15605     // Morph external string to be TwoByte string.
15606     string->set_map(CcTest::heap()->external_string_map());
15607     i::ExternalTwoByteString* morphed =
15608          i::ExternalTwoByteString::cast(string);
15609     morphed->set_resource(uc16_resource);
15610   } else {
15611     // Check old map is not internalized or long.
15612     CHECK(string->map() == CcTest::heap()->external_string_map());
15613     // Morph external string to be one-byte string.
15614     string->set_map(CcTest::heap()->external_one_byte_string_map());
15615     i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
15616     morphed->set_resource(one_byte_resource);
15617   }
15618 }
15619
15620
15621 // Test that we can still flatten a string if the components it is built up
15622 // from have been turned into 16 bit strings in the mean time.
15623 THREADED_TEST(MorphCompositeStringTest) {
15624   char utf_buffer[129];
15625   const char* c_string = "Now is the time for all good men"
15626                          " to come to the aid of the party";
15627   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15628   {
15629     LocalContext env;
15630     i::Factory* factory = CcTest::i_isolate()->factory();
15631     v8::HandleScope scope(env->GetIsolate());
15632     OneByteVectorResource one_byte_resource(
15633         i::Vector<const char>(c_string, i::StrLength(c_string)));
15634     UC16VectorResource uc16_resource(
15635         i::Vector<const uint16_t>(two_byte_string,
15636                                   i::StrLength(c_string)));
15637
15638     Local<String> lhs(
15639         v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15640                                         &one_byte_resource).ToHandleChecked()));
15641     Local<String> rhs(
15642         v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15643                                         &one_byte_resource).ToHandleChecked()));
15644
15645     env->Global()->Set(v8_str("lhs"), lhs);
15646     env->Global()->Set(v8_str("rhs"), rhs);
15647
15648     CompileRun(
15649         "var cons = lhs + rhs;"
15650         "var slice = lhs.substring(1, lhs.length - 1);"
15651         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15652
15653     CHECK(lhs->IsOneByte());
15654     CHECK(rhs->IsOneByte());
15655
15656     MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
15657                  &uc16_resource);
15658     MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
15659                  &uc16_resource);
15660
15661     // This should UTF-8 without flattening, since everything is ASCII.
15662     Handle<String> cons = v8_compile("cons")->Run().As<String>();
15663     CHECK_EQ(128, cons->Utf8Length());
15664     int nchars = -1;
15665     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15666     CHECK_EQ(128, nchars);
15667     CHECK_EQ(0, strcmp(
15668         utf_buffer,
15669         "Now is the time for all good men to come to the aid of the party"
15670         "Now is the time for all good men to come to the aid of the party"));
15671
15672     // Now do some stuff to make sure the strings are flattened, etc.
15673     CompileRun(
15674         "/[^a-z]/.test(cons);"
15675         "/[^a-z]/.test(slice);"
15676         "/[^a-z]/.test(slice_on_cons);");
15677     const char* expected_cons =
15678         "Now is the time for all good men to come to the aid of the party"
15679         "Now is the time for all good men to come to the aid of the party";
15680     const char* expected_slice =
15681         "ow is the time for all good men to come to the aid of the part";
15682     const char* expected_slice_on_cons =
15683         "ow is the time for all good men to come to the aid of the party"
15684         "Now is the time for all good men to come to the aid of the part";
15685     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15686              env->Global()->Get(v8_str("cons")));
15687     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15688              env->Global()->Get(v8_str("slice")));
15689     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15690              env->Global()->Get(v8_str("slice_on_cons")));
15691   }
15692   i::DeleteArray(two_byte_string);
15693 }
15694
15695
15696 TEST(CompileExternalTwoByteSource) {
15697   LocalContext context;
15698   v8::HandleScope scope(context->GetIsolate());
15699
15700   // This is a very short list of sources, which currently is to check for a
15701   // regression caused by r2703.
15702   const char* one_byte_sources[] = {
15703       "0.5",
15704       "-0.5",   // This mainly testes PushBack in the Scanner.
15705       "--0.5",  // This mainly testes PushBack in the Scanner.
15706       NULL};
15707
15708   // Compile the sources as external two byte strings.
15709   for (int i = 0; one_byte_sources[i] != NULL; i++) {
15710     uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15711     TestResource* uc16_resource = new TestResource(two_byte_string);
15712     v8::Local<v8::String> source =
15713         v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15714     v8::Script::Compile(source);
15715   }
15716 }
15717
15718
15719 #ifndef V8_INTERPRETED_REGEXP
15720
15721 struct RegExpInterruptionData {
15722   v8::base::Atomic32 loop_count;
15723   UC16VectorResource* string_resource;
15724   v8::Persistent<v8::String> string;
15725 } regexp_interruption_data;
15726
15727
15728 class RegExpInterruptionThread : public v8::base::Thread {
15729  public:
15730   explicit RegExpInterruptionThread(v8::Isolate* isolate)
15731       : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15732
15733   virtual void Run() {
15734     for (v8::base::NoBarrier_Store(&regexp_interruption_data.loop_count, 0);
15735          v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) < 7;
15736          v8::base::NoBarrier_AtomicIncrement(
15737              &regexp_interruption_data.loop_count, 1)) {
15738       v8::base::OS::Sleep(50);  // Wait a bit before requesting GC.
15739       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15740     }
15741     v8::base::OS::Sleep(50);  // Wait a bit before terminating.
15742     v8::V8::TerminateExecution(isolate_);
15743   }
15744
15745  private:
15746   v8::Isolate* isolate_;
15747 };
15748
15749
15750 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15751   if (v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) != 2) {
15752     return;
15753   }
15754   v8::HandleScope scope(CcTest::isolate());
15755   v8::Local<v8::String> string = v8::Local<v8::String>::New(
15756       CcTest::isolate(), regexp_interruption_data.string);
15757   string->MakeExternal(regexp_interruption_data.string_resource);
15758 }
15759
15760
15761 // Test that RegExp execution can be interrupted.  Specifically, we test
15762 // * interrupting with GC
15763 // * turn the subject string from one-byte internal to two-byte external string
15764 // * force termination
15765 TEST(RegExpInterruption) {
15766   v8::HandleScope scope(CcTest::isolate());
15767   LocalContext env;
15768
15769   RegExpInterruptionThread timeout_thread(CcTest::isolate());
15770
15771   v8::V8::AddGCPrologueCallback(RunBeforeGC);
15772   static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15773   i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
15774   v8::Local<v8::String> string = v8_str(one_byte_content);
15775
15776   CcTest::global()->Set(v8_str("a"), string);
15777   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15778   regexp_interruption_data.string_resource = new UC16VectorResource(
15779       i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
15780
15781   v8::TryCatch try_catch;
15782   timeout_thread.Start();
15783
15784   CompileRun("/((a*)*)*b/.exec(a)");
15785   CHECK(try_catch.HasTerminated());
15786
15787   timeout_thread.Join();
15788
15789   regexp_interruption_data.string.Reset();
15790   i::DeleteArray(uc16_content);
15791 }
15792
15793 #endif  // V8_INTERPRETED_REGEXP
15794
15795
15796 // Test that we cannot set a property on the global object if there
15797 // is a read-only property in the prototype chain.
15798 TEST(ReadOnlyPropertyInGlobalProto) {
15799   v8::Isolate* isolate = CcTest::isolate();
15800   v8::HandleScope scope(isolate);
15801   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15802   LocalContext context(0, templ);
15803   v8::Handle<v8::Object> global = context->Global();
15804   v8::Handle<v8::Object> global_proto =
15805       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15806   global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
15807                          v8::ReadOnly);
15808   global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
15809                          v8::ReadOnly);
15810   // Check without 'eval' or 'with'.
15811   v8::Handle<v8::Value> res =
15812       CompileRun("function f() { x = 42; return x; }; f()");
15813   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15814   // Check with 'eval'.
15815   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15816   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15817   // Check with 'with'.
15818   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15819   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15820 }
15821
15822 static int force_set_set_count = 0;
15823 static int force_set_get_count = 0;
15824 bool pass_on_get = false;
15825
15826 static void ForceSetGetter(v8::Local<v8::String> name,
15827                            const v8::PropertyCallbackInfo<v8::Value>& info) {
15828   force_set_get_count++;
15829   if (pass_on_get) {
15830     return;
15831   }
15832   info.GetReturnValue().Set(3);
15833 }
15834
15835 static void ForceSetSetter(v8::Local<v8::String> name,
15836                            v8::Local<v8::Value> value,
15837                            const v8::PropertyCallbackInfo<void>& info) {
15838   force_set_set_count++;
15839 }
15840
15841 static void ForceSetInterceptSetter(
15842     v8::Local<v8::String> name,
15843     v8::Local<v8::Value> value,
15844     const v8::PropertyCallbackInfo<v8::Value>& info) {
15845   force_set_set_count++;
15846   info.GetReturnValue().SetUndefined();
15847 }
15848
15849
15850 TEST(ForceSet) {
15851   force_set_get_count = 0;
15852   force_set_set_count = 0;
15853   pass_on_get = false;
15854
15855   v8::Isolate* isolate = CcTest::isolate();
15856   v8::HandleScope scope(isolate);
15857   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15858   v8::Handle<v8::String> access_property =
15859       v8::String::NewFromUtf8(isolate, "a");
15860   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15861   LocalContext context(NULL, templ);
15862   v8::Handle<v8::Object> global = context->Global();
15863
15864   // Ordinary properties
15865   v8::Handle<v8::String> simple_property =
15866       v8::String::NewFromUtf8(isolate, "p");
15867   global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15868   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15869   // This should fail because the property is read-only
15870   global->Set(simple_property, v8::Int32::New(isolate, 5));
15871   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15872   // This should succeed even though the property is read-only
15873   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15874   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15875
15876   // Accessors
15877   CHECK_EQ(0, force_set_set_count);
15878   CHECK_EQ(0, force_set_get_count);
15879   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15880   // CHECK_EQ the property shouldn't override it, just call the setter
15881   // which in this case does nothing.
15882   global->Set(access_property, v8::Int32::New(isolate, 7));
15883   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15884   CHECK_EQ(1, force_set_set_count);
15885   CHECK_EQ(2, force_set_get_count);
15886   // Forcing the property to be set should override the accessor without
15887   // calling it
15888   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15889   CHECK_EQ(8, global->Get(access_property)->Int32Value());
15890   CHECK_EQ(1, force_set_set_count);
15891   CHECK_EQ(2, force_set_get_count);
15892 }
15893
15894
15895 TEST(ForceSetWithInterceptor) {
15896   force_set_get_count = 0;
15897   force_set_set_count = 0;
15898   pass_on_get = false;
15899
15900   v8::Isolate* isolate = CcTest::isolate();
15901   v8::HandleScope scope(isolate);
15902   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15903   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15904   LocalContext context(NULL, templ);
15905   v8::Handle<v8::Object> global = context->Global();
15906
15907   v8::Handle<v8::String> some_property =
15908       v8::String::NewFromUtf8(isolate, "a");
15909   CHECK_EQ(0, force_set_set_count);
15910   CHECK_EQ(0, force_set_get_count);
15911   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15912   // Setting the property shouldn't override it, just call the setter
15913   // which in this case does nothing.
15914   global->Set(some_property, v8::Int32::New(isolate, 7));
15915   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15916   CHECK_EQ(1, force_set_set_count);
15917   CHECK_EQ(2, force_set_get_count);
15918   // Getting the property when the interceptor returns an empty handle
15919   // should yield undefined, since the property isn't present on the
15920   // object itself yet.
15921   pass_on_get = true;
15922   CHECK(global->Get(some_property)->IsUndefined());
15923   CHECK_EQ(1, force_set_set_count);
15924   CHECK_EQ(3, force_set_get_count);
15925   // Forcing the property to be set should cause the value to be
15926   // set locally without calling the interceptor.
15927   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15928   CHECK_EQ(8, global->Get(some_property)->Int32Value());
15929   CHECK_EQ(1, force_set_set_count);
15930   CHECK_EQ(4, force_set_get_count);
15931   // Reenabling the interceptor should cause it to take precedence over
15932   // the property
15933   pass_on_get = false;
15934   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15935   CHECK_EQ(1, force_set_set_count);
15936   CHECK_EQ(5, force_set_get_count);
15937   // The interceptor should also work for other properties
15938   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15939                   ->Int32Value());
15940   CHECK_EQ(1, force_set_set_count);
15941   CHECK_EQ(6, force_set_get_count);
15942 }
15943
15944
15945 THREADED_TEST(ForceDelete) {
15946   v8::Isolate* isolate = CcTest::isolate();
15947   v8::HandleScope scope(isolate);
15948   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15949   LocalContext context(NULL, templ);
15950   v8::Handle<v8::Object> global = context->Global();
15951
15952   // Ordinary properties
15953   v8::Handle<v8::String> simple_property =
15954       v8::String::NewFromUtf8(isolate, "p");
15955   global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15956   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15957   // This should fail because the property is dont-delete.
15958   CHECK(!global->Delete(simple_property));
15959   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15960   // This should succeed even though the property is dont-delete.
15961   CHECK(global->ForceDelete(simple_property));
15962   CHECK(global->Get(simple_property)->IsUndefined());
15963 }
15964
15965
15966 static int force_delete_interceptor_count = 0;
15967 static bool pass_on_delete = false;
15968
15969
15970 static void ForceDeleteDeleter(
15971     v8::Local<v8::String> name,
15972     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15973   force_delete_interceptor_count++;
15974   if (pass_on_delete) return;
15975   info.GetReturnValue().Set(true);
15976 }
15977
15978
15979 THREADED_TEST(ForceDeleteWithInterceptor) {
15980   force_delete_interceptor_count = 0;
15981   pass_on_delete = false;
15982
15983   v8::Isolate* isolate = CcTest::isolate();
15984   v8::HandleScope scope(isolate);
15985   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15986   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15987   LocalContext context(NULL, templ);
15988   v8::Handle<v8::Object> global = context->Global();
15989
15990   v8::Handle<v8::String> some_property =
15991       v8::String::NewFromUtf8(isolate, "a");
15992   global->ForceSet(some_property, v8::Integer::New(isolate, 42),
15993                    v8::DontDelete);
15994
15995   // Deleting a property should get intercepted and nothing should
15996   // happen.
15997   CHECK_EQ(0, force_delete_interceptor_count);
15998   CHECK(global->Delete(some_property));
15999   CHECK_EQ(1, force_delete_interceptor_count);
16000   CHECK_EQ(42, global->Get(some_property)->Int32Value());
16001   // Deleting the property when the interceptor returns an empty
16002   // handle should not delete the property since it is DontDelete.
16003   pass_on_delete = true;
16004   CHECK(!global->Delete(some_property));
16005   CHECK_EQ(2, force_delete_interceptor_count);
16006   CHECK_EQ(42, global->Get(some_property)->Int32Value());
16007   // Forcing the property to be deleted should delete the value
16008   // without calling the interceptor.
16009   CHECK(global->ForceDelete(some_property));
16010   CHECK(global->Get(some_property)->IsUndefined());
16011   CHECK_EQ(2, force_delete_interceptor_count);
16012 }
16013
16014
16015 // Make sure that forcing a delete invalidates any IC stubs, so we
16016 // don't read the hole value.
16017 THREADED_TEST(ForceDeleteIC) {
16018   LocalContext context;
16019   v8::HandleScope scope(context->GetIsolate());
16020   // Create a DontDelete variable on the global object.
16021   CompileRun("this.__proto__ = { foo: 'horse' };"
16022              "var foo = 'fish';"
16023              "function f() { return foo.length; }");
16024   // Initialize the IC for foo in f.
16025   CompileRun("for (var i = 0; i < 4; i++) f();");
16026   // Make sure the value of foo is correct before the deletion.
16027   CHECK_EQ(4, CompileRun("f()")->Int32Value());
16028   // Force the deletion of foo.
16029   CHECK(context->Global()->ForceDelete(v8_str("foo")));
16030   // Make sure the value for foo is read from the prototype, and that
16031   // we don't get in trouble with reading the deleted cell value
16032   // sentinel.
16033   CHECK_EQ(5, CompileRun("f()")->Int32Value());
16034 }
16035
16036
16037 TEST(InlinedFunctionAcrossContexts) {
16038   i::FLAG_allow_natives_syntax = true;
16039   v8::Isolate* isolate = CcTest::isolate();
16040   v8::HandleScope outer_scope(isolate);
16041   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
16042   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
16043   ctx1->Enter();
16044
16045   {
16046     v8::HandleScope inner_scope(CcTest::isolate());
16047     CompileRun("var G = 42; function foo() { return G; }");
16048     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
16049     ctx2->Enter();
16050     ctx2->Global()->Set(v8_str("o"), foo);
16051     v8::Local<v8::Value> res = CompileRun(
16052         "function f() { return o(); }"
16053         "for (var i = 0; i < 10; ++i) f();"
16054         "%OptimizeFunctionOnNextCall(f);"
16055         "f();");
16056     CHECK_EQ(42, res->Int32Value());
16057     ctx2->Exit();
16058     v8::Handle<v8::String> G_property =
16059         v8::String::NewFromUtf8(CcTest::isolate(), "G");
16060     CHECK(ctx1->Global()->ForceDelete(G_property));
16061     ctx2->Enter();
16062     ExpectString(
16063         "(function() {"
16064         "  try {"
16065         "    return f();"
16066         "  } catch(e) {"
16067         "    return e.toString();"
16068         "  }"
16069         " })()",
16070         "ReferenceError: G is not defined");
16071     ctx2->Exit();
16072     ctx1->Exit();
16073   }
16074 }
16075
16076
16077 static v8::Local<Context> calling_context0;
16078 static v8::Local<Context> calling_context1;
16079 static v8::Local<Context> calling_context2;
16080
16081
16082 // Check that the call to the callback is initiated in
16083 // calling_context2, the directly calling context is calling_context1
16084 // and the callback itself is in calling_context0.
16085 static void GetCallingContextCallback(
16086     const v8::FunctionCallbackInfo<v8::Value>& args) {
16087   ApiTestFuzzer::Fuzz();
16088   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
16089   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
16090   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
16091   args.GetReturnValue().Set(42);
16092 }
16093
16094
16095 THREADED_TEST(GetCurrentContextWhenNotInContext) {
16096   i::Isolate* isolate = CcTest::i_isolate();
16097   CHECK(isolate != NULL);
16098   CHECK(isolate->context() == NULL);
16099   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
16100   v8::HandleScope scope(v8_isolate);
16101   // The following should not crash, but return an empty handle.
16102   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
16103   CHECK(current.IsEmpty());
16104 }
16105
16106
16107 THREADED_TEST(GetCallingContext) {
16108   v8::Isolate* isolate = CcTest::isolate();
16109   v8::HandleScope scope(isolate);
16110
16111   Local<Context> calling_context0(Context::New(isolate));
16112   Local<Context> calling_context1(Context::New(isolate));
16113   Local<Context> calling_context2(Context::New(isolate));
16114   ::calling_context0 = calling_context0;
16115   ::calling_context1 = calling_context1;
16116   ::calling_context2 = calling_context2;
16117
16118   // Allow cross-domain access.
16119   Local<String> token = v8_str("<security token>");
16120   calling_context0->SetSecurityToken(token);
16121   calling_context1->SetSecurityToken(token);
16122   calling_context2->SetSecurityToken(token);
16123
16124   // Create an object with a C++ callback in context0.
16125   calling_context0->Enter();
16126   Local<v8::FunctionTemplate> callback_templ =
16127       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
16128   calling_context0->Global()->Set(v8_str("callback"),
16129                                   callback_templ->GetFunction());
16130   calling_context0->Exit();
16131
16132   // Expose context0 in context1 and set up a function that calls the
16133   // callback function.
16134   calling_context1->Enter();
16135   calling_context1->Global()->Set(v8_str("context0"),
16136                                   calling_context0->Global());
16137   CompileRun("function f() { context0.callback() }");
16138   calling_context1->Exit();
16139
16140   // Expose context1 in context2 and call the callback function in
16141   // context0 indirectly through f in context1.
16142   calling_context2->Enter();
16143   calling_context2->Global()->Set(v8_str("context1"),
16144                                   calling_context1->Global());
16145   CompileRun("context1.f()");
16146   calling_context2->Exit();
16147   ::calling_context0.Clear();
16148   ::calling_context1.Clear();
16149   ::calling_context2.Clear();
16150 }
16151
16152
16153 // Check that a variable declaration with no explicit initialization
16154 // value does shadow an existing property in the prototype chain.
16155 THREADED_TEST(InitGlobalVarInProtoChain) {
16156   LocalContext context;
16157   v8::HandleScope scope(context->GetIsolate());
16158   // Introduce a variable in the prototype chain.
16159   CompileRun("__proto__.x = 42");
16160   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
16161   CHECK(!result->IsUndefined());
16162   CHECK_EQ(43, result->Int32Value());
16163 }
16164
16165
16166 // Regression test for issue 398.
16167 // If a function is added to an object, creating a constant function
16168 // field, and the result is cloned, replacing the constant function on the
16169 // original should not affect the clone.
16170 // See http://code.google.com/p/v8/issues/detail?id=398
16171 THREADED_TEST(ReplaceConstantFunction) {
16172   LocalContext context;
16173   v8::Isolate* isolate = context->GetIsolate();
16174   v8::HandleScope scope(isolate);
16175   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16176   v8::Handle<v8::FunctionTemplate> func_templ =
16177       v8::FunctionTemplate::New(isolate);
16178   v8::Handle<v8::String> foo_string =
16179       v8::String::NewFromUtf8(isolate, "foo");
16180   obj->Set(foo_string, func_templ->GetFunction());
16181   v8::Handle<v8::Object> obj_clone = obj->Clone();
16182   obj_clone->Set(foo_string,
16183                  v8::String::NewFromUtf8(isolate, "Hello"));
16184   CHECK(!obj->Get(foo_string)->IsUndefined());
16185 }
16186
16187
16188 static void CheckElementValue(i::Isolate* isolate,
16189                               int expected,
16190                               i::Handle<i::Object> obj,
16191                               int offset) {
16192   i::Object* element =
16193       *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
16194   CHECK_EQ(expected, i::Smi::cast(element)->value());
16195 }
16196
16197
16198 THREADED_TEST(PixelArray) {
16199   LocalContext context;
16200   i::Isolate* isolate = CcTest::i_isolate();
16201   i::Factory* factory = isolate->factory();
16202   v8::HandleScope scope(context->GetIsolate());
16203   const int kElementCount = 260;
16204   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16205   i::Handle<i::ExternalUint8ClampedArray> pixels =
16206       i::Handle<i::ExternalUint8ClampedArray>::cast(
16207           factory->NewExternalArray(kElementCount,
16208                                     v8::kExternalUint8ClampedArray,
16209                                     pixel_data));
16210   // Force GC to trigger verification.
16211   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16212   for (int i = 0; i < kElementCount; i++) {
16213     pixels->set(i, i % 256);
16214   }
16215   // Force GC to trigger verification.
16216   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16217   for (int i = 0; i < kElementCount; i++) {
16218     CHECK_EQ(i % 256, pixels->get_scalar(i));
16219     CHECK_EQ(i % 256, pixel_data[i]);
16220   }
16221
16222   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16223   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16224   // Set the elements to be the pixels.
16225   // jsobj->set_elements(*pixels);
16226   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16227   CheckElementValue(isolate, 1, jsobj, 1);
16228   obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
16229   context->Global()->Set(v8_str("pixels"), obj);
16230   v8::Handle<v8::Value> result = CompileRun("pixels.field");
16231   CHECK_EQ(1503, result->Int32Value());
16232   result = CompileRun("pixels[1]");
16233   CHECK_EQ(1, result->Int32Value());
16234
16235   result = CompileRun("var sum = 0;"
16236                       "for (var i = 0; i < 8; i++) {"
16237                       "  sum += pixels[i] = pixels[i] = -i;"
16238                       "}"
16239                       "sum;");
16240   CHECK_EQ(-28, result->Int32Value());
16241
16242   result = CompileRun("var sum = 0;"
16243                       "for (var i = 0; i < 8; i++) {"
16244                       "  sum += pixels[i] = pixels[i] = 0;"
16245                       "}"
16246                       "sum;");
16247   CHECK_EQ(0, result->Int32Value());
16248
16249   result = CompileRun("var sum = 0;"
16250                       "for (var i = 0; i < 8; i++) {"
16251                       "  sum += pixels[i] = pixels[i] = 255;"
16252                       "}"
16253                       "sum;");
16254   CHECK_EQ(8 * 255, result->Int32Value());
16255
16256   result = CompileRun("var sum = 0;"
16257                       "for (var i = 0; i < 8; i++) {"
16258                       "  sum += pixels[i] = pixels[i] = 256 + i;"
16259                       "}"
16260                       "sum;");
16261   CHECK_EQ(2076, result->Int32Value());
16262
16263   result = CompileRun("var sum = 0;"
16264                       "for (var i = 0; i < 8; i++) {"
16265                       "  sum += pixels[i] = pixels[i] = i;"
16266                       "}"
16267                       "sum;");
16268   CHECK_EQ(28, result->Int32Value());
16269
16270   result = CompileRun("var sum = 0;"
16271                       "for (var i = 0; i < 8; i++) {"
16272                       "  sum += pixels[i];"
16273                       "}"
16274                       "sum;");
16275   CHECK_EQ(28, result->Int32Value());
16276
16277   i::Handle<i::Smi> value(i::Smi::FromInt(2),
16278                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
16279   i::Handle<i::Object> no_failure;
16280   no_failure = i::JSObject::SetElement(
16281       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16282   DCHECK(!no_failure.is_null());
16283   USE(no_failure);
16284   CheckElementValue(isolate, 2, jsobj, 1);
16285   *value.location() = i::Smi::FromInt(256);
16286   no_failure = i::JSObject::SetElement(
16287       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16288   DCHECK(!no_failure.is_null());
16289   USE(no_failure);
16290   CheckElementValue(isolate, 255, jsobj, 1);
16291   *value.location() = i::Smi::FromInt(-1);
16292   no_failure = i::JSObject::SetElement(
16293       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16294   DCHECK(!no_failure.is_null());
16295   USE(no_failure);
16296   CheckElementValue(isolate, 0, jsobj, 1);
16297
16298   result = CompileRun("for (var i = 0; i < 8; i++) {"
16299                       "  pixels[i] = (i * 65) - 109;"
16300                       "}"
16301                       "pixels[1] + pixels[6];");
16302   CHECK_EQ(255, result->Int32Value());
16303   CheckElementValue(isolate, 0, jsobj, 0);
16304   CheckElementValue(isolate, 0, jsobj, 1);
16305   CheckElementValue(isolate, 21, jsobj, 2);
16306   CheckElementValue(isolate, 86, jsobj, 3);
16307   CheckElementValue(isolate, 151, jsobj, 4);
16308   CheckElementValue(isolate, 216, jsobj, 5);
16309   CheckElementValue(isolate, 255, jsobj, 6);
16310   CheckElementValue(isolate, 255, jsobj, 7);
16311   result = CompileRun("var sum = 0;"
16312                       "for (var i = 0; i < 8; i++) {"
16313                       "  sum += pixels[i];"
16314                       "}"
16315                       "sum;");
16316   CHECK_EQ(984, result->Int32Value());
16317
16318   result = CompileRun("for (var i = 0; i < 8; i++) {"
16319                       "  pixels[i] = (i * 1.1);"
16320                       "}"
16321                       "pixels[1] + pixels[6];");
16322   CHECK_EQ(8, result->Int32Value());
16323   CheckElementValue(isolate, 0, jsobj, 0);
16324   CheckElementValue(isolate, 1, jsobj, 1);
16325   CheckElementValue(isolate, 2, jsobj, 2);
16326   CheckElementValue(isolate, 3, jsobj, 3);
16327   CheckElementValue(isolate, 4, jsobj, 4);
16328   CheckElementValue(isolate, 6, jsobj, 5);
16329   CheckElementValue(isolate, 7, jsobj, 6);
16330   CheckElementValue(isolate, 8, jsobj, 7);
16331
16332   result = CompileRun("for (var i = 0; i < 8; i++) {"
16333                       "  pixels[7] = undefined;"
16334                       "}"
16335                       "pixels[7];");
16336   CHECK_EQ(0, result->Int32Value());
16337   CheckElementValue(isolate, 0, jsobj, 7);
16338
16339   result = CompileRun("for (var i = 0; i < 8; i++) {"
16340                       "  pixels[6] = '2.3';"
16341                       "}"
16342                       "pixels[6];");
16343   CHECK_EQ(2, result->Int32Value());
16344   CheckElementValue(isolate, 2, jsobj, 6);
16345
16346   result = CompileRun("for (var i = 0; i < 8; i++) {"
16347                       "  pixels[5] = NaN;"
16348                       "}"
16349                       "pixels[5];");
16350   CHECK_EQ(0, result->Int32Value());
16351   CheckElementValue(isolate, 0, jsobj, 5);
16352
16353   result = CompileRun("for (var i = 0; i < 8; i++) {"
16354                       "  pixels[8] = Infinity;"
16355                       "}"
16356                       "pixels[8];");
16357   CHECK_EQ(255, result->Int32Value());
16358   CheckElementValue(isolate, 255, jsobj, 8);
16359
16360   result = CompileRun("for (var i = 0; i < 8; i++) {"
16361                       "  pixels[9] = -Infinity;"
16362                       "}"
16363                       "pixels[9];");
16364   CHECK_EQ(0, result->Int32Value());
16365   CheckElementValue(isolate, 0, jsobj, 9);
16366
16367   result = CompileRun("pixels[3] = 33;"
16368                       "delete pixels[3];"
16369                       "pixels[3];");
16370   CHECK_EQ(33, result->Int32Value());
16371
16372   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
16373                       "pixels[2] = 12; pixels[3] = 13;"
16374                       "pixels.__defineGetter__('2',"
16375                       "function() { return 120; });"
16376                       "pixels[2];");
16377   CHECK_EQ(12, result->Int32Value());
16378
16379   result = CompileRun("var js_array = new Array(40);"
16380                       "js_array[0] = 77;"
16381                       "js_array;");
16382   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16383
16384   result = CompileRun("pixels[1] = 23;"
16385                       "pixels.__proto__ = [];"
16386                       "js_array.__proto__ = pixels;"
16387                       "js_array.concat(pixels);");
16388   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16389   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16390
16391   result = CompileRun("pixels[1] = 23;");
16392   CHECK_EQ(23, result->Int32Value());
16393
16394   // Test for index greater than 255.  Regression test for:
16395   // http://code.google.com/p/chromium/issues/detail?id=26337.
16396   result = CompileRun("pixels[256] = 255;");
16397   CHECK_EQ(255, result->Int32Value());
16398   result = CompileRun("var i = 0;"
16399                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
16400                       "i");
16401   CHECK_EQ(255, result->Int32Value());
16402
16403   // Make sure that pixel array ICs recognize when a non-pixel array
16404   // is passed to it.
16405   result = CompileRun("function pa_load(p) {"
16406                       "  var sum = 0;"
16407                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16408                       "  return sum;"
16409                       "}"
16410                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16411                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16412                       "just_ints = new Object();"
16413                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16414                       "for (var i = 0; i < 10; ++i) {"
16415                       "  result = pa_load(just_ints);"
16416                       "}"
16417                       "result");
16418   CHECK_EQ(32640, result->Int32Value());
16419
16420   // Make sure that pixel array ICs recognize out-of-bound accesses.
16421   result = CompileRun("function pa_load(p, start) {"
16422                       "  var sum = 0;"
16423                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
16424                       "  return sum;"
16425                       "}"
16426                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16427                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16428                       "for (var i = 0; i < 10; ++i) {"
16429                       "  result = pa_load(pixels,-10);"
16430                       "}"
16431                       "result");
16432   CHECK_EQ(0, result->Int32Value());
16433
16434   // Make sure that generic ICs properly handles a pixel array.
16435   result = CompileRun("function pa_load(p) {"
16436                       "  var sum = 0;"
16437                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16438                       "  return sum;"
16439                       "}"
16440                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16441                       "just_ints = new Object();"
16442                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16443                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16444                       "for (var i = 0; i < 10; ++i) {"
16445                       "  result = pa_load(pixels);"
16446                       "}"
16447                       "result");
16448   CHECK_EQ(32640, result->Int32Value());
16449
16450   // Make sure that generic load ICs recognize out-of-bound accesses in
16451   // pixel arrays.
16452   result = CompileRun("function pa_load(p, start) {"
16453                       "  var sum = 0;"
16454                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
16455                       "  return sum;"
16456                       "}"
16457                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16458                       "just_ints = new Object();"
16459                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16460                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
16461                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16462                       "for (var i = 0; i < 10; ++i) {"
16463                       "  result = pa_load(pixels,-10);"
16464                       "}"
16465                       "result");
16466   CHECK_EQ(0, result->Int32Value());
16467
16468   // Make sure that generic ICs properly handles other types than pixel
16469   // arrays (that the inlined fast pixel array test leaves the right information
16470   // in the right registers).
16471   result = CompileRun("function pa_load(p) {"
16472                       "  var sum = 0;"
16473                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16474                       "  return sum;"
16475                       "}"
16476                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16477                       "just_ints = new Object();"
16478                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16479                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16480                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16481                       "sparse_array = new Object();"
16482                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16483                       "sparse_array[1000000] = 3;"
16484                       "for (var i = 0; i < 10; ++i) {"
16485                       "  result = pa_load(sparse_array);"
16486                       "}"
16487                       "result");
16488   CHECK_EQ(32640, result->Int32Value());
16489
16490   // Make sure that pixel array store ICs clamp values correctly.
16491   result = CompileRun("function pa_store(p) {"
16492                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16493                       "}"
16494                       "pa_store(pixels);"
16495                       "var sum = 0;"
16496                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16497                       "sum");
16498   CHECK_EQ(48896, result->Int32Value());
16499
16500   // Make sure that pixel array stores correctly handle accesses outside
16501   // of the pixel array..
16502   result = CompileRun("function pa_store(p,start) {"
16503                       "  for (var j = 0; j < 256; j++) {"
16504                       "    p[j+start] = j * 2;"
16505                       "  }"
16506                       "}"
16507                       "pa_store(pixels,0);"
16508                       "pa_store(pixels,-128);"
16509                       "var sum = 0;"
16510                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16511                       "sum");
16512   CHECK_EQ(65280, result->Int32Value());
16513
16514   // Make sure that the generic store stub correctly handle accesses outside
16515   // of the pixel array..
16516   result = CompileRun("function pa_store(p,start) {"
16517                       "  for (var j = 0; j < 256; j++) {"
16518                       "    p[j+start] = j * 2;"
16519                       "  }"
16520                       "}"
16521                       "pa_store(pixels,0);"
16522                       "just_ints = new Object();"
16523                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16524                       "pa_store(just_ints, 0);"
16525                       "pa_store(pixels,-128);"
16526                       "var sum = 0;"
16527                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16528                       "sum");
16529   CHECK_EQ(65280, result->Int32Value());
16530
16531   // Make sure that the generic keyed store stub clamps pixel array values
16532   // correctly.
16533   result = CompileRun("function pa_store(p) {"
16534                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16535                       "}"
16536                       "pa_store(pixels);"
16537                       "just_ints = new Object();"
16538                       "pa_store(just_ints);"
16539                       "pa_store(pixels);"
16540                       "var sum = 0;"
16541                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16542                       "sum");
16543   CHECK_EQ(48896, result->Int32Value());
16544
16545   // Make sure that pixel array loads are optimized by crankshaft.
16546   result = CompileRun("function pa_load(p) {"
16547                       "  var sum = 0;"
16548                       "  for (var i=0; i<256; ++i) {"
16549                       "    sum += p[i];"
16550                       "  }"
16551                       "  return sum; "
16552                       "}"
16553                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16554                       "for (var i = 0; i < 5000; ++i) {"
16555                       "  result = pa_load(pixels);"
16556                       "}"
16557                       "result");
16558   CHECK_EQ(32640, result->Int32Value());
16559
16560   // Make sure that pixel array stores are optimized by crankshaft.
16561   result = CompileRun("function pa_init(p) {"
16562                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16563                       "}"
16564                       "function pa_load(p) {"
16565                       "  var sum = 0;"
16566                       "  for (var i=0; i<256; ++i) {"
16567                       "    sum += p[i];"
16568                       "  }"
16569                       "  return sum; "
16570                       "}"
16571                       "for (var i = 0; i < 5000; ++i) {"
16572                       "  pa_init(pixels);"
16573                       "}"
16574                       "result = pa_load(pixels);"
16575                       "result");
16576   CHECK_EQ(32640, result->Int32Value());
16577
16578   free(pixel_data);
16579 }
16580
16581
16582 THREADED_TEST(PixelArrayInfo) {
16583   LocalContext context;
16584   v8::HandleScope scope(context->GetIsolate());
16585   for (int size = 0; size < 100; size += 10) {
16586     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16587     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16588     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16589     CHECK(obj->HasIndexedPropertiesInPixelData());
16590     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16591     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16592     free(pixel_data);
16593   }
16594 }
16595
16596
16597 static void NotHandledIndexedPropertyGetter(
16598     uint32_t index,
16599     const v8::PropertyCallbackInfo<v8::Value>& info) {
16600   ApiTestFuzzer::Fuzz();
16601 }
16602
16603
16604 static void NotHandledIndexedPropertySetter(
16605     uint32_t index,
16606     Local<Value> value,
16607     const v8::PropertyCallbackInfo<v8::Value>& info) {
16608   ApiTestFuzzer::Fuzz();
16609 }
16610
16611
16612 THREADED_TEST(PixelArrayWithInterceptor) {
16613   LocalContext context;
16614   i::Factory* factory = CcTest::i_isolate()->factory();
16615   v8::Isolate* isolate = context->GetIsolate();
16616   v8::HandleScope scope(isolate);
16617   const int kElementCount = 260;
16618   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16619   i::Handle<i::ExternalUint8ClampedArray> pixels =
16620       i::Handle<i::ExternalUint8ClampedArray>::cast(
16621           factory->NewExternalArray(kElementCount,
16622                                     v8::kExternalUint8ClampedArray,
16623                                     pixel_data));
16624   for (int i = 0; i < kElementCount; i++) {
16625     pixels->set(i, i % 256);
16626   }
16627   v8::Handle<v8::ObjectTemplate> templ =
16628       v8::ObjectTemplate::New(context->GetIsolate());
16629   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16630                                    NotHandledIndexedPropertySetter);
16631   v8::Handle<v8::Object> obj = templ->NewInstance();
16632   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16633   context->Global()->Set(v8_str("pixels"), obj);
16634   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16635   CHECK_EQ(1, result->Int32Value());
16636   result = CompileRun("var sum = 0;"
16637                       "for (var i = 0; i < 8; i++) {"
16638                       "  sum += pixels[i] = pixels[i] = -i;"
16639                       "}"
16640                       "sum;");
16641   CHECK_EQ(-28, result->Int32Value());
16642   result = CompileRun("pixels.hasOwnProperty('1')");
16643   CHECK(result->BooleanValue());
16644   free(pixel_data);
16645 }
16646
16647
16648 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16649   switch (array_type) {
16650     case v8::kExternalInt8Array:
16651     case v8::kExternalUint8Array:
16652     case v8::kExternalUint8ClampedArray:
16653       return 1;
16654       break;
16655     case v8::kExternalInt16Array:
16656     case v8::kExternalUint16Array:
16657       return 2;
16658       break;
16659     case v8::kExternalInt32Array:
16660     case v8::kExternalUint32Array:
16661     case v8::kExternalFloat32Array:
16662       return 4;
16663       break;
16664     case v8::kExternalFloat64Array:
16665       return 8;
16666       break;
16667     default:
16668       UNREACHABLE();
16669       return -1;
16670   }
16671   UNREACHABLE();
16672   return -1;
16673 }
16674
16675
16676 template <class ExternalArrayClass, class ElementType>
16677 static void ObjectWithExternalArrayTestHelper(
16678     Handle<Context> context,
16679     v8::Handle<Object> obj,
16680     int element_count,
16681     v8::ExternalArrayType array_type,
16682     int64_t low, int64_t high) {
16683   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16684   i::Isolate* isolate = jsobj->GetIsolate();
16685   obj->Set(v8_str("field"),
16686            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16687   context->Global()->Set(v8_str("ext_array"), obj);
16688   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16689   CHECK_EQ(1503, result->Int32Value());
16690   result = CompileRun("ext_array[1]");
16691   CHECK_EQ(1, result->Int32Value());
16692
16693   // Check assigned smis
16694   result = CompileRun("for (var i = 0; i < 8; i++) {"
16695                       "  ext_array[i] = i;"
16696                       "}"
16697                       "var sum = 0;"
16698                       "for (var i = 0; i < 8; i++) {"
16699                       "  sum += ext_array[i];"
16700                       "}"
16701                       "sum;");
16702
16703   CHECK_EQ(28, result->Int32Value());
16704   // Check pass through of assigned smis
16705   result = CompileRun("var sum = 0;"
16706                       "for (var i = 0; i < 8; i++) {"
16707                       "  sum += ext_array[i] = ext_array[i] = -i;"
16708                       "}"
16709                       "sum;");
16710   CHECK_EQ(-28, result->Int32Value());
16711
16712
16713   // Check assigned smis in reverse order
16714   result = CompileRun("for (var i = 8; --i >= 0; ) {"
16715                       "  ext_array[i] = i;"
16716                       "}"
16717                       "var sum = 0;"
16718                       "for (var i = 0; i < 8; i++) {"
16719                       "  sum += ext_array[i];"
16720                       "}"
16721                       "sum;");
16722   CHECK_EQ(28, result->Int32Value());
16723
16724   // Check pass through of assigned HeapNumbers
16725   result = CompileRun("var sum = 0;"
16726                       "for (var i = 0; i < 16; i+=2) {"
16727                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16728                       "}"
16729                       "sum;");
16730   CHECK_EQ(-28, result->Int32Value());
16731
16732   // Check assigned HeapNumbers
16733   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16734                       "  ext_array[i] = (i * 0.5);"
16735                       "}"
16736                       "var sum = 0;"
16737                       "for (var i = 0; i < 16; i+=2) {"
16738                       "  sum += ext_array[i];"
16739                       "}"
16740                       "sum;");
16741   CHECK_EQ(28, result->Int32Value());
16742
16743   // Check assigned HeapNumbers in reverse order
16744   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16745                       "  ext_array[i] = (i * 0.5);"
16746                       "}"
16747                       "var sum = 0;"
16748                       "for (var i = 0; i < 16; i+=2) {"
16749                       "  sum += ext_array[i];"
16750                       "}"
16751                       "sum;");
16752   CHECK_EQ(28, result->Int32Value());
16753
16754   i::ScopedVector<char> test_buf(1024);
16755
16756   // Check legal boundary conditions.
16757   // The repeated loads and stores ensure the ICs are exercised.
16758   const char* boundary_program =
16759       "var res = 0;"
16760       "for (var i = 0; i < 16; i++) {"
16761       "  ext_array[i] = %lld;"
16762       "  if (i > 8) {"
16763       "    res = ext_array[i];"
16764       "  }"
16765       "}"
16766       "res;";
16767   i::SNPrintF(test_buf,
16768               boundary_program,
16769               low);
16770   result = CompileRun(test_buf.start());
16771   CHECK_EQ(low, result->IntegerValue());
16772
16773   i::SNPrintF(test_buf,
16774               boundary_program,
16775               high);
16776   result = CompileRun(test_buf.start());
16777   CHECK_EQ(high, result->IntegerValue());
16778
16779   // Check misprediction of type in IC.
16780   result = CompileRun("var tmp_array = ext_array;"
16781                       "var sum = 0;"
16782                       "for (var i = 0; i < 8; i++) {"
16783                       "  tmp_array[i] = i;"
16784                       "  sum += tmp_array[i];"
16785                       "  if (i == 4) {"
16786                       "    tmp_array = {};"
16787                       "  }"
16788                       "}"
16789                       "sum;");
16790   // Force GC to trigger verification.
16791   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16792   CHECK_EQ(28, result->Int32Value());
16793
16794   // Make sure out-of-range loads do not throw.
16795   i::SNPrintF(test_buf,
16796               "var caught_exception = false;"
16797               "try {"
16798               "  ext_array[%d];"
16799               "} catch (e) {"
16800               "  caught_exception = true;"
16801               "}"
16802               "caught_exception;",
16803               element_count);
16804   result = CompileRun(test_buf.start());
16805   CHECK_EQ(false, result->BooleanValue());
16806
16807   // Make sure out-of-range stores do not throw.
16808   i::SNPrintF(test_buf,
16809               "var caught_exception = false;"
16810               "try {"
16811               "  ext_array[%d] = 1;"
16812               "} catch (e) {"
16813               "  caught_exception = true;"
16814               "}"
16815               "caught_exception;",
16816               element_count);
16817   result = CompileRun(test_buf.start());
16818   CHECK_EQ(false, result->BooleanValue());
16819
16820   // Check other boundary conditions, values and operations.
16821   result = CompileRun("for (var i = 0; i < 8; i++) {"
16822                       "  ext_array[7] = undefined;"
16823                       "}"
16824                       "ext_array[7];");
16825   CHECK_EQ(0, result->Int32Value());
16826   if (array_type == v8::kExternalFloat64Array ||
16827       array_type == v8::kExternalFloat32Array) {
16828     CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()),
16829              static_cast<int>(
16830                  i::Object::GetElement(
16831                      isolate, jsobj, 7).ToHandleChecked()->Number()));
16832   } else {
16833     CheckElementValue(isolate, 0, jsobj, 7);
16834   }
16835
16836   result = CompileRun("for (var i = 0; i < 8; i++) {"
16837                       "  ext_array[6] = '2.3';"
16838                       "}"
16839                       "ext_array[6];");
16840   CHECK_EQ(2, result->Int32Value());
16841   CHECK_EQ(2,
16842            static_cast<int>(
16843                i::Object::GetElement(
16844                    isolate, jsobj, 6).ToHandleChecked()->Number()));
16845
16846   if (array_type != v8::kExternalFloat32Array &&
16847       array_type != v8::kExternalFloat64Array) {
16848     // Though the specification doesn't state it, be explicit about
16849     // converting NaNs and +/-Infinity to zero.
16850     result = CompileRun("for (var i = 0; i < 8; i++) {"
16851                         "  ext_array[i] = 5;"
16852                         "}"
16853                         "for (var i = 0; i < 8; i++) {"
16854                         "  ext_array[i] = NaN;"
16855                         "}"
16856                         "ext_array[5];");
16857     CHECK_EQ(0, result->Int32Value());
16858     CheckElementValue(isolate, 0, jsobj, 5);
16859
16860     result = CompileRun("for (var i = 0; i < 8; i++) {"
16861                         "  ext_array[i] = 5;"
16862                         "}"
16863                         "for (var i = 0; i < 8; i++) {"
16864                         "  ext_array[i] = Infinity;"
16865                         "}"
16866                         "ext_array[5];");
16867     int expected_value =
16868         (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16869     CHECK_EQ(expected_value, result->Int32Value());
16870     CheckElementValue(isolate, expected_value, jsobj, 5);
16871
16872     result = CompileRun("for (var i = 0; i < 8; i++) {"
16873                         "  ext_array[i] = 5;"
16874                         "}"
16875                         "for (var i = 0; i < 8; i++) {"
16876                         "  ext_array[i] = -Infinity;"
16877                         "}"
16878                         "ext_array[5];");
16879     CHECK_EQ(0, result->Int32Value());
16880     CheckElementValue(isolate, 0, jsobj, 5);
16881
16882     // Check truncation behavior of integral arrays.
16883     const char* unsigned_data =
16884         "var source_data = [0.6, 10.6];"
16885         "var expected_results = [0, 10];";
16886     const char* signed_data =
16887         "var source_data = [0.6, 10.6, -0.6, -10.6];"
16888         "var expected_results = [0, 10, 0, -10];";
16889     const char* pixel_data =
16890         "var source_data = [0.6, 10.6];"
16891         "var expected_results = [1, 11];";
16892     bool is_unsigned =
16893         (array_type == v8::kExternalUint8Array ||
16894          array_type == v8::kExternalUint16Array ||
16895          array_type == v8::kExternalUint32Array);
16896     bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16897
16898     i::SNPrintF(test_buf,
16899                 "%s"
16900                 "var all_passed = true;"
16901                 "for (var i = 0; i < source_data.length; i++) {"
16902                 "  for (var j = 0; j < 8; j++) {"
16903                 "    ext_array[j] = source_data[i];"
16904                 "  }"
16905                 "  all_passed = all_passed &&"
16906                 "               (ext_array[5] == expected_results[i]);"
16907                 "}"
16908                 "all_passed;",
16909                 (is_unsigned ?
16910                      unsigned_data :
16911                      (is_pixel_data ? pixel_data : signed_data)));
16912     result = CompileRun(test_buf.start());
16913     CHECK_EQ(true, result->BooleanValue());
16914   }
16915
16916   i::Handle<ExternalArrayClass> array(
16917       ExternalArrayClass::cast(jsobj->elements()));
16918   for (int i = 0; i < element_count; i++) {
16919     array->set(i, static_cast<ElementType>(i));
16920   }
16921
16922   // Test complex assignments
16923   result = CompileRun("function ee_op_test_complex_func(sum) {"
16924                       " for (var i = 0; i < 40; ++i) {"
16925                       "   sum += (ext_array[i] += 1);"
16926                       "   sum += (ext_array[i] -= 1);"
16927                       " } "
16928                       " return sum;"
16929                       "}"
16930                       "sum=0;"
16931                       "for (var i=0;i<10000;++i) {"
16932                       "  sum=ee_op_test_complex_func(sum);"
16933                       "}"
16934                       "sum;");
16935   CHECK_EQ(16000000, result->Int32Value());
16936
16937   // Test count operations
16938   result = CompileRun("function ee_op_test_count_func(sum) {"
16939                       " for (var i = 0; i < 40; ++i) {"
16940                       "   sum += (++ext_array[i]);"
16941                       "   sum += (--ext_array[i]);"
16942                       " } "
16943                       " return sum;"
16944                       "}"
16945                       "sum=0;"
16946                       "for (var i=0;i<10000;++i) {"
16947                       "  sum=ee_op_test_count_func(sum);"
16948                       "}"
16949                       "sum;");
16950   CHECK_EQ(16000000, result->Int32Value());
16951
16952   result = CompileRun("ext_array[3] = 33;"
16953                       "delete ext_array[3];"
16954                       "ext_array[3];");
16955   CHECK_EQ(33, result->Int32Value());
16956
16957   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16958                       "ext_array[2] = 12; ext_array[3] = 13;"
16959                       "ext_array.__defineGetter__('2',"
16960                       "function() { return 120; });"
16961                       "ext_array[2];");
16962   CHECK_EQ(12, result->Int32Value());
16963
16964   result = CompileRun("var js_array = new Array(40);"
16965                       "js_array[0] = 77;"
16966                       "js_array;");
16967   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16968
16969   result = CompileRun("ext_array[1] = 23;"
16970                       "ext_array.__proto__ = [];"
16971                       "js_array.__proto__ = ext_array;"
16972                       "js_array.concat(ext_array);");
16973   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16974   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16975
16976   result = CompileRun("ext_array[1] = 23;");
16977   CHECK_EQ(23, result->Int32Value());
16978 }
16979
16980
16981 template <class FixedTypedArrayClass,
16982           i::ElementsKind elements_kind,
16983           class ElementType>
16984 static void FixedTypedArrayTestHelper(
16985     v8::ExternalArrayType array_type,
16986     ElementType low,
16987     ElementType high) {
16988   i::FLAG_allow_natives_syntax = true;
16989   LocalContext context;
16990   i::Isolate* isolate = CcTest::i_isolate();
16991   i::Factory* factory = isolate->factory();
16992   v8::HandleScope scope(context->GetIsolate());
16993   const int kElementCount = 260;
16994   i::Handle<FixedTypedArrayClass> fixed_array =
16995     i::Handle<FixedTypedArrayClass>::cast(
16996         factory->NewFixedTypedArray(kElementCount, array_type));
16997   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16998            fixed_array->map()->instance_type());
16999   CHECK_EQ(kElementCount, fixed_array->length());
17000   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17001   for (int i = 0; i < kElementCount; i++) {
17002     fixed_array->set(i, static_cast<ElementType>(i));
17003   }
17004   // Force GC to trigger verification.
17005   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17006   for (int i = 0; i < kElementCount; i++) {
17007     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
17008              static_cast<int64_t>(fixed_array->get_scalar(i)));
17009   }
17010   v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
17011   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17012   i::Handle<i::Map> fixed_array_map =
17013       i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
17014   jsobj->set_map(*fixed_array_map);
17015   jsobj->set_elements(*fixed_array);
17016
17017   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
17018       context.local(), obj, kElementCount, array_type,
17019       static_cast<int64_t>(low),
17020       static_cast<int64_t>(high));
17021 }
17022
17023
17024 THREADED_TEST(FixedUint8Array) {
17025   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
17026     v8::kExternalUint8Array,
17027     0x0, 0xFF);
17028 }
17029
17030
17031 THREADED_TEST(FixedUint8ClampedArray) {
17032   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
17033                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
17034     v8::kExternalUint8ClampedArray,
17035     0x0, 0xFF);
17036 }
17037
17038
17039 THREADED_TEST(FixedInt8Array) {
17040   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
17041     v8::kExternalInt8Array,
17042     -0x80, 0x7F);
17043 }
17044
17045
17046 THREADED_TEST(FixedUint16Array) {
17047   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
17048     v8::kExternalUint16Array,
17049     0x0, 0xFFFF);
17050 }
17051
17052
17053 THREADED_TEST(FixedInt16Array) {
17054   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
17055     v8::kExternalInt16Array,
17056     -0x8000, 0x7FFF);
17057 }
17058
17059
17060 THREADED_TEST(FixedUint32Array) {
17061   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
17062     v8::kExternalUint32Array,
17063     0x0, UINT_MAX);
17064 }
17065
17066
17067 THREADED_TEST(FixedInt32Array) {
17068   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
17069     v8::kExternalInt32Array,
17070     INT_MIN, INT_MAX);
17071 }
17072
17073
17074 THREADED_TEST(FixedFloat32Array) {
17075   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
17076     v8::kExternalFloat32Array,
17077     -500, 500);
17078 }
17079
17080
17081 THREADED_TEST(FixedFloat64Array) {
17082   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
17083     v8::kExternalFloat64Array,
17084     -500, 500);
17085 }
17086
17087
17088 template <class ExternalArrayClass, class ElementType>
17089 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
17090                                     int64_t low,
17091                                     int64_t high) {
17092   LocalContext context;
17093   i::Isolate* isolate = CcTest::i_isolate();
17094   i::Factory* factory = isolate->factory();
17095   v8::HandleScope scope(context->GetIsolate());
17096   const int kElementCount = 40;
17097   int element_size = ExternalArrayElementSize(array_type);
17098   ElementType* array_data =
17099       static_cast<ElementType*>(malloc(kElementCount * element_size));
17100   i::Handle<ExternalArrayClass> array =
17101       i::Handle<ExternalArrayClass>::cast(
17102           factory->NewExternalArray(kElementCount, array_type, array_data));
17103   // Force GC to trigger verification.
17104   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17105   for (int i = 0; i < kElementCount; i++) {
17106     array->set(i, static_cast<ElementType>(i));
17107   }
17108   // Force GC to trigger verification.
17109   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17110   for (int i = 0; i < kElementCount; i++) {
17111     CHECK_EQ(static_cast<int64_t>(i),
17112              static_cast<int64_t>(array->get_scalar(i)));
17113     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
17114   }
17115
17116   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
17117   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17118   // Set the elements to be the external array.
17119   obj->SetIndexedPropertiesToExternalArrayData(array_data,
17120                                                array_type,
17121                                                kElementCount);
17122   CHECK_EQ(1,
17123            static_cast<int>(
17124                i::Object::GetElement(
17125                    isolate, jsobj, 1).ToHandleChecked()->Number()));
17126
17127   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17128       context.local(), obj, kElementCount, array_type, low, high);
17129
17130   v8::Handle<v8::Value> result;
17131
17132   // Test more complex manipulations which cause eax to contain values
17133   // that won't be completely overwritten by loads from the arrays.
17134   // This catches bugs in the instructions used for the KeyedLoadIC
17135   // for byte and word types.
17136   {
17137     const int kXSize = 300;
17138     const int kYSize = 300;
17139     const int kLargeElementCount = kXSize * kYSize * 4;
17140     ElementType* large_array_data =
17141         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
17142     v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
17143     // Set the elements to be the external array.
17144     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
17145                                                        array_type,
17146                                                        kLargeElementCount);
17147     context->Global()->Set(v8_str("large_array"), large_obj);
17148     // Initialize contents of a few rows.
17149     for (int x = 0; x < 300; x++) {
17150       int row = 0;
17151       int offset = row * 300 * 4;
17152       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17153       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17154       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17155       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17156       row = 150;
17157       offset = row * 300 * 4;
17158       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17159       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17160       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17161       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17162       row = 298;
17163       offset = row * 300 * 4;
17164       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17165       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17166       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17167       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17168     }
17169     // The goal of the code below is to make "offset" large enough
17170     // that the computation of the index (which goes into eax) has
17171     // high bits set which will not be overwritten by a byte or short
17172     // load.
17173     result = CompileRun("var failed = false;"
17174                         "var offset = 0;"
17175                         "for (var i = 0; i < 300; i++) {"
17176                         "  if (large_array[4 * i] != 127 ||"
17177                         "      large_array[4 * i + 1] != 0 ||"
17178                         "      large_array[4 * i + 2] != 0 ||"
17179                         "      large_array[4 * i + 3] != 127) {"
17180                         "    failed = true;"
17181                         "  }"
17182                         "}"
17183                         "offset = 150 * 300 * 4;"
17184                         "for (var i = 0; i < 300; i++) {"
17185                         "  if (large_array[offset + 4 * i] != 127 ||"
17186                         "      large_array[offset + 4 * i + 1] != 0 ||"
17187                         "      large_array[offset + 4 * i + 2] != 0 ||"
17188                         "      large_array[offset + 4 * i + 3] != 127) {"
17189                         "    failed = true;"
17190                         "  }"
17191                         "}"
17192                         "offset = 298 * 300 * 4;"
17193                         "for (var i = 0; i < 300; i++) {"
17194                         "  if (large_array[offset + 4 * i] != 127 ||"
17195                         "      large_array[offset + 4 * i + 1] != 0 ||"
17196                         "      large_array[offset + 4 * i + 2] != 0 ||"
17197                         "      large_array[offset + 4 * i + 3] != 127) {"
17198                         "    failed = true;"
17199                         "  }"
17200                         "}"
17201                         "!failed;");
17202     CHECK_EQ(true, result->BooleanValue());
17203     free(large_array_data);
17204   }
17205
17206   // The "" property descriptor is overloaded to store information about
17207   // the external array. Ensure that setting and accessing the "" property
17208   // works (it should overwrite the information cached about the external
17209   // array in the DescriptorArray) in various situations.
17210   result = CompileRun("ext_array[''] = 23; ext_array['']");
17211   CHECK_EQ(23, result->Int32Value());
17212
17213   // Property "" set after the external array is associated with the object.
17214   {
17215     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17216     obj2->Set(v8_str("ee_test_field"),
17217               v8::Int32::New(context->GetIsolate(), 256));
17218     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
17219     // Set the elements to be the external array.
17220     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17221                                                   array_type,
17222                                                   kElementCount);
17223     context->Global()->Set(v8_str("ext_array"), obj2);
17224     result = CompileRun("ext_array['']");
17225     CHECK_EQ(1503, result->Int32Value());
17226   }
17227
17228   // Property "" set after the external array is associated with the object.
17229   {
17230     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17231     obj2->Set(v8_str("ee_test_field_2"),
17232               v8::Int32::New(context->GetIsolate(), 256));
17233     // Set the elements to be the external array.
17234     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17235                                                   array_type,
17236                                                   kElementCount);
17237     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
17238     context->Global()->Set(v8_str("ext_array"), obj2);
17239     result = CompileRun("ext_array['']");
17240     CHECK_EQ(1503, result->Int32Value());
17241   }
17242
17243   // Should reuse the map from previous test.
17244   {
17245     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17246     obj2->Set(v8_str("ee_test_field_2"),
17247               v8::Int32::New(context->GetIsolate(), 256));
17248     // Set the elements to be the external array. Should re-use the map
17249     // from previous test.
17250     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17251                                                   array_type,
17252                                                   kElementCount);
17253     context->Global()->Set(v8_str("ext_array"), obj2);
17254     result = CompileRun("ext_array['']");
17255   }
17256
17257   // Property "" is a constant function that shouldn't not be interfered with
17258   // when an external array is set.
17259   {
17260     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17261     // Start
17262     obj2->Set(v8_str("ee_test_field3"),
17263               v8::Int32::New(context->GetIsolate(), 256));
17264
17265     // Add a constant function to an object.
17266     context->Global()->Set(v8_str("ext_array"), obj2);
17267     result = CompileRun("ext_array[''] = function() {return 1503;};"
17268                         "ext_array['']();");
17269
17270     // Add an external array transition to the same map that
17271     // has the constant transition.
17272     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
17273     obj3->Set(v8_str("ee_test_field3"),
17274               v8::Int32::New(context->GetIsolate(), 256));
17275     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
17276                                                   array_type,
17277                                                   kElementCount);
17278     context->Global()->Set(v8_str("ext_array"), obj3);
17279   }
17280
17281   // If a external array transition is in the map, it should get clobbered
17282   // by a constant function.
17283   {
17284     // Add an external array transition.
17285     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
17286     obj3->Set(v8_str("ee_test_field4"),
17287               v8::Int32::New(context->GetIsolate(), 256));
17288     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
17289                                                   array_type,
17290                                                   kElementCount);
17291
17292     // Add a constant function to the same map that just got an external array
17293     // transition.
17294     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17295     obj2->Set(v8_str("ee_test_field4"),
17296               v8::Int32::New(context->GetIsolate(), 256));
17297     context->Global()->Set(v8_str("ext_array"), obj2);
17298     result = CompileRun("ext_array[''] = function() {return 1503;};"
17299                         "ext_array['']();");
17300   }
17301
17302   free(array_data);
17303 }
17304
17305
17306 THREADED_TEST(ExternalInt8Array) {
17307   ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
17308       v8::kExternalInt8Array,
17309       -128,
17310       127);
17311 }
17312
17313
17314 THREADED_TEST(ExternalUint8Array) {
17315   ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
17316       v8::kExternalUint8Array,
17317       0,
17318       255);
17319 }
17320
17321
17322 THREADED_TEST(ExternalUint8ClampedArray) {
17323   ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
17324       v8::kExternalUint8ClampedArray,
17325       0,
17326       255);
17327 }
17328
17329
17330 THREADED_TEST(ExternalInt16Array) {
17331   ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
17332       v8::kExternalInt16Array,
17333       -32768,
17334       32767);
17335 }
17336
17337
17338 THREADED_TEST(ExternalUint16Array) {
17339   ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
17340       v8::kExternalUint16Array,
17341       0,
17342       65535);
17343 }
17344
17345
17346 THREADED_TEST(ExternalInt32Array) {
17347   ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
17348       v8::kExternalInt32Array,
17349       INT_MIN,   // -2147483648
17350       INT_MAX);  //  2147483647
17351 }
17352
17353
17354 THREADED_TEST(ExternalUint32Array) {
17355   ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
17356       v8::kExternalUint32Array,
17357       0,
17358       UINT_MAX);  // 4294967295
17359 }
17360
17361
17362 THREADED_TEST(ExternalFloat32Array) {
17363   ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
17364       v8::kExternalFloat32Array,
17365       -500,
17366       500);
17367 }
17368
17369
17370 THREADED_TEST(ExternalFloat64Array) {
17371   ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
17372       v8::kExternalFloat64Array,
17373       -500,
17374       500);
17375 }
17376
17377
17378 THREADED_TEST(ExternalArrays) {
17379   TestExternalInt8Array();
17380   TestExternalUint8Array();
17381   TestExternalInt16Array();
17382   TestExternalUint16Array();
17383   TestExternalInt32Array();
17384   TestExternalUint32Array();
17385   TestExternalFloat32Array();
17386 }
17387
17388
17389 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
17390   LocalContext context;
17391   v8::HandleScope scope(context->GetIsolate());
17392   for (int size = 0; size < 100; size += 10) {
17393     int element_size = ExternalArrayElementSize(array_type);
17394     void* external_data = malloc(size * element_size);
17395     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
17396     obj->SetIndexedPropertiesToExternalArrayData(
17397         external_data, array_type, size);
17398     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
17399     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
17400     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
17401     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
17402     free(external_data);
17403   }
17404 }
17405
17406
17407 THREADED_TEST(ExternalArrayInfo) {
17408   ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
17409   ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
17410   ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
17411   ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
17412   ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
17413   ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
17414   ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
17415   ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
17416   ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
17417 }
17418
17419
17420 void ExtArrayLimitsHelper(v8::Isolate* isolate,
17421                           v8::ExternalArrayType array_type,
17422                           int size) {
17423   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
17424   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17425   last_location = last_message = NULL;
17426   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
17427   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
17428   CHECK_NE(NULL, last_location);
17429   CHECK_NE(NULL, last_message);
17430 }
17431
17432
17433 TEST(ExternalArrayLimits) {
17434   LocalContext context;
17435   v8::Isolate* isolate = context->GetIsolate();
17436   v8::HandleScope scope(isolate);
17437   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
17438   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
17439   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
17440   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
17441   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
17442   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
17443   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
17444   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
17445   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
17446   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
17447   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
17448   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
17449   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
17450   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
17451   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
17452   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
17453   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
17454   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
17455 }
17456
17457
17458 template <typename ElementType, typename TypedArray,
17459           class ExternalArrayClass>
17460 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
17461                           int64_t low, int64_t high) {
17462   const int kElementCount = 50;
17463
17464   i::ScopedVector<ElementType> backing_store(kElementCount+2);
17465
17466   LocalContext env;
17467   v8::Isolate* isolate = env->GetIsolate();
17468   v8::HandleScope handle_scope(isolate);
17469
17470   Local<v8::ArrayBuffer> ab =
17471       v8::ArrayBuffer::New(isolate, backing_store.start(),
17472                            (kElementCount + 2) * sizeof(ElementType));
17473   Local<TypedArray> ta =
17474       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17475   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17476   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17477   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17478   CHECK_EQ(kElementCount*sizeof(ElementType),
17479            static_cast<int>(ta->ByteLength()));
17480   CHECK_EQ(ab, ta->Buffer());
17481
17482   ElementType* data = backing_store.start() + 2;
17483   for (int i = 0; i < kElementCount; i++) {
17484     data[i] = static_cast<ElementType>(i);
17485   }
17486
17487   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17488       env.local(), ta, kElementCount, array_type, low, high);
17489 }
17490
17491
17492 THREADED_TEST(Uint8Array) {
17493   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17494       v8::kExternalUint8Array, 0, 0xFF);
17495 }
17496
17497
17498 THREADED_TEST(Int8Array) {
17499   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17500       v8::kExternalInt8Array, -0x80, 0x7F);
17501 }
17502
17503
17504 THREADED_TEST(Uint16Array) {
17505   TypedArrayTestHelper<uint16_t,
17506                        v8::Uint16Array,
17507                        i::ExternalUint16Array>(
17508       v8::kExternalUint16Array, 0, 0xFFFF);
17509 }
17510
17511
17512 THREADED_TEST(Int16Array) {
17513   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17514       v8::kExternalInt16Array, -0x8000, 0x7FFF);
17515 }
17516
17517
17518 THREADED_TEST(Uint32Array) {
17519   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17520       v8::kExternalUint32Array, 0, UINT_MAX);
17521 }
17522
17523
17524 THREADED_TEST(Int32Array) {
17525   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17526       v8::kExternalInt32Array, INT_MIN, INT_MAX);
17527 }
17528
17529
17530 THREADED_TEST(Float32Array) {
17531   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17532       v8::kExternalFloat32Array, -500, 500);
17533 }
17534
17535
17536 THREADED_TEST(Float64Array) {
17537   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17538       v8::kExternalFloat64Array, -500, 500);
17539 }
17540
17541
17542 THREADED_TEST(Uint8ClampedArray) {
17543   TypedArrayTestHelper<uint8_t,
17544                        v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17545       v8::kExternalUint8ClampedArray, 0, 0xFF);
17546 }
17547
17548
17549 THREADED_TEST(DataView) {
17550   const int kSize = 50;
17551
17552   i::ScopedVector<uint8_t> backing_store(kSize+2);
17553
17554   LocalContext env;
17555   v8::Isolate* isolate = env->GetIsolate();
17556   v8::HandleScope handle_scope(isolate);
17557
17558   Local<v8::ArrayBuffer> ab =
17559       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17560   Local<v8::DataView> dv =
17561       v8::DataView::New(ab, 2, kSize);
17562   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17563   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17564   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17565   CHECK_EQ(ab, dv->Buffer());
17566 }
17567
17568
17569 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
17570   THREADED_TEST(Is##View) {                                                   \
17571     LocalContext env;                                                         \
17572     v8::Isolate* isolate = env->GetIsolate();                                 \
17573     v8::HandleScope handle_scope(isolate);                                    \
17574                                                                               \
17575     Handle<Value> result = CompileRun(                                        \
17576         "var ab = new ArrayBuffer(128);"                                      \
17577         "new " #View "(ab)");                                                 \
17578     CHECK(result->IsArrayBufferView());                                       \
17579     CHECK(result->Is##View());                                                \
17580     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
17581   }
17582
17583 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17584 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17585 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17586 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17587 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17588 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17589 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17590 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17591 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17592 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17593
17594 #undef IS_ARRAY_BUFFER_VIEW_TEST
17595
17596
17597
17598 THREADED_TEST(ScriptContextDependence) {
17599   LocalContext c1;
17600   v8::HandleScope scope(c1->GetIsolate());
17601   const char *source = "foo";
17602   v8::Handle<v8::Script> dep = v8_compile(source);
17603   v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17604       c1->GetIsolate(), source));
17605   v8::Handle<v8::UnboundScript> indep =
17606       v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17607   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17608                     v8::Integer::New(c1->GetIsolate(), 100));
17609   CHECK_EQ(dep->Run()->Int32Value(), 100);
17610   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17611   LocalContext c2;
17612   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17613                     v8::Integer::New(c2->GetIsolate(), 101));
17614   CHECK_EQ(dep->Run()->Int32Value(), 100);
17615   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17616 }
17617
17618
17619 THREADED_TEST(StackTrace) {
17620   LocalContext context;
17621   v8::HandleScope scope(context->GetIsolate());
17622   v8::TryCatch try_catch;
17623   const char *source = "function foo() { FAIL.FAIL; }; foo();";
17624   v8::Handle<v8::String> src =
17625       v8::String::NewFromUtf8(context->GetIsolate(), source);
17626   v8::Handle<v8::String> origin =
17627       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17628   v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17629   v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17630       ->BindToCurrentContext()
17631       ->Run();
17632   CHECK(try_catch.HasCaught());
17633   v8::String::Utf8Value stack(try_catch.StackTrace());
17634   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17635 }
17636
17637
17638 // Checks that a StackFrame has certain expected values.
17639 void checkStackFrame(const char* expected_script_name,
17640     const char* expected_func_name, int expected_line_number,
17641     int expected_column, bool is_eval, bool is_constructor,
17642     v8::Handle<v8::StackFrame> frame) {
17643   v8::HandleScope scope(CcTest::isolate());
17644   v8::String::Utf8Value func_name(frame->GetFunctionName());
17645   v8::String::Utf8Value script_name(frame->GetScriptName());
17646   if (*script_name == NULL) {
17647     // The situation where there is no associated script, like for evals.
17648     CHECK(expected_script_name == NULL);
17649   } else {
17650     CHECK(strstr(*script_name, expected_script_name) != NULL);
17651   }
17652   CHECK(strstr(*func_name, expected_func_name) != NULL);
17653   CHECK_EQ(expected_line_number, frame->GetLineNumber());
17654   CHECK_EQ(expected_column, frame->GetColumn());
17655   CHECK_EQ(is_eval, frame->IsEval());
17656   CHECK_EQ(is_constructor, frame->IsConstructor());
17657 }
17658
17659
17660 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17661   v8::HandleScope scope(args.GetIsolate());
17662   const char* origin = "capture-stack-trace-test";
17663   const int kOverviewTest = 1;
17664   const int kDetailedTest = 2;
17665
17666   DCHECK(args.Length() == 1);
17667
17668   int testGroup = args[0]->Int32Value();
17669   if (testGroup == kOverviewTest) {
17670     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17671         args.GetIsolate(), 10, v8::StackTrace::kOverview);
17672     CHECK_EQ(4, stackTrace->GetFrameCount());
17673     checkStackFrame(origin, "bar", 2, 10, false, false,
17674                     stackTrace->GetFrame(0));
17675     checkStackFrame(origin, "foo", 6, 3, false, false,
17676                     stackTrace->GetFrame(1));
17677     // This is the source string inside the eval which has the call to foo.
17678     checkStackFrame(NULL, "", 1, 5, false, false,
17679                     stackTrace->GetFrame(2));
17680     // The last frame is an anonymous function which has the initial eval call.
17681     checkStackFrame(origin, "", 8, 7, false, false,
17682                     stackTrace->GetFrame(3));
17683
17684     CHECK(stackTrace->AsArray()->IsArray());
17685   } else if (testGroup == kDetailedTest) {
17686     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17687         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17688     CHECK_EQ(4, stackTrace->GetFrameCount());
17689     checkStackFrame(origin, "bat", 4, 22, false, false,
17690                     stackTrace->GetFrame(0));
17691     checkStackFrame(origin, "baz", 8, 3, false, true,
17692                     stackTrace->GetFrame(1));
17693     bool is_eval = true;
17694     // This is the source string inside the eval which has the call to baz.
17695     checkStackFrame(NULL, "", 1, 5, is_eval, false,
17696                     stackTrace->GetFrame(2));
17697     // The last frame is an anonymous function which has the initial eval call.
17698     checkStackFrame(origin, "", 10, 1, false, false,
17699                     stackTrace->GetFrame(3));
17700
17701     CHECK(stackTrace->AsArray()->IsArray());
17702   }
17703 }
17704
17705
17706 // Tests the C++ StackTrace API.
17707 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17708 // THREADED_TEST(CaptureStackTrace) {
17709 TEST(CaptureStackTrace) {
17710   v8::Isolate* isolate = CcTest::isolate();
17711   v8::HandleScope scope(isolate);
17712   v8::Handle<v8::String> origin =
17713       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17714   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17715   templ->Set(v8_str("AnalyzeStackInNativeCode"),
17716              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17717   LocalContext context(0, templ);
17718
17719   // Test getting OVERVIEW information. Should ignore information that is not
17720   // script name, function name, line number, and column offset.
17721   const char *overview_source =
17722     "function bar() {\n"
17723     "  var y; AnalyzeStackInNativeCode(1);\n"
17724     "}\n"
17725     "function foo() {\n"
17726     "\n"
17727     "  bar();\n"
17728     "}\n"
17729     "var x;eval('new foo();');";
17730   v8::Handle<v8::String> overview_src =
17731       v8::String::NewFromUtf8(isolate, overview_source);
17732   v8::ScriptCompiler::Source script_source(overview_src,
17733                                            v8::ScriptOrigin(origin));
17734   v8::Handle<Value> overview_result(
17735       v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17736           ->BindToCurrentContext()
17737           ->Run());
17738   CHECK(!overview_result.IsEmpty());
17739   CHECK(overview_result->IsObject());
17740
17741   // Test getting DETAILED information.
17742   const char *detailed_source =
17743     "function bat() {AnalyzeStackInNativeCode(2);\n"
17744     "}\n"
17745     "\n"
17746     "function baz() {\n"
17747     "  bat();\n"
17748     "}\n"
17749     "eval('new baz();');";
17750   v8::Handle<v8::String> detailed_src =
17751       v8::String::NewFromUtf8(isolate, detailed_source);
17752   // Make the script using a non-zero line and column offset.
17753   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17754   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17755   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17756   v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17757   v8::Handle<v8::UnboundScript> detailed_script(
17758       v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17759   v8::Handle<Value> detailed_result(
17760       detailed_script->BindToCurrentContext()->Run());
17761   CHECK(!detailed_result.IsEmpty());
17762   CHECK(detailed_result->IsObject());
17763 }
17764
17765
17766 static void StackTraceForUncaughtExceptionListener(
17767     v8::Handle<v8::Message> message,
17768     v8::Handle<Value>) {
17769   report_count++;
17770   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17771   CHECK_EQ(2, stack_trace->GetFrameCount());
17772   checkStackFrame("origin", "foo", 2, 3, false, false,
17773                   stack_trace->GetFrame(0));
17774   checkStackFrame("origin", "bar", 5, 3, false, false,
17775                   stack_trace->GetFrame(1));
17776 }
17777
17778
17779 TEST(CaptureStackTraceForUncaughtException) {
17780   report_count = 0;
17781   LocalContext env;
17782   v8::HandleScope scope(env->GetIsolate());
17783   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17784   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17785
17786   CompileRunWithOrigin(
17787       "function foo() {\n"
17788       "  throw 1;\n"
17789       "};\n"
17790       "function bar() {\n"
17791       "  foo();\n"
17792       "};",
17793       "origin");
17794   v8::Local<v8::Object> global = env->Global();
17795   Local<Value> trouble = global->Get(v8_str("bar"));
17796   CHECK(trouble->IsFunction());
17797   Function::Cast(*trouble)->Call(global, 0, NULL);
17798   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17799   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17800   CHECK_EQ(1, report_count);
17801 }
17802
17803
17804 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
17805   report_count = 0;
17806   LocalContext env;
17807   v8::HandleScope scope(env->GetIsolate());
17808
17809   // Create an Error object first.
17810   CompileRunWithOrigin(
17811       "function foo() {\n"
17812       "e=new Error('err');\n"
17813       "};\n"
17814       "function bar() {\n"
17815       "  foo();\n"
17816       "};\n"
17817       "var e;",
17818       "origin");
17819   v8::Local<v8::Object> global = env->Global();
17820   Local<Value> trouble = global->Get(v8_str("bar"));
17821   CHECK(trouble->IsFunction());
17822   Function::Cast(*trouble)->Call(global, 0, NULL);
17823
17824   // Enable capturing detailed stack trace late, and throw the exception.
17825   // The detailed stack trace should be extracted from the simple stack.
17826   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17827   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17828   CompileRunWithOrigin("throw e", "origin");
17829   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17830   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17831   CHECK_EQ(1, report_count);
17832 }
17833
17834
17835 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17836   LocalContext env;
17837   v8::HandleScope scope(env->GetIsolate());
17838   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17839                                                     1024,
17840                                                     v8::StackTrace::kDetailed);
17841
17842   CompileRun(
17843       "var setters = ['column', 'lineNumber', 'scriptName',\n"
17844       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17845       "    'isConstructor'];\n"
17846       "for (var i = 0; i < setters.length; i++) {\n"
17847       "  var prop = setters[i];\n"
17848       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17849       "}\n");
17850   CompileRun("throw 'exception';");
17851   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17852 }
17853
17854
17855 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17856                                      v8::Handle<v8::Value> data) {
17857   // Use the frame where JavaScript is called from.
17858   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17859   CHECK(!stack_trace.IsEmpty());
17860   int frame_count = stack_trace->GetFrameCount();
17861   CHECK_EQ(3, frame_count);
17862   int line_number[] = {1, 2, 5};
17863   for (int i = 0; i < frame_count; i++) {
17864     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17865   }
17866 }
17867
17868
17869 // Test that we only return the stack trace at the site where the exception
17870 // is first thrown (not where it is rethrown).
17871 TEST(RethrowStackTrace) {
17872   LocalContext env;
17873   v8::HandleScope scope(env->GetIsolate());
17874   // We make sure that
17875   // - the stack trace of the ReferenceError in g() is reported.
17876   // - the stack trace is not overwritten when e1 is rethrown by t().
17877   // - the stack trace of e2 does not overwrite that of e1.
17878   const char* source =
17879       "function g() { error; }          \n"
17880       "function f() { g(); }            \n"
17881       "function t(e) { throw e; }       \n"
17882       "try {                            \n"
17883       "  f();                           \n"
17884       "} catch (e1) {                   \n"
17885       "  try {                          \n"
17886       "    error;                       \n"
17887       "  } catch (e2) {                 \n"
17888       "    t(e1);                       \n"
17889       "  }                              \n"
17890       "}                                \n";
17891   v8::V8::AddMessageListener(RethrowStackTraceHandler);
17892   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17893   CompileRun(source);
17894   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17895   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17896 }
17897
17898
17899 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17900                                               v8::Handle<v8::Value> data) {
17901   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17902   CHECK(!stack_trace.IsEmpty());
17903   int frame_count = stack_trace->GetFrameCount();
17904   CHECK_EQ(2, frame_count);
17905   int line_number[] = {3, 7};
17906   for (int i = 0; i < frame_count; i++) {
17907     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17908   }
17909 }
17910
17911
17912 // Test that we do not recognize identity for primitive exceptions.
17913 TEST(RethrowPrimitiveStackTrace) {
17914   LocalContext env;
17915   v8::HandleScope scope(env->GetIsolate());
17916   // We do not capture stack trace for non Error objects on creation time.
17917   // Instead, we capture the stack trace on last throw.
17918   const char* source =
17919       "function g() { throw 404; }      \n"
17920       "function f() { g(); }            \n"
17921       "function t(e) { throw e; }       \n"
17922       "try {                            \n"
17923       "  f();                           \n"
17924       "} catch (e1) {                   \n"
17925       "  t(e1)                          \n"
17926       "}                                \n";
17927   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17928   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17929   CompileRun(source);
17930   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17931   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17932 }
17933
17934
17935 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17936                                               v8::Handle<v8::Value> data) {
17937   // Use the frame where JavaScript is called from.
17938   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17939   CHECK(!stack_trace.IsEmpty());
17940   CHECK_EQ(1, stack_trace->GetFrameCount());
17941   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17942 }
17943
17944
17945 // Test that the stack trace is captured when the error object is created and
17946 // not where it is thrown.
17947 TEST(RethrowExistingStackTrace) {
17948   LocalContext env;
17949   v8::HandleScope scope(env->GetIsolate());
17950   const char* source =
17951       "var e = new Error();           \n"
17952       "throw e;                       \n";
17953   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17954   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17955   CompileRun(source);
17956   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17957   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17958 }
17959
17960
17961 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17962                                                v8::Handle<v8::Value> data) {
17963   // Use the frame where JavaScript is called from.
17964   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17965   CHECK(!stack_trace.IsEmpty());
17966   CHECK_EQ(1, stack_trace->GetFrameCount());
17967   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17968 }
17969
17970
17971 // Test that the stack trace is captured where the bogus Error object is thrown.
17972 TEST(RethrowBogusErrorStackTrace) {
17973   LocalContext env;
17974   v8::HandleScope scope(env->GetIsolate());
17975   const char* source =
17976       "var e = {__proto__: new Error()} \n"
17977       "throw e;                         \n";
17978   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17979   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17980   CompileRun(source);
17981   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17982   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17983 }
17984
17985
17986 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
17987 int promise_reject_counter = 0;
17988 int promise_revoke_counter = 0;
17989 int promise_reject_line_number = -1;
17990 int promise_reject_frame_count = -1;
17991
17992 void PromiseRejectCallback(v8::PromiseRejectMessage message) {
17993   if (message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
17994     promise_reject_counter++;
17995     CcTest::global()->Set(v8_str("rejected"), message.GetPromise());
17996     CcTest::global()->Set(v8_str("value"), message.GetValue());
17997     v8::Handle<v8::StackTrace> stack_trace =
17998         v8::Exception::GetMessage(message.GetValue())->GetStackTrace();
17999     if (!stack_trace.IsEmpty()) {
18000       promise_reject_frame_count = stack_trace->GetFrameCount();
18001       if (promise_reject_frame_count > 0) {
18002         CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
18003         promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
18004       } else {
18005         promise_reject_line_number = -1;
18006       }
18007     }
18008   } else {
18009     promise_revoke_counter++;
18010     CcTest::global()->Set(v8_str("revoked"), message.GetPromise());
18011     CHECK(message.GetValue().IsEmpty());
18012   }
18013 }
18014
18015
18016 v8::Handle<v8::Promise> GetPromise(const char* name) {
18017   return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
18018 }
18019
18020
18021 v8::Handle<v8::Value> RejectValue() {
18022   return CcTest::global()->Get(v8_str("value"));
18023 }
18024
18025
18026 void ResetPromiseStates() {
18027   promise_reject_counter = 0;
18028   promise_revoke_counter = 0;
18029   promise_reject_line_number = -1;
18030   promise_reject_frame_count = -1;
18031   CcTest::global()->Set(v8_str("rejected"), v8_str(""));
18032   CcTest::global()->Set(v8_str("value"), v8_str(""));
18033   CcTest::global()->Set(v8_str("revoked"), v8_str(""));
18034 }
18035
18036
18037 TEST(PromiseRejectCallback) {
18038   LocalContext env;
18039   v8::Isolate* isolate = env->GetIsolate();
18040   v8::HandleScope scope(isolate);
18041
18042   isolate->SetPromiseRejectCallback(PromiseRejectCallback);
18043
18044   ResetPromiseStates();
18045
18046   // Create promise p0.
18047   CompileRun(
18048       "var reject;            \n"
18049       "var p0 = new Promise(  \n"
18050       "  function(res, rej) { \n"
18051       "    reject = rej;      \n"
18052       "  }                    \n"
18053       ");                     \n");
18054   CHECK(!GetPromise("p0")->HasHandler());
18055   CHECK_EQ(0, promise_reject_counter);
18056   CHECK_EQ(0, promise_revoke_counter);
18057
18058   // Add resolve handler (and default reject handler) to p0.
18059   CompileRun("var p1 = p0.then(function(){});");
18060   CHECK(GetPromise("p0")->HasHandler());
18061   CHECK(!GetPromise("p1")->HasHandler());
18062   CHECK_EQ(0, promise_reject_counter);
18063   CHECK_EQ(0, promise_revoke_counter);
18064
18065   // Reject p0.
18066   CompileRun("reject('ppp');");
18067   CHECK(GetPromise("p0")->HasHandler());
18068   CHECK(!GetPromise("p1")->HasHandler());
18069   CHECK_EQ(1, promise_reject_counter);
18070   CHECK_EQ(0, promise_revoke_counter);
18071   CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
18072   CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
18073   CHECK(RejectValue()->Equals(v8_str("ppp")));
18074
18075   // Reject p0 again. Callback is not triggered again.
18076   CompileRun("reject();");
18077   CHECK(GetPromise("p0")->HasHandler());
18078   CHECK(!GetPromise("p1")->HasHandler());
18079   CHECK_EQ(1, promise_reject_counter);
18080   CHECK_EQ(0, promise_revoke_counter);
18081
18082   // Add resolve handler to p1.
18083   CompileRun("var p2 = p1.then(function(){});");
18084   CHECK(GetPromise("p0")->HasHandler());
18085   CHECK(GetPromise("p1")->HasHandler());
18086   CHECK(!GetPromise("p2")->HasHandler());
18087   CHECK_EQ(2, promise_reject_counter);
18088   CHECK_EQ(1, promise_revoke_counter);
18089   CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
18090   CHECK(RejectValue()->Equals(v8_str("ppp")));
18091   CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
18092
18093   ResetPromiseStates();
18094
18095   // Create promise q0.
18096   CompileRun(
18097       "var q0 = new Promise(  \n"
18098       "  function(res, rej) { \n"
18099       "    reject = rej;      \n"
18100       "  }                    \n"
18101       ");                     \n");
18102   CHECK(!GetPromise("q0")->HasHandler());
18103   CHECK_EQ(0, promise_reject_counter);
18104   CHECK_EQ(0, promise_revoke_counter);
18105
18106   // Add reject handler to q0.
18107   CompileRun("var q1 = q0.catch(function() {});");
18108   CHECK(GetPromise("q0")->HasHandler());
18109   CHECK(!GetPromise("q1")->HasHandler());
18110   CHECK_EQ(0, promise_reject_counter);
18111   CHECK_EQ(0, promise_revoke_counter);
18112
18113   // Reject q0.
18114   CompileRun("reject('qq')");
18115   CHECK(GetPromise("q0")->HasHandler());
18116   CHECK(!GetPromise("q1")->HasHandler());
18117   CHECK_EQ(0, promise_reject_counter);
18118   CHECK_EQ(0, promise_revoke_counter);
18119
18120   // Add a new reject handler, which rejects by returning Promise.reject().
18121   // The returned promise q_ triggers a reject callback at first, only to
18122   // revoke it when returning it causes q2 to be rejected.
18123   CompileRun(
18124       "var q_;"
18125       "var q2 = q0.catch(               \n"
18126       "   function() {                  \n"
18127       "     q_ = Promise.reject('qqq'); \n"
18128       "     return q_;                  \n"
18129       "   }                             \n"
18130       ");                               \n");
18131   CHECK(GetPromise("q0")->HasHandler());
18132   CHECK(!GetPromise("q1")->HasHandler());
18133   CHECK(!GetPromise("q2")->HasHandler());
18134   CHECK(GetPromise("q_")->HasHandler());
18135   CHECK_EQ(2, promise_reject_counter);
18136   CHECK_EQ(1, promise_revoke_counter);
18137   CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
18138   CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
18139   CHECK(RejectValue()->Equals(v8_str("qqq")));
18140
18141   // Add a reject handler to the resolved q1, which rejects by throwing.
18142   CompileRun(
18143       "var q3 = q1.then(  \n"
18144       "   function() {    \n"
18145       "     throw 'qqqq'; \n"
18146       "   }               \n"
18147       ");                 \n");
18148   CHECK(GetPromise("q0")->HasHandler());
18149   CHECK(GetPromise("q1")->HasHandler());
18150   CHECK(!GetPromise("q2")->HasHandler());
18151   CHECK(!GetPromise("q3")->HasHandler());
18152   CHECK_EQ(3, promise_reject_counter);
18153   CHECK_EQ(1, promise_revoke_counter);
18154   CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
18155   CHECK(RejectValue()->Equals(v8_str("qqqq")));
18156
18157   ResetPromiseStates();
18158
18159   // Create promise r0, which has three handlers, two of which handle rejects.
18160   CompileRun(
18161       "var r0 = new Promise(             \n"
18162       "  function(res, rej) {            \n"
18163       "    reject = rej;                 \n"
18164       "  }                               \n"
18165       ");                                \n"
18166       "var r1 = r0.catch(function() {}); \n"
18167       "var r2 = r0.then(function() {});  \n"
18168       "var r3 = r0.then(function() {},   \n"
18169       "                 function() {});  \n");
18170   CHECK(GetPromise("r0")->HasHandler());
18171   CHECK(!GetPromise("r1")->HasHandler());
18172   CHECK(!GetPromise("r2")->HasHandler());
18173   CHECK(!GetPromise("r3")->HasHandler());
18174   CHECK_EQ(0, promise_reject_counter);
18175   CHECK_EQ(0, promise_revoke_counter);
18176
18177   // Reject r0.
18178   CompileRun("reject('rrr')");
18179   CHECK(GetPromise("r0")->HasHandler());
18180   CHECK(!GetPromise("r1")->HasHandler());
18181   CHECK(!GetPromise("r2")->HasHandler());
18182   CHECK(!GetPromise("r3")->HasHandler());
18183   CHECK_EQ(1, promise_reject_counter);
18184   CHECK_EQ(0, promise_revoke_counter);
18185   CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
18186   CHECK(RejectValue()->Equals(v8_str("rrr")));
18187
18188   // Add reject handler to r2.
18189   CompileRun("var r4 = r2.catch(function() {});");
18190   CHECK(GetPromise("r0")->HasHandler());
18191   CHECK(!GetPromise("r1")->HasHandler());
18192   CHECK(GetPromise("r2")->HasHandler());
18193   CHECK(!GetPromise("r3")->HasHandler());
18194   CHECK(!GetPromise("r4")->HasHandler());
18195   CHECK_EQ(1, promise_reject_counter);
18196   CHECK_EQ(1, promise_revoke_counter);
18197   CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
18198   CHECK(RejectValue()->Equals(v8_str("rrr")));
18199
18200   // Add reject handlers to r4.
18201   CompileRun("var r5 = r4.then(function() {}, function() {});");
18202   CHECK(GetPromise("r0")->HasHandler());
18203   CHECK(!GetPromise("r1")->HasHandler());
18204   CHECK(GetPromise("r2")->HasHandler());
18205   CHECK(!GetPromise("r3")->HasHandler());
18206   CHECK(GetPromise("r4")->HasHandler());
18207   CHECK(!GetPromise("r5")->HasHandler());
18208   CHECK_EQ(1, promise_reject_counter);
18209   CHECK_EQ(1, promise_revoke_counter);
18210
18211   ResetPromiseStates();
18212
18213   // Create promise s0, which has three handlers, none of which handle rejects.
18214   CompileRun(
18215       "var s0 = new Promise(            \n"
18216       "  function(res, rej) {           \n"
18217       "    reject = rej;                \n"
18218       "  }                              \n"
18219       ");                               \n"
18220       "var s1 = s0.then(function() {}); \n"
18221       "var s2 = s0.then(function() {}); \n"
18222       "var s3 = s0.then(function() {}); \n");
18223   CHECK(GetPromise("s0")->HasHandler());
18224   CHECK(!GetPromise("s1")->HasHandler());
18225   CHECK(!GetPromise("s2")->HasHandler());
18226   CHECK(!GetPromise("s3")->HasHandler());
18227   CHECK_EQ(0, promise_reject_counter);
18228   CHECK_EQ(0, promise_revoke_counter);
18229
18230   // Reject s0.
18231   CompileRun("reject('sss')");
18232   CHECK(GetPromise("s0")->HasHandler());
18233   CHECK(!GetPromise("s1")->HasHandler());
18234   CHECK(!GetPromise("s2")->HasHandler());
18235   CHECK(!GetPromise("s3")->HasHandler());
18236   CHECK_EQ(3, promise_reject_counter);
18237   CHECK_EQ(0, promise_revoke_counter);
18238   CHECK(RejectValue()->Equals(v8_str("sss")));
18239
18240   // Test stack frames.
18241   V8::SetCaptureStackTraceForUncaughtExceptions(true);
18242
18243   ResetPromiseStates();
18244
18245   // Create promise t0, which is rejected in the constructor with an error.
18246   CompileRunWithOrigin(
18247       "var t0 = new Promise(  \n"
18248       "  function(res, rej) { \n"
18249       "    reference_error;   \n"
18250       "  }                    \n"
18251       ");                     \n",
18252       "pro", 0, 0);
18253   CHECK(!GetPromise("t0")->HasHandler());
18254   CHECK_EQ(1, promise_reject_counter);
18255   CHECK_EQ(0, promise_revoke_counter);
18256   CHECK_EQ(2, promise_reject_frame_count);
18257   CHECK_EQ(3, promise_reject_line_number);
18258
18259   ResetPromiseStates();
18260
18261   // Create promise u0 and chain u1 to it, which is rejected via throw.
18262   CompileRunWithOrigin(
18263       "var u0 = Promise.resolve();        \n"
18264       "var u1 = u0.then(                  \n"
18265       "           function() {            \n"
18266       "             (function() {         \n"
18267       "                throw new Error(); \n"
18268       "              })();                \n"
18269       "           }                       \n"
18270       "         );                        \n",
18271       "pro", 0, 0);
18272   CHECK(GetPromise("u0")->HasHandler());
18273   CHECK(!GetPromise("u1")->HasHandler());
18274   CHECK_EQ(1, promise_reject_counter);
18275   CHECK_EQ(0, promise_revoke_counter);
18276   CHECK_EQ(2, promise_reject_frame_count);
18277   CHECK_EQ(5, promise_reject_line_number);
18278
18279   // Throw in u3, which handles u1's rejection.
18280   CompileRunWithOrigin(
18281       "function f() {                \n"
18282       "  return (function() {        \n"
18283       "    return new Error();       \n"
18284       "  })();                       \n"
18285       "}                             \n"
18286       "var u2 = Promise.reject(f()); \n"
18287       "var u3 = u1.catch(            \n"
18288       "           function() {       \n"
18289       "             return u2;       \n"
18290       "           }                  \n"
18291       "         );                   \n",
18292       "pro", 0, 0);
18293   CHECK(GetPromise("u0")->HasHandler());
18294   CHECK(GetPromise("u1")->HasHandler());
18295   CHECK(GetPromise("u2")->HasHandler());
18296   CHECK(!GetPromise("u3")->HasHandler());
18297   CHECK_EQ(3, promise_reject_counter);
18298   CHECK_EQ(2, promise_revoke_counter);
18299   CHECK_EQ(3, promise_reject_frame_count);
18300   CHECK_EQ(3, promise_reject_line_number);
18301
18302   ResetPromiseStates();
18303
18304   // Create promise rejected promise v0, which is incorrectly handled by v1
18305   // via chaining cycle.
18306   CompileRunWithOrigin(
18307       "var v0 = Promise.reject(); \n"
18308       "var v1 = v0.catch(         \n"
18309       "           function() {    \n"
18310       "             return v1;    \n"
18311       "           }               \n"
18312       "         );                \n",
18313       "pro", 0, 0);
18314   CHECK(GetPromise("v0")->HasHandler());
18315   CHECK(!GetPromise("v1")->HasHandler());
18316   CHECK_EQ(2, promise_reject_counter);
18317   CHECK_EQ(1, promise_revoke_counter);
18318   CHECK_EQ(0, promise_reject_frame_count);
18319   CHECK_EQ(-1, promise_reject_line_number);
18320 }
18321
18322
18323 void AnalyzeStackOfEvalWithSourceURL(
18324     const v8::FunctionCallbackInfo<v8::Value>& args) {
18325   v8::HandleScope scope(args.GetIsolate());
18326   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18327       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18328   CHECK_EQ(5, stackTrace->GetFrameCount());
18329   v8::Handle<v8::String> url = v8_str("eval_url");
18330   for (int i = 0; i < 3; i++) {
18331     v8::Handle<v8::String> name =
18332         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18333     CHECK(!name.IsEmpty());
18334     CHECK_EQ(url, name);
18335   }
18336 }
18337
18338
18339 TEST(SourceURLInStackTrace) {
18340   v8::Isolate* isolate = CcTest::isolate();
18341   v8::HandleScope scope(isolate);
18342   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18343   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
18344              v8::FunctionTemplate::New(isolate,
18345                                        AnalyzeStackOfEvalWithSourceURL));
18346   LocalContext context(0, templ);
18347
18348   const char *source =
18349     "function outer() {\n"
18350     "function bar() {\n"
18351     "  AnalyzeStackOfEvalWithSourceURL();\n"
18352     "}\n"
18353     "function foo() {\n"
18354     "\n"
18355     "  bar();\n"
18356     "}\n"
18357     "foo();\n"
18358     "}\n"
18359     "eval('(' + outer +')()%s');";
18360
18361   i::ScopedVector<char> code(1024);
18362   i::SNPrintF(code, source, "//# sourceURL=eval_url");
18363   CHECK(CompileRun(code.start())->IsUndefined());
18364   i::SNPrintF(code, source, "//@ sourceURL=eval_url");
18365   CHECK(CompileRun(code.start())->IsUndefined());
18366 }
18367
18368
18369 static int scriptIdInStack[2];
18370
18371 void AnalyzeScriptIdInStack(
18372     const v8::FunctionCallbackInfo<v8::Value>& args) {
18373   v8::HandleScope scope(args.GetIsolate());
18374   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18375       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
18376   CHECK_EQ(2, stackTrace->GetFrameCount());
18377   for (int i = 0; i < 2; i++) {
18378     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
18379   }
18380 }
18381
18382
18383 TEST(ScriptIdInStackTrace) {
18384   v8::Isolate* isolate = CcTest::isolate();
18385   v8::HandleScope scope(isolate);
18386   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18387   templ->Set(v8_str("AnalyzeScriptIdInStack"),
18388              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
18389   LocalContext context(0, templ);
18390
18391   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18392     isolate,
18393     "function foo() {\n"
18394     "  AnalyzeScriptIdInStack();"
18395     "}\n"
18396     "foo();\n");
18397   v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
18398   script->Run();
18399   for (int i = 0; i < 2; i++) {
18400     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
18401     CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
18402   }
18403 }
18404
18405
18406 void AnalyzeStackOfInlineScriptWithSourceURL(
18407     const v8::FunctionCallbackInfo<v8::Value>& args) {
18408   v8::HandleScope scope(args.GetIsolate());
18409   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18410       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18411   CHECK_EQ(4, stackTrace->GetFrameCount());
18412   v8::Handle<v8::String> url = v8_str("url");
18413   for (int i = 0; i < 3; i++) {
18414     v8::Handle<v8::String> name =
18415         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18416     CHECK(!name.IsEmpty());
18417     CHECK_EQ(url, name);
18418   }
18419 }
18420
18421
18422 TEST(InlineScriptWithSourceURLInStackTrace) {
18423   v8::Isolate* isolate = CcTest::isolate();
18424   v8::HandleScope scope(isolate);
18425   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18426   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
18427              v8::FunctionTemplate::New(
18428                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
18429   LocalContext context(0, templ);
18430
18431   const char *source =
18432     "function outer() {\n"
18433     "function bar() {\n"
18434     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
18435     "}\n"
18436     "function foo() {\n"
18437     "\n"
18438     "  bar();\n"
18439     "}\n"
18440     "foo();\n"
18441     "}\n"
18442     "outer()\n%s";
18443
18444   i::ScopedVector<char> code(1024);
18445   i::SNPrintF(code, source, "//# sourceURL=source_url");
18446   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18447   i::SNPrintF(code, source, "//@ sourceURL=source_url");
18448   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18449 }
18450
18451
18452 void AnalyzeStackOfDynamicScriptWithSourceURL(
18453     const v8::FunctionCallbackInfo<v8::Value>& args) {
18454   v8::HandleScope scope(args.GetIsolate());
18455   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18456       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18457   CHECK_EQ(4, stackTrace->GetFrameCount());
18458   v8::Handle<v8::String> url = v8_str("source_url");
18459   for (int i = 0; i < 3; i++) {
18460     v8::Handle<v8::String> name =
18461         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18462     CHECK(!name.IsEmpty());
18463     CHECK_EQ(url, name);
18464   }
18465 }
18466
18467
18468 TEST(DynamicWithSourceURLInStackTrace) {
18469   v8::Isolate* isolate = CcTest::isolate();
18470   v8::HandleScope scope(isolate);
18471   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18472   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
18473              v8::FunctionTemplate::New(
18474                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
18475   LocalContext context(0, templ);
18476
18477   const char *source =
18478     "function outer() {\n"
18479     "function bar() {\n"
18480     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
18481     "}\n"
18482     "function foo() {\n"
18483     "\n"
18484     "  bar();\n"
18485     "}\n"
18486     "foo();\n"
18487     "}\n"
18488     "outer()\n%s";
18489
18490   i::ScopedVector<char> code(1024);
18491   i::SNPrintF(code, source, "//# sourceURL=source_url");
18492   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18493   i::SNPrintF(code, source, "//@ sourceURL=source_url");
18494   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18495 }
18496
18497
18498 TEST(DynamicWithSourceURLInStackTraceString) {
18499   LocalContext context;
18500   v8::HandleScope scope(context->GetIsolate());
18501
18502   const char *source =
18503     "function outer() {\n"
18504     "  function foo() {\n"
18505     "    FAIL.FAIL;\n"
18506     "  }\n"
18507     "  foo();\n"
18508     "}\n"
18509     "outer()\n%s";
18510
18511   i::ScopedVector<char> code(1024);
18512   i::SNPrintF(code, source, "//# sourceURL=source_url");
18513   v8::TryCatch try_catch;
18514   CompileRunWithOrigin(code.start(), "", 0, 0);
18515   CHECK(try_catch.HasCaught());
18516   v8::String::Utf8Value stack(try_catch.StackTrace());
18517   CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
18518 }
18519
18520
18521 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18522   LocalContext context;
18523   v8::HandleScope scope(context->GetIsolate());
18524
18525   const char *source =
18526     "function outer() {\n"
18527     "  var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
18528     "  //# sourceURL=source_url\";\n"
18529     "  eval(scriptContents);\n"
18530     "  foo(); }\n"
18531     "outer();\n"
18532     "//# sourceURL=outer_url";
18533
18534   v8::TryCatch try_catch;
18535   CompileRun(source);
18536   CHECK(try_catch.HasCaught());
18537
18538   Local<v8::Message> message = try_catch.Message();
18539   Handle<Value> sourceURL =
18540     message->GetScriptOrigin().ResourceName();
18541   CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
18542 }
18543
18544
18545 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18546   LocalContext context;
18547   v8::HandleScope scope(context->GetIsolate());
18548
18549   const char *source =
18550     "function outer() {\n"
18551     "  var scriptContents = \"function boo(){ boo(); }\\\n"
18552     "  //# sourceURL=source_url\";\n"
18553     "  eval(scriptContents);\n"
18554     "  boo(); }\n"
18555     "outer();\n"
18556     "//# sourceURL=outer_url";
18557
18558   v8::TryCatch try_catch;
18559   CompileRun(source);
18560   CHECK(try_catch.HasCaught());
18561
18562   Local<v8::Message> message = try_catch.Message();
18563   Handle<Value> sourceURL =
18564     message->GetScriptOrigin().ResourceName();
18565   CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
18566 }
18567
18568
18569 static void CreateGarbageInOldSpace() {
18570   i::Factory* factory = CcTest::i_isolate()->factory();
18571   v8::HandleScope scope(CcTest::isolate());
18572   i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
18573   for (int i = 0; i < 1000; i++) {
18574     factory->NewFixedArray(1000, i::TENURED);
18575   }
18576 }
18577
18578
18579 // Test that idle notification can be handled and eventually returns true.
18580 TEST(IdleNotification) {
18581   const intptr_t MB = 1024 * 1024;
18582   const int IdlePauseInMs = 1000;
18583   LocalContext env;
18584   v8::HandleScope scope(env->GetIsolate());
18585   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18586   CreateGarbageInOldSpace();
18587   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18588   CHECK_GT(size_with_garbage, initial_size + MB);
18589   bool finished = false;
18590   for (int i = 0; i < 200 && !finished; i++) {
18591     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18592   }
18593   intptr_t final_size = CcTest::heap()->SizeOfObjects();
18594   CHECK(finished);
18595   CHECK_LT(final_size, initial_size + 1);
18596 }
18597
18598
18599 // Test that idle notification can be handled and eventually collects garbage.
18600 TEST(IdleNotificationWithSmallHint) {
18601   const intptr_t MB = 1024 * 1024;
18602   const int IdlePauseInMs = 900;
18603   LocalContext env;
18604   v8::HandleScope scope(env->GetIsolate());
18605   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18606   CreateGarbageInOldSpace();
18607   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18608   CHECK_GT(size_with_garbage, initial_size + MB);
18609   bool finished = false;
18610   for (int i = 0; i < 200 && !finished; i++) {
18611     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18612   }
18613   intptr_t final_size = CcTest::heap()->SizeOfObjects();
18614   CHECK(finished);
18615   CHECK_LT(final_size, initial_size + 1);
18616 }
18617
18618
18619 // Test that idle notification can be handled and eventually collects garbage.
18620 TEST(IdleNotificationWithLargeHint) {
18621   const intptr_t MB = 1024 * 1024;
18622   const int IdlePauseInMs = 900;
18623   LocalContext env;
18624   v8::HandleScope scope(env->GetIsolate());
18625   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18626   CreateGarbageInOldSpace();
18627   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18628   CHECK_GT(size_with_garbage, initial_size + MB);
18629   bool finished = false;
18630   for (int i = 0; i < 200 && !finished; i++) {
18631     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18632   }
18633   intptr_t final_size = CcTest::heap()->SizeOfObjects();
18634   CHECK(finished);
18635   CHECK_LT(final_size, initial_size + 1);
18636 }
18637
18638
18639 TEST(Regress2333) {
18640   LocalContext env;
18641   for (int i = 0; i < 3; i++) {
18642     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
18643   }
18644 }
18645
18646 static uint32_t* stack_limit;
18647
18648 static void GetStackLimitCallback(
18649     const v8::FunctionCallbackInfo<v8::Value>& args) {
18650   stack_limit = reinterpret_cast<uint32_t*>(
18651       CcTest::i_isolate()->stack_guard()->real_climit());
18652 }
18653
18654
18655 // Uses the address of a local variable to determine the stack top now.
18656 // Given a size, returns an address that is that far from the current
18657 // top of stack.
18658 static uint32_t* ComputeStackLimit(uint32_t size) {
18659   uint32_t* answer = &size - (size / sizeof(size));
18660   // If the size is very large and the stack is very near the bottom of
18661   // memory then the calculation above may wrap around and give an address
18662   // that is above the (downwards-growing) stack.  In that case we return
18663   // a very low address.
18664   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
18665   return answer;
18666 }
18667
18668
18669 // We need at least 165kB for an x64 debug build with clang and ASAN.
18670 static const int stack_breathing_room = 256 * i::KB;
18671
18672
18673 TEST(SetStackLimit) {
18674   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
18675
18676   // Set stack limit.
18677   CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18678
18679   // Execute a script.
18680   LocalContext env;
18681   v8::HandleScope scope(env->GetIsolate());
18682   Local<v8::FunctionTemplate> fun_templ =
18683       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
18684   Local<Function> fun = fun_templ->GetFunction();
18685   env->Global()->Set(v8_str("get_stack_limit"), fun);
18686   CompileRun("get_stack_limit();");
18687
18688   CHECK(stack_limit == set_limit);
18689 }
18690
18691
18692 TEST(SetStackLimitInThread) {
18693   uint32_t* set_limit;
18694   {
18695     v8::Locker locker(CcTest::isolate());
18696     set_limit = ComputeStackLimit(stack_breathing_room);
18697
18698     // Set stack limit.
18699     CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18700
18701     // Execute a script.
18702     v8::HandleScope scope(CcTest::isolate());
18703     LocalContext env;
18704     Local<v8::FunctionTemplate> fun_templ =
18705         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
18706     Local<Function> fun = fun_templ->GetFunction();
18707     env->Global()->Set(v8_str("get_stack_limit"), fun);
18708     CompileRun("get_stack_limit();");
18709
18710     CHECK(stack_limit == set_limit);
18711   }
18712   {
18713     v8::Locker locker(CcTest::isolate());
18714     CHECK(stack_limit == set_limit);
18715   }
18716 }
18717
18718
18719 THREADED_TEST(GetHeapStatistics) {
18720   LocalContext c1;
18721   v8::HandleScope scope(c1->GetIsolate());
18722   v8::HeapStatistics heap_statistics;
18723   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
18724   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
18725   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
18726   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
18727   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
18728 }
18729
18730
18731 class VisitorImpl : public v8::ExternalResourceVisitor {
18732  public:
18733   explicit VisitorImpl(TestResource** resource) {
18734     for (int i = 0; i < 4; i++) {
18735       resource_[i] = resource[i];
18736       found_resource_[i] = false;
18737     }
18738   }
18739   virtual ~VisitorImpl() {}
18740   virtual void VisitExternalString(v8::Handle<v8::String> string) {
18741     if (!string->IsExternal()) {
18742       CHECK(string->IsExternalOneByte());
18743       return;
18744     }
18745     v8::String::ExternalStringResource* resource =
18746         string->GetExternalStringResource();
18747     CHECK(resource);
18748     for (int i = 0; i < 4; i++) {
18749       if (resource_[i] == resource) {
18750         CHECK(!found_resource_[i]);
18751         found_resource_[i] = true;
18752       }
18753     }
18754   }
18755   void CheckVisitedResources() {
18756     for (int i = 0; i < 4; i++) {
18757       CHECK(found_resource_[i]);
18758     }
18759   }
18760
18761  private:
18762   v8::String::ExternalStringResource* resource_[4];
18763   bool found_resource_[4];
18764 };
18765
18766
18767 TEST(ExternalizeOldSpaceTwoByteCons) {
18768   LocalContext env;
18769   v8::HandleScope scope(env->GetIsolate());
18770   v8::Local<v8::String> cons =
18771       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18772   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18773   CcTest::heap()->CollectAllAvailableGarbage();
18774   CHECK(CcTest::heap()->old_pointer_space()->Contains(
18775             *v8::Utils::OpenHandle(*cons)));
18776
18777   TestResource* resource = new TestResource(
18778       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
18779   cons->MakeExternal(resource);
18780
18781   CHECK(cons->IsExternal());
18782   CHECK_EQ(resource, cons->GetExternalStringResource());
18783   String::Encoding encoding;
18784   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18785   CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
18786 }
18787
18788
18789 TEST(ExternalizeOldSpaceOneByteCons) {
18790   LocalContext env;
18791   v8::HandleScope scope(env->GetIsolate());
18792   v8::Local<v8::String> cons =
18793       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18794   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18795   CcTest::heap()->CollectAllAvailableGarbage();
18796   CHECK(CcTest::heap()->old_pointer_space()->Contains(
18797             *v8::Utils::OpenHandle(*cons)));
18798
18799   TestOneByteResource* resource =
18800       new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
18801   cons->MakeExternal(resource);
18802
18803   CHECK(cons->IsExternalOneByte());
18804   CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
18805   String::Encoding encoding;
18806   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18807   CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
18808 }
18809
18810
18811 TEST(VisitExternalStrings) {
18812   LocalContext env;
18813   v8::HandleScope scope(env->GetIsolate());
18814   const char* string = "Some string";
18815   uint16_t* two_byte_string = AsciiToTwoByteString(string);
18816   TestResource* resource[4];
18817   resource[0] = new TestResource(two_byte_string);
18818   v8::Local<v8::String> string0 =
18819       v8::String::NewExternal(env->GetIsolate(), resource[0]);
18820   resource[1] = new TestResource(two_byte_string, NULL, false);
18821   v8::Local<v8::String> string1 =
18822       v8::String::NewExternal(env->GetIsolate(), resource[1]);
18823
18824   // Externalized symbol.
18825   resource[2] = new TestResource(two_byte_string, NULL, false);
18826   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
18827       env->GetIsolate(), string, v8::String::kInternalizedString);
18828   CHECK(string2->MakeExternal(resource[2]));
18829
18830   // Symbolized External.
18831   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18832   v8::Local<v8::String> string3 =
18833       v8::String::NewExternal(env->GetIsolate(), resource[3]);
18834   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
18835   // Turn into a symbol.
18836   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18837   CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18838       string3_i).is_null());
18839   CHECK(string3_i->IsInternalizedString());
18840
18841   // We need to add usages for string* to avoid warnings in GCC 4.7
18842   CHECK(string0->IsExternal());
18843   CHECK(string1->IsExternal());
18844   CHECK(string2->IsExternal());
18845   CHECK(string3->IsExternal());
18846
18847   VisitorImpl visitor(resource);
18848   v8::V8::VisitExternalResources(&visitor);
18849   visitor.CheckVisitedResources();
18850 }
18851
18852
18853 TEST(ExternalStringCollectedAtTearDown) {
18854   int destroyed = 0;
18855   v8::Isolate* isolate = v8::Isolate::New();
18856   { v8::Isolate::Scope isolate_scope(isolate);
18857     v8::HandleScope handle_scope(isolate);
18858     const char* s = "One string to test them all, one string to find them.";
18859     TestOneByteResource* inscription =
18860         new TestOneByteResource(i::StrDup(s), &destroyed);
18861     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
18862     // Ring is still alive.  Orcs are roaming freely across our lands.
18863     CHECK_EQ(0, destroyed);
18864     USE(ring);
18865   }
18866
18867   isolate->Dispose();
18868   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18869   CHECK_EQ(1, destroyed);
18870 }
18871
18872
18873 TEST(ExternalInternalizedStringCollectedAtTearDown) {
18874   int destroyed = 0;
18875   v8::Isolate* isolate = v8::Isolate::New();
18876   { v8::Isolate::Scope isolate_scope(isolate);
18877     LocalContext env(isolate);
18878     v8::HandleScope handle_scope(isolate);
18879     CompileRun("var ring = 'One string to test them all';");
18880     const char* s = "One string to test them all";
18881     TestOneByteResource* inscription =
18882         new TestOneByteResource(i::StrDup(s), &destroyed);
18883     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18884     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18885     ring->MakeExternal(inscription);
18886     // Ring is still alive.  Orcs are roaming freely across our lands.
18887     CHECK_EQ(0, destroyed);
18888     USE(ring);
18889   }
18890
18891   isolate->Dispose();
18892   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18893   CHECK_EQ(1, destroyed);
18894 }
18895
18896
18897 TEST(ExternalInternalizedStringCollectedAtGC) {
18898   int destroyed = 0;
18899   { LocalContext env;
18900     v8::HandleScope handle_scope(env->GetIsolate());
18901     CompileRun("var ring = 'One string to test them all';");
18902     const char* s = "One string to test them all";
18903     TestOneByteResource* inscription =
18904         new TestOneByteResource(i::StrDup(s), &destroyed);
18905     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18906     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18907     ring->MakeExternal(inscription);
18908     // Ring is still alive.  Orcs are roaming freely across our lands.
18909     CHECK_EQ(0, destroyed);
18910     USE(ring);
18911   }
18912
18913   // Garbage collector deals swift blows to evil.
18914   CcTest::i_isolate()->compilation_cache()->Clear();
18915   CcTest::heap()->CollectAllAvailableGarbage();
18916
18917   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18918   CHECK_EQ(1, destroyed);
18919 }
18920
18921
18922 static double DoubleFromBits(uint64_t value) {
18923   double target;
18924   i::MemCopy(&target, &value, sizeof(target));
18925   return target;
18926 }
18927
18928
18929 static uint64_t DoubleToBits(double value) {
18930   uint64_t target;
18931   i::MemCopy(&target, &value, sizeof(target));
18932   return target;
18933 }
18934
18935
18936 static double DoubleToDateTime(double input) {
18937   double date_limit = 864e13;
18938   if (std::isnan(input) || input < -date_limit || input > date_limit) {
18939     return v8::base::OS::nan_value();
18940   }
18941   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18942 }
18943
18944
18945 // We don't have a consistent way to write 64-bit constants syntactically, so we
18946 // split them into two 32-bit constants and combine them programmatically.
18947 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18948   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18949 }
18950
18951
18952 THREADED_TEST(QuietSignalingNaNs) {
18953   LocalContext context;
18954   v8::Isolate* isolate = context->GetIsolate();
18955   v8::HandleScope scope(isolate);
18956   v8::TryCatch try_catch;
18957
18958   // Special double values.
18959   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18960   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18961   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18962   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18963   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18964   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18965   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18966
18967   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18968   // on either side of the epoch.
18969   double date_limit = 864e13;
18970
18971   double test_values[] = {
18972       snan,
18973       qnan,
18974       infinity,
18975       max_normal,
18976       date_limit + 1,
18977       date_limit,
18978       min_normal,
18979       max_denormal,
18980       min_denormal,
18981       0,
18982       -0,
18983       -min_denormal,
18984       -max_denormal,
18985       -min_normal,
18986       -date_limit,
18987       -date_limit - 1,
18988       -max_normal,
18989       -infinity,
18990       -qnan,
18991       -snan
18992   };
18993   int num_test_values = 20;
18994
18995   for (int i = 0; i < num_test_values; i++) {
18996     double test_value = test_values[i];
18997
18998     // Check that Number::New preserves non-NaNs and quiets SNaNs.
18999     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
19000     double stored_number = number->NumberValue();
19001     if (!std::isnan(test_value)) {
19002       CHECK_EQ(test_value, stored_number);
19003     } else {
19004       uint64_t stored_bits = DoubleToBits(stored_number);
19005       // Check if quiet nan (bits 51..62 all set).
19006 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19007     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
19008       // Most significant fraction bit for quiet nan is set to 0
19009       // on MIPS architecture. Allowed by IEEE-754.
19010       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19011 #else
19012       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
19013 #endif
19014     }
19015
19016     // Check that Date::New preserves non-NaNs in the date range and
19017     // quiets SNaNs.
19018     v8::Handle<v8::Value> date =
19019         v8::Date::New(isolate, test_value);
19020     double expected_stored_date = DoubleToDateTime(test_value);
19021     double stored_date = date->NumberValue();
19022     if (!std::isnan(expected_stored_date)) {
19023       CHECK_EQ(expected_stored_date, stored_date);
19024     } else {
19025       uint64_t stored_bits = DoubleToBits(stored_date);
19026       // Check if quiet nan (bits 51..62 all set).
19027 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19028     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
19029       // Most significant fraction bit for quiet nan is set to 0
19030       // on MIPS architecture. Allowed by IEEE-754.
19031       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19032 #else
19033       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
19034 #endif
19035     }
19036   }
19037 }
19038
19039
19040 static void SpaghettiIncident(
19041     const v8::FunctionCallbackInfo<v8::Value>& args) {
19042   v8::HandleScope scope(args.GetIsolate());
19043   v8::TryCatch tc;
19044   v8::Handle<v8::String> str(args[0]->ToString());
19045   USE(str);
19046   if (tc.HasCaught())
19047     tc.ReThrow();
19048 }
19049
19050
19051 // Test that an exception can be propagated down through a spaghetti
19052 // stack using ReThrow.
19053 THREADED_TEST(SpaghettiStackReThrow) {
19054   v8::Isolate* isolate = CcTest::isolate();
19055   v8::HandleScope scope(isolate);
19056   LocalContext context;
19057   context->Global()->Set(
19058       v8::String::NewFromUtf8(isolate, "s"),
19059       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
19060   v8::TryCatch try_catch;
19061   CompileRun(
19062       "var i = 0;"
19063       "var o = {"
19064       "  toString: function () {"
19065       "    if (i == 10) {"
19066       "      throw 'Hey!';"
19067       "    } else {"
19068       "      i++;"
19069       "      return s(o);"
19070       "    }"
19071       "  }"
19072       "};"
19073       "s(o);");
19074   CHECK(try_catch.HasCaught());
19075   v8::String::Utf8Value value(try_catch.Exception());
19076   CHECK_EQ(0, strcmp(*value, "Hey!"));
19077 }
19078
19079
19080 TEST(Regress528) {
19081   v8::V8::Initialize();
19082   v8::Isolate* isolate = CcTest::isolate();
19083   v8::HandleScope scope(isolate);
19084   v8::Local<Context> other_context;
19085   int gc_count;
19086
19087   // Create a context used to keep the code from aging in the compilation
19088   // cache.
19089   other_context = Context::New(isolate);
19090
19091   // Context-dependent context data creates reference from the compilation
19092   // cache to the global object.
19093   const char* source_simple = "1";
19094   {
19095     v8::HandleScope scope(isolate);
19096     v8::Local<Context> context = Context::New(isolate);
19097
19098     context->Enter();
19099     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
19100     context->SetEmbedderData(0, obj);
19101     CompileRun(source_simple);
19102     context->Exit();
19103   }
19104   isolate->ContextDisposedNotification();
19105   for (gc_count = 1; gc_count < 10; gc_count++) {
19106     other_context->Enter();
19107     CompileRun(source_simple);
19108     other_context->Exit();
19109     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19110     if (GetGlobalObjectsCount() == 1) break;
19111   }
19112   CHECK_GE(2, gc_count);
19113   CHECK_EQ(1, GetGlobalObjectsCount());
19114
19115   // Eval in a function creates reference from the compilation cache to the
19116   // global object.
19117   const char* source_eval = "function f(){eval('1')}; f()";
19118   {
19119     v8::HandleScope scope(isolate);
19120     v8::Local<Context> context = Context::New(isolate);
19121
19122     context->Enter();
19123     CompileRun(source_eval);
19124     context->Exit();
19125   }
19126   isolate->ContextDisposedNotification();
19127   for (gc_count = 1; gc_count < 10; gc_count++) {
19128     other_context->Enter();
19129     CompileRun(source_eval);
19130     other_context->Exit();
19131     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19132     if (GetGlobalObjectsCount() == 1) break;
19133   }
19134   CHECK_GE(2, gc_count);
19135   CHECK_EQ(1, GetGlobalObjectsCount());
19136
19137   // Looking up the line number for an exception creates reference from the
19138   // compilation cache to the global object.
19139   const char* source_exception = "function f(){throw 1;} f()";
19140   {
19141     v8::HandleScope scope(isolate);
19142     v8::Local<Context> context = Context::New(isolate);
19143
19144     context->Enter();
19145     v8::TryCatch try_catch;
19146     CompileRun(source_exception);
19147     CHECK(try_catch.HasCaught());
19148     v8::Handle<v8::Message> message = try_catch.Message();
19149     CHECK(!message.IsEmpty());
19150     CHECK_EQ(1, message->GetLineNumber());
19151     context->Exit();
19152   }
19153   isolate->ContextDisposedNotification();
19154   for (gc_count = 1; gc_count < 10; gc_count++) {
19155     other_context->Enter();
19156     CompileRun(source_exception);
19157     other_context->Exit();
19158     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19159     if (GetGlobalObjectsCount() == 1) break;
19160   }
19161   CHECK_GE(2, gc_count);
19162   CHECK_EQ(1, GetGlobalObjectsCount());
19163
19164   isolate->ContextDisposedNotification();
19165 }
19166
19167
19168 THREADED_TEST(ScriptOrigin) {
19169   LocalContext env;
19170   v8::HandleScope scope(env->GetIsolate());
19171   v8::ScriptOrigin origin =
19172       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19173   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19174       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
19175   v8::Script::Compile(script, &origin)->Run();
19176   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19177       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19178   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19179       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19180
19181   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
19182   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
19183   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
19184
19185   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
19186   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
19187   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
19188 }
19189
19190
19191 THREADED_TEST(FunctionGetInferredName) {
19192   LocalContext env;
19193   v8::HandleScope scope(env->GetIsolate());
19194   v8::ScriptOrigin origin =
19195       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19196   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19197       env->GetIsolate(),
19198       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
19199   v8::Script::Compile(script, &origin)->Run();
19200   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19201       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19202   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
19203 }
19204
19205
19206 THREADED_TEST(FunctionGetDisplayName) {
19207   LocalContext env;
19208   v8::HandleScope scope(env->GetIsolate());
19209   const char* code = "var error = false;"
19210                      "function a() { this.x = 1; };"
19211                      "a.displayName = 'display_a';"
19212                      "var b = (function() {"
19213                      "  var f = function() { this.x = 2; };"
19214                      "  f.displayName = 'display_b';"
19215                      "  return f;"
19216                      "})();"
19217                      "var c = function() {};"
19218                      "c.__defineGetter__('displayName', function() {"
19219                      "  error = true;"
19220                      "  throw new Error();"
19221                      "});"
19222                      "function d() {};"
19223                      "d.__defineGetter__('displayName', function() {"
19224                      "  error = true;"
19225                      "  return 'wrong_display_name';"
19226                      "});"
19227                      "function e() {};"
19228                      "e.displayName = 'wrong_display_name';"
19229                      "e.__defineSetter__('displayName', function() {"
19230                      "  error = true;"
19231                      "  throw new Error();"
19232                      "});"
19233                      "function f() {};"
19234                      "f.displayName = { 'foo': 6, toString: function() {"
19235                      "  error = true;"
19236                      "  return 'wrong_display_name';"
19237                      "}};"
19238                      "var g = function() {"
19239                      "  arguments.callee.displayName = 'set_in_runtime';"
19240                      "}; g();"
19241                      ;
19242   v8::ScriptOrigin origin =
19243       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19244   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
19245       ->Run();
19246   v8::Local<v8::Value> error =
19247       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
19248   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
19249       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
19250   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
19251       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
19252   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
19253       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
19254   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
19255       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
19256   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
19257       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
19258   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19259       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19260   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19261       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19262   CHECK_EQ(false, error->BooleanValue());
19263   CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
19264   CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
19265   CHECK(c->GetDisplayName()->IsUndefined());
19266   CHECK(d->GetDisplayName()->IsUndefined());
19267   CHECK(e->GetDisplayName()->IsUndefined());
19268   CHECK(f->GetDisplayName()->IsUndefined());
19269   CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
19270 }
19271
19272
19273 THREADED_TEST(ScriptLineNumber) {
19274   LocalContext env;
19275   v8::HandleScope scope(env->GetIsolate());
19276   v8::ScriptOrigin origin =
19277       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19278   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19279       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
19280   v8::Script::Compile(script, &origin)->Run();
19281   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19282       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19283   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19284       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19285   CHECK_EQ(0, f->GetScriptLineNumber());
19286   CHECK_EQ(2, g->GetScriptLineNumber());
19287 }
19288
19289
19290 THREADED_TEST(ScriptColumnNumber) {
19291   LocalContext env;
19292   v8::Isolate* isolate = env->GetIsolate();
19293   v8::HandleScope scope(isolate);
19294   v8::ScriptOrigin origin =
19295       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
19296                        v8::Integer::New(isolate, 3),
19297                        v8::Integer::New(isolate, 2));
19298   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19299       isolate, "function foo() {}\n\n     function bar() {}");
19300   v8::Script::Compile(script, &origin)->Run();
19301   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19302       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
19303   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19304       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
19305   CHECK_EQ(14, foo->GetScriptColumnNumber());
19306   CHECK_EQ(17, bar->GetScriptColumnNumber());
19307 }
19308
19309
19310 THREADED_TEST(FunctionIsBuiltin) {
19311   LocalContext env;
19312   v8::Isolate* isolate = env->GetIsolate();
19313   v8::HandleScope scope(isolate);
19314   v8::Local<v8::Function> f;
19315   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
19316   CHECK(f->IsBuiltin());
19317   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
19318   CHECK(f->IsBuiltin());
19319   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
19320   CHECK(f->IsBuiltin());
19321   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
19322   CHECK(f->IsBuiltin());
19323   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
19324   CHECK(!f->IsBuiltin());
19325 }
19326
19327
19328 THREADED_TEST(FunctionGetScriptId) {
19329   LocalContext env;
19330   v8::Isolate* isolate = env->GetIsolate();
19331   v8::HandleScope scope(isolate);
19332   v8::ScriptOrigin origin =
19333       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
19334                        v8::Integer::New(isolate, 3),
19335                        v8::Integer::New(isolate, 2));
19336   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
19337       isolate, "function foo() {}\n\n     function bar() {}");
19338   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
19339   script->Run();
19340   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19341       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
19342   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19343       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
19344   CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
19345   CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
19346 }
19347
19348
19349 THREADED_TEST(FunctionGetBoundFunction) {
19350   LocalContext env;
19351   v8::HandleScope scope(env->GetIsolate());
19352   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
19353       env->GetIsolate(), "test"));
19354   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19355       env->GetIsolate(),
19356       "var a = new Object();\n"
19357       "a.x = 1;\n"
19358       "function f () { return this.x };\n"
19359       "var g = f.bind(a);\n"
19360       "var b = g();");
19361   v8::Script::Compile(script, &origin)->Run();
19362   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19363       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19364   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19365       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19366   CHECK(g->GetBoundFunction()->IsFunction());
19367   Local<v8::Function> original_function = Local<v8::Function>::Cast(
19368       g->GetBoundFunction());
19369   CHECK_EQ(f->GetName(), original_function->GetName());
19370   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
19371   CHECK_EQ(f->GetScriptColumnNumber(),
19372            original_function->GetScriptColumnNumber());
19373 }
19374
19375
19376 static void GetterWhichReturns42(
19377     Local<String> name,
19378     const v8::PropertyCallbackInfo<v8::Value>& info) {
19379   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19380   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19381   info.GetReturnValue().Set(v8_num(42));
19382 }
19383
19384
19385 static void SetterWhichSetsYOnThisTo23(
19386     Local<String> name,
19387     Local<Value> value,
19388     const v8::PropertyCallbackInfo<void>& info) {
19389   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19390   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19391   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19392 }
19393
19394
19395 void FooGetInterceptor(Local<String> name,
19396                        const v8::PropertyCallbackInfo<v8::Value>& info) {
19397   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19398   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19399   if (!name->Equals(v8_str("foo"))) return;
19400   info.GetReturnValue().Set(v8_num(42));
19401 }
19402
19403
19404 void FooSetInterceptor(Local<String> name,
19405                        Local<Value> value,
19406                        const v8::PropertyCallbackInfo<v8::Value>& info) {
19407   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19408   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19409   if (!name->Equals(v8_str("foo"))) return;
19410   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19411   info.GetReturnValue().Set(v8_num(23));
19412 }
19413
19414
19415 TEST(SetterOnConstructorPrototype) {
19416   v8::Isolate* isolate = CcTest::isolate();
19417   v8::HandleScope scope(isolate);
19418   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19419   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19420                      SetterWhichSetsYOnThisTo23);
19421   LocalContext context;
19422   context->Global()->Set(v8_str("P"), templ->NewInstance());
19423   CompileRun("function C1() {"
19424              "  this.x = 23;"
19425              "};"
19426              "C1.prototype = P;"
19427              "function C2() {"
19428              "  this.x = 23"
19429              "};"
19430              "C2.prototype = { };"
19431              "C2.prototype.__proto__ = P;");
19432
19433   v8::Local<v8::Script> script;
19434   script = v8_compile("new C1();");
19435   for (int i = 0; i < 10; i++) {
19436     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19437     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
19438     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
19439   }
19440
19441 script = v8_compile("new C2();");
19442   for (int i = 0; i < 10; i++) {
19443     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
19444     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
19445     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
19446   }
19447 }
19448
19449
19450 static void NamedPropertyGetterWhichReturns42(
19451     Local<String> name,
19452     const v8::PropertyCallbackInfo<v8::Value>& info) {
19453   info.GetReturnValue().Set(v8_num(42));
19454 }
19455
19456
19457 static void NamedPropertySetterWhichSetsYOnThisTo23(
19458     Local<String> name,
19459     Local<Value> value,
19460     const v8::PropertyCallbackInfo<v8::Value>& info) {
19461   if (name->Equals(v8_str("x"))) {
19462     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19463   }
19464 }
19465
19466
19467 THREADED_TEST(InterceptorOnConstructorPrototype) {
19468   v8::Isolate* isolate = CcTest::isolate();
19469   v8::HandleScope scope(isolate);
19470   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19471   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
19472                                  NamedPropertySetterWhichSetsYOnThisTo23);
19473   LocalContext context;
19474   context->Global()->Set(v8_str("P"), templ->NewInstance());
19475   CompileRun("function C1() {"
19476              "  this.x = 23;"
19477              "};"
19478              "C1.prototype = P;"
19479              "function C2() {"
19480              "  this.x = 23"
19481              "};"
19482              "C2.prototype = { };"
19483              "C2.prototype.__proto__ = P;");
19484
19485   v8::Local<v8::Script> script;
19486   script = v8_compile("new C1();");
19487   for (int i = 0; i < 10; i++) {
19488     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19489     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
19490     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
19491   }
19492
19493   script = v8_compile("new C2();");
19494   for (int i = 0; i < 10; i++) {
19495     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
19496     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
19497     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
19498   }
19499 }
19500
19501
19502 TEST(Regress618) {
19503   const char* source = "function C1() {"
19504                        "  this.x = 23;"
19505                        "};"
19506                        "C1.prototype = P;";
19507
19508   LocalContext context;
19509   v8::Isolate* isolate = context->GetIsolate();
19510   v8::HandleScope scope(isolate);
19511   v8::Local<v8::Script> script;
19512
19513   // Use a simple object as prototype.
19514   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
19515   prototype->Set(v8_str("y"), v8_num(42));
19516   context->Global()->Set(v8_str("P"), prototype);
19517
19518   // This compile will add the code to the compilation cache.
19519   CompileRun(source);
19520
19521   script = v8_compile("new C1();");
19522   // Allow enough iterations for the inobject slack tracking logic
19523   // to finalize instance size and install the fast construct stub.
19524   for (int i = 0; i < 256; i++) {
19525     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19526     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
19527     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
19528   }
19529
19530   // Use an API object with accessors as prototype.
19531   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19532   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19533                      SetterWhichSetsYOnThisTo23);
19534   context->Global()->Set(v8_str("P"), templ->NewInstance());
19535
19536   // This compile will get the code from the compilation cache.
19537   CompileRun(source);
19538
19539   script = v8_compile("new C1();");
19540   for (int i = 0; i < 10; i++) {
19541     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19542     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
19543     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
19544   }
19545 }
19546
19547 v8::Isolate* gc_callbacks_isolate = NULL;
19548 int prologue_call_count = 0;
19549 int epilogue_call_count = 0;
19550 int prologue_call_count_second = 0;
19551 int epilogue_call_count_second = 0;
19552 int prologue_call_count_alloc = 0;
19553 int epilogue_call_count_alloc = 0;
19554
19555 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
19556   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19557   ++prologue_call_count;
19558 }
19559
19560
19561 void PrologueCallback(v8::Isolate* isolate,
19562                       v8::GCType,
19563                       v8::GCCallbackFlags flags) {
19564   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19565   CHECK_EQ(gc_callbacks_isolate, isolate);
19566   ++prologue_call_count;
19567 }
19568
19569
19570 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
19571   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19572   ++epilogue_call_count;
19573 }
19574
19575
19576 void EpilogueCallback(v8::Isolate* isolate,
19577                       v8::GCType,
19578                       v8::GCCallbackFlags flags) {
19579   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19580   CHECK_EQ(gc_callbacks_isolate, isolate);
19581   ++epilogue_call_count;
19582 }
19583
19584
19585 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
19586   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19587   ++prologue_call_count_second;
19588 }
19589
19590
19591 void PrologueCallbackSecond(v8::Isolate* isolate,
19592                             v8::GCType,
19593                             v8::GCCallbackFlags flags) {
19594   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19595   CHECK_EQ(gc_callbacks_isolate, isolate);
19596   ++prologue_call_count_second;
19597 }
19598
19599
19600 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
19601   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19602   ++epilogue_call_count_second;
19603 }
19604
19605
19606 void EpilogueCallbackSecond(v8::Isolate* isolate,
19607                             v8::GCType,
19608                             v8::GCCallbackFlags flags) {
19609   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19610   CHECK_EQ(gc_callbacks_isolate, isolate);
19611   ++epilogue_call_count_second;
19612 }
19613
19614
19615 void PrologueCallbackAlloc(v8::Isolate* isolate,
19616                            v8::GCType,
19617                            v8::GCCallbackFlags flags) {
19618   v8::HandleScope scope(isolate);
19619
19620   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19621   CHECK_EQ(gc_callbacks_isolate, isolate);
19622   ++prologue_call_count_alloc;
19623
19624   // Simulate full heap to see if we will reenter this callback
19625   SimulateFullSpace(CcTest::heap()->new_space());
19626
19627   Local<Object> obj = Object::New(isolate);
19628   CHECK(!obj.IsEmpty());
19629
19630   CcTest::heap()->CollectAllGarbage(
19631       i::Heap::kAbortIncrementalMarkingMask);
19632 }
19633
19634
19635 void EpilogueCallbackAlloc(v8::Isolate* isolate,
19636                            v8::GCType,
19637                            v8::GCCallbackFlags flags) {
19638   v8::HandleScope scope(isolate);
19639
19640   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19641   CHECK_EQ(gc_callbacks_isolate, isolate);
19642   ++epilogue_call_count_alloc;
19643
19644   // Simulate full heap to see if we will reenter this callback
19645   SimulateFullSpace(CcTest::heap()->new_space());
19646
19647   Local<Object> obj = Object::New(isolate);
19648   CHECK(!obj.IsEmpty());
19649
19650   CcTest::heap()->CollectAllGarbage(
19651       i::Heap::kAbortIncrementalMarkingMask);
19652 }
19653
19654
19655 TEST(GCCallbacksOld) {
19656   LocalContext context;
19657
19658   v8::V8::AddGCPrologueCallback(PrologueCallback);
19659   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
19660   CHECK_EQ(0, prologue_call_count);
19661   CHECK_EQ(0, epilogue_call_count);
19662   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19663   CHECK_EQ(1, prologue_call_count);
19664   CHECK_EQ(1, epilogue_call_count);
19665   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
19666   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
19667   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19668   CHECK_EQ(2, prologue_call_count);
19669   CHECK_EQ(2, epilogue_call_count);
19670   CHECK_EQ(1, prologue_call_count_second);
19671   CHECK_EQ(1, epilogue_call_count_second);
19672   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
19673   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
19674   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19675   CHECK_EQ(2, prologue_call_count);
19676   CHECK_EQ(2, epilogue_call_count);
19677   CHECK_EQ(2, prologue_call_count_second);
19678   CHECK_EQ(2, epilogue_call_count_second);
19679   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
19680   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19681   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19682   CHECK_EQ(2, prologue_call_count);
19683   CHECK_EQ(2, epilogue_call_count);
19684   CHECK_EQ(2, prologue_call_count_second);
19685   CHECK_EQ(2, epilogue_call_count_second);
19686 }
19687
19688
19689 TEST(GCCallbacks) {
19690   LocalContext context;
19691   v8::Isolate* isolate = context->GetIsolate();
19692   gc_callbacks_isolate = isolate;
19693   isolate->AddGCPrologueCallback(PrologueCallback);
19694   isolate->AddGCEpilogueCallback(EpilogueCallback);
19695   CHECK_EQ(0, prologue_call_count);
19696   CHECK_EQ(0, epilogue_call_count);
19697   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19698   CHECK_EQ(1, prologue_call_count);
19699   CHECK_EQ(1, epilogue_call_count);
19700   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
19701   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
19702   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19703   CHECK_EQ(2, prologue_call_count);
19704   CHECK_EQ(2, epilogue_call_count);
19705   CHECK_EQ(1, prologue_call_count_second);
19706   CHECK_EQ(1, epilogue_call_count_second);
19707   isolate->RemoveGCPrologueCallback(PrologueCallback);
19708   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
19709   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19710   CHECK_EQ(2, prologue_call_count);
19711   CHECK_EQ(2, epilogue_call_count);
19712   CHECK_EQ(2, prologue_call_count_second);
19713   CHECK_EQ(2, epilogue_call_count_second);
19714   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
19715   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19716   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19717   CHECK_EQ(2, prologue_call_count);
19718   CHECK_EQ(2, epilogue_call_count);
19719   CHECK_EQ(2, prologue_call_count_second);
19720   CHECK_EQ(2, epilogue_call_count_second);
19721
19722   CHECK_EQ(0, prologue_call_count_alloc);
19723   CHECK_EQ(0, epilogue_call_count_alloc);
19724   isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
19725   isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
19726   CcTest::heap()->CollectAllGarbage(
19727       i::Heap::kAbortIncrementalMarkingMask);
19728   CHECK_EQ(1, prologue_call_count_alloc);
19729   CHECK_EQ(1, epilogue_call_count_alloc);
19730   isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
19731   isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
19732 }
19733
19734
19735 THREADED_TEST(AddToJSFunctionResultCache) {
19736   i::FLAG_stress_compaction = false;
19737   i::FLAG_allow_natives_syntax = true;
19738   v8::HandleScope scope(CcTest::isolate());
19739
19740   LocalContext context;
19741
19742   const char* code =
19743       "(function() {"
19744       "  var key0 = 'a';"
19745       "  var key1 = 'b';"
19746       "  var r0 = %_GetFromCache(0, key0);"
19747       "  var r1 = %_GetFromCache(0, key1);"
19748       "  var r0_ = %_GetFromCache(0, key0);"
19749       "  if (r0 !== r0_)"
19750       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
19751       "  var r1_ = %_GetFromCache(0, key1);"
19752       "  if (r1 !== r1_)"
19753       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
19754       "  return 'PASSED';"
19755       "})()";
19756   CcTest::heap()->ClearJSFunctionResultCaches();
19757   ExpectString(code, "PASSED");
19758 }
19759
19760
19761 THREADED_TEST(FillJSFunctionResultCache) {
19762   i::FLAG_allow_natives_syntax = true;
19763   LocalContext context;
19764   v8::HandleScope scope(context->GetIsolate());
19765
19766   const char* code =
19767       "(function() {"
19768       "  var k = 'a';"
19769       "  var r = %_GetFromCache(0, k);"
19770       "  for (var i = 0; i < 16; i++) {"
19771       "    %_GetFromCache(0, 'a' + i);"
19772       "  };"
19773       "  if (r === %_GetFromCache(0, k))"
19774       "    return 'FAILED: k0CacheSize is too small';"
19775       "  return 'PASSED';"
19776       "})()";
19777   CcTest::heap()->ClearJSFunctionResultCaches();
19778   ExpectString(code, "PASSED");
19779 }
19780
19781
19782 THREADED_TEST(RoundRobinGetFromCache) {
19783   i::FLAG_allow_natives_syntax = true;
19784   LocalContext context;
19785   v8::HandleScope scope(context->GetIsolate());
19786
19787   const char* code =
19788       "(function() {"
19789       "  var keys = [];"
19790       "  for (var i = 0; i < 16; i++) keys.push(i);"
19791       "  var values = [];"
19792       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19793       "  for (var i = 0; i < 16; i++) {"
19794       "    var v = %_GetFromCache(0, keys[i]);"
19795       "    if (v.toString() !== values[i].toString())"
19796       "      return 'Wrong value for ' + "
19797       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
19798       "  };"
19799       "  return 'PASSED';"
19800       "})()";
19801   CcTest::heap()->ClearJSFunctionResultCaches();
19802   ExpectString(code, "PASSED");
19803 }
19804
19805
19806 THREADED_TEST(ReverseGetFromCache) {
19807   i::FLAG_allow_natives_syntax = true;
19808   LocalContext context;
19809   v8::HandleScope scope(context->GetIsolate());
19810
19811   const char* code =
19812       "(function() {"
19813       "  var keys = [];"
19814       "  for (var i = 0; i < 16; i++) keys.push(i);"
19815       "  var values = [];"
19816       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19817       "  for (var i = 15; i >= 16; i--) {"
19818       "    var v = %_GetFromCache(0, keys[i]);"
19819       "    if (v !== values[i])"
19820       "      return 'Wrong value for ' + "
19821       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
19822       "  };"
19823       "  return 'PASSED';"
19824       "})()";
19825   CcTest::heap()->ClearJSFunctionResultCaches();
19826   ExpectString(code, "PASSED");
19827 }
19828
19829
19830 THREADED_TEST(TestEviction) {
19831   i::FLAG_allow_natives_syntax = true;
19832   LocalContext context;
19833   v8::HandleScope scope(context->GetIsolate());
19834
19835   const char* code =
19836       "(function() {"
19837       "  for (var i = 0; i < 2*16; i++) {"
19838       "    %_GetFromCache(0, 'a' + i);"
19839       "  };"
19840       "  return 'PASSED';"
19841       "})()";
19842   CcTest::heap()->ClearJSFunctionResultCaches();
19843   ExpectString(code, "PASSED");
19844 }
19845
19846
19847 THREADED_TEST(TwoByteStringInOneByteCons) {
19848   // See Chromium issue 47824.
19849   LocalContext context;
19850   v8::HandleScope scope(context->GetIsolate());
19851
19852   const char* init_code =
19853       "var str1 = 'abelspendabel';"
19854       "var str2 = str1 + str1 + str1;"
19855       "str2;";
19856   Local<Value> result = CompileRun(init_code);
19857
19858   Local<Value> indexof = CompileRun("str2.indexOf('els')");
19859   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19860
19861   CHECK(result->IsString());
19862   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19863   int length = string->length();
19864   CHECK(string->IsOneByteRepresentation());
19865
19866   i::Handle<i::String> flat_string = i::String::Flatten(string);
19867
19868   CHECK(string->IsOneByteRepresentation());
19869   CHECK(flat_string->IsOneByteRepresentation());
19870
19871   // Create external resource.
19872   uint16_t* uc16_buffer = new uint16_t[length + 1];
19873
19874   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19875   uc16_buffer[length] = 0;
19876
19877   TestResource resource(uc16_buffer);
19878
19879   flat_string->MakeExternal(&resource);
19880
19881   CHECK(flat_string->IsTwoByteRepresentation());
19882
19883   // If the cons string has been short-circuited, skip the following checks.
19884   if (!string.is_identical_to(flat_string)) {
19885     // At this point, we should have a Cons string which is flat and one-byte,
19886     // with a first half that is a two-byte string (although it only contains
19887     // one-byte characters). This is a valid sequence of steps, and it can
19888     // happen in real pages.
19889     CHECK(string->IsOneByteRepresentation());
19890     i::ConsString* cons = i::ConsString::cast(*string);
19891     CHECK_EQ(0, cons->second()->length());
19892     CHECK(cons->first()->IsTwoByteRepresentation());
19893   }
19894
19895   // Check that some string operations work.
19896
19897   // Atom RegExp.
19898   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19899   CHECK_EQ(6, reresult->Int32Value());
19900
19901   // Nonatom RegExp.
19902   reresult = CompileRun("str2.match(/abe./g).length;");
19903   CHECK_EQ(6, reresult->Int32Value());
19904
19905   reresult = CompileRun("str2.search(/bel/g);");
19906   CHECK_EQ(1, reresult->Int32Value());
19907
19908   reresult = CompileRun("str2.search(/be./g);");
19909   CHECK_EQ(1, reresult->Int32Value());
19910
19911   ExpectTrue("/bel/g.test(str2);");
19912
19913   ExpectTrue("/be./g.test(str2);");
19914
19915   reresult = CompileRun("/bel/g.exec(str2);");
19916   CHECK(!reresult->IsNull());
19917
19918   reresult = CompileRun("/be./g.exec(str2);");
19919   CHECK(!reresult->IsNull());
19920
19921   ExpectString("str2.substring(2, 10);", "elspenda");
19922
19923   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19924
19925   ExpectString("str2.charAt(2);", "e");
19926
19927   ExpectObject("str2.indexOf('els');", indexof);
19928
19929   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19930
19931   reresult = CompileRun("str2.charCodeAt(2);");
19932   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19933 }
19934
19935
19936 TEST(ContainsOnlyOneByte) {
19937   v8::V8::Initialize();
19938   v8::Isolate* isolate = CcTest::isolate();
19939   v8::HandleScope scope(isolate);
19940   // Make a buffer long enough that it won't automatically be converted.
19941   const int length = 512;
19942   // Ensure word aligned assignment.
19943   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19944   i::SmartArrayPointer<uintptr_t>
19945   aligned_contents(new uintptr_t[aligned_length]);
19946   uint16_t* string_contents =
19947       reinterpret_cast<uint16_t*>(aligned_contents.get());
19948   // Set to contain only one byte.
19949   for (int i = 0; i < length-1; i++) {
19950     string_contents[i] = 0x41;
19951   }
19952   string_contents[length-1] = 0;
19953   // Simple case.
19954   Handle<String> string =
19955       String::NewExternal(isolate,
19956                           new TestResource(string_contents, NULL, false));
19957   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19958   // Counter example.
19959   string = String::NewFromTwoByte(isolate, string_contents);
19960   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19961   // Test left right and balanced cons strings.
19962   Handle<String> base = String::NewFromUtf8(isolate, "a");
19963   Handle<String> left = base;
19964   Handle<String> right = base;
19965   for (int i = 0; i < 1000; i++) {
19966     left = String::Concat(base, left);
19967     right = String::Concat(right, base);
19968   }
19969   Handle<String> balanced = String::Concat(left, base);
19970   balanced = String::Concat(balanced, right);
19971   Handle<String> cons_strings[] = {left, balanced, right};
19972   Handle<String> two_byte =
19973       String::NewExternal(isolate,
19974                           new TestResource(string_contents, NULL, false));
19975   USE(two_byte); USE(cons_strings);
19976   for (size_t i = 0; i < arraysize(cons_strings); i++) {
19977     // Base assumptions.
19978     string = cons_strings[i];
19979     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19980     // Test left and right concatentation.
19981     string = String::Concat(two_byte, cons_strings[i]);
19982     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19983     string = String::Concat(cons_strings[i], two_byte);
19984     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19985   }
19986   // Set bits in different positions
19987   // for strings of different lengths and alignments.
19988   for (int alignment = 0; alignment < 7; alignment++) {
19989     for (int size = 2; alignment + size < length; size *= 2) {
19990       int zero_offset = size + alignment;
19991       string_contents[zero_offset] = 0;
19992       for (int i = 0; i < size; i++) {
19993         int shift = 8 + (i % 7);
19994         string_contents[alignment + i] = 1 << shift;
19995         string = String::NewExternal(
19996             isolate,
19997             new TestResource(string_contents + alignment, NULL, false));
19998         CHECK_EQ(size, string->Length());
19999         CHECK(!string->ContainsOnlyOneByte());
20000         string_contents[alignment + i] = 0x41;
20001       }
20002       string_contents[zero_offset] = 0x41;
20003     }
20004   }
20005 }
20006
20007
20008 // Failed access check callback that performs a GC on each invocation.
20009 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
20010                                  v8::AccessType type,
20011                                  Local<v8::Value> data) {
20012   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20013 }
20014
20015
20016 TEST(GCInFailedAccessCheckCallback) {
20017   // Install a failed access check callback that performs a GC on each
20018   // invocation. Then force the callback to be called from va
20019
20020   v8::V8::Initialize();
20021   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
20022
20023   v8::Isolate* isolate = CcTest::isolate();
20024   v8::HandleScope scope(isolate);
20025
20026   // Create an ObjectTemplate for global objects and install access
20027   // check callbacks that will block access.
20028   v8::Handle<v8::ObjectTemplate> global_template =
20029       v8::ObjectTemplate::New(isolate);
20030   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
20031                                            IndexedGetAccessBlocker,
20032                                            v8::Handle<v8::Value>(),
20033                                            false);
20034
20035   // Create a context and set an x property on it's global object.
20036   LocalContext context0(NULL, global_template);
20037   context0->Global()->Set(v8_str("x"), v8_num(42));
20038   v8::Handle<v8::Object> global0 = context0->Global();
20039
20040   // Create a context with a different security token so that the
20041   // failed access check callback will be called on each access.
20042   LocalContext context1(NULL, global_template);
20043   context1->Global()->Set(v8_str("other"), global0);
20044
20045   // Get property with failed access check.
20046   ExpectUndefined("other.x");
20047
20048   // Get element with failed access check.
20049   ExpectUndefined("other[0]");
20050
20051   // Set property with failed access check.
20052   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
20053   CHECK(result->IsObject());
20054
20055   // Set element with failed access check.
20056   result = CompileRun("other[0] = new Object()");
20057   CHECK(result->IsObject());
20058
20059   // Get property attribute with failed access check.
20060   ExpectFalse("\'x\' in other");
20061
20062   // Get property attribute for element with failed access check.
20063   ExpectFalse("0 in other");
20064
20065   // Delete property.
20066   ExpectFalse("delete other.x");
20067
20068   // Delete element.
20069   CHECK_EQ(false, global0->Delete(0));
20070
20071   // DefineAccessor.
20072   CHECK_EQ(false,
20073            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
20074
20075   // Define JavaScript accessor.
20076   ExpectUndefined("Object.prototype.__defineGetter__.call("
20077                   "    other, \'x\', function() { return 42; })");
20078
20079   // LookupAccessor.
20080   ExpectUndefined("Object.prototype.__lookupGetter__.call("
20081                   "    other, \'x\')");
20082
20083   // HasOwnElement.
20084   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
20085
20086   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
20087   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
20088   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
20089
20090   // Reset the failed access check callback so it does not influence
20091   // the other tests.
20092   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
20093 }
20094
20095
20096 TEST(IsolateNewDispose) {
20097   v8::Isolate* current_isolate = CcTest::isolate();
20098   v8::Isolate* isolate = v8::Isolate::New();
20099   CHECK(isolate != NULL);
20100   CHECK(current_isolate != isolate);
20101   CHECK(current_isolate == CcTest::isolate());
20102
20103   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20104   last_location = last_message = NULL;
20105   isolate->Dispose();
20106   CHECK_EQ(last_location, NULL);
20107   CHECK_EQ(last_message, NULL);
20108 }
20109
20110
20111 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
20112   v8::Isolate* isolate = v8::Isolate::New();
20113   {
20114     v8::Isolate::Scope i_scope(isolate);
20115     v8::HandleScope scope(isolate);
20116     LocalContext context(isolate);
20117     // Run something in this isolate.
20118     ExpectTrue("true");
20119     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20120     last_location = last_message = NULL;
20121     // Still entered, should fail.
20122     isolate->Dispose();
20123     CHECK_NE(last_location, NULL);
20124     CHECK_NE(last_message, NULL);
20125   }
20126   isolate->Dispose();
20127 }
20128
20129
20130 TEST(RunTwoIsolatesOnSingleThread) {
20131   // Run isolate 1.
20132   v8::Isolate* isolate1 = v8::Isolate::New();
20133   isolate1->Enter();
20134   v8::Persistent<v8::Context> context1;
20135   {
20136     v8::HandleScope scope(isolate1);
20137     context1.Reset(isolate1, Context::New(isolate1));
20138   }
20139
20140   {
20141     v8::HandleScope scope(isolate1);
20142     v8::Local<v8::Context> context =
20143         v8::Local<v8::Context>::New(isolate1, context1);
20144     v8::Context::Scope context_scope(context);
20145     // Run something in new isolate.
20146     CompileRun("var foo = 'isolate 1';");
20147     ExpectString("function f() { return foo; }; f()", "isolate 1");
20148   }
20149
20150   // Run isolate 2.
20151   v8::Isolate* isolate2 = v8::Isolate::New();
20152   v8::Persistent<v8::Context> context2;
20153
20154   {
20155     v8::Isolate::Scope iscope(isolate2);
20156     v8::HandleScope scope(isolate2);
20157     context2.Reset(isolate2, Context::New(isolate2));
20158     v8::Local<v8::Context> context =
20159         v8::Local<v8::Context>::New(isolate2, context2);
20160     v8::Context::Scope context_scope(context);
20161
20162     // Run something in new isolate.
20163     CompileRun("var foo = 'isolate 2';");
20164     ExpectString("function f() { return foo; }; f()", "isolate 2");
20165   }
20166
20167   {
20168     v8::HandleScope scope(isolate1);
20169     v8::Local<v8::Context> context =
20170         v8::Local<v8::Context>::New(isolate1, context1);
20171     v8::Context::Scope context_scope(context);
20172     // Now again in isolate 1
20173     ExpectString("function f() { return foo; }; f()", "isolate 1");
20174   }
20175
20176   isolate1->Exit();
20177
20178   // Run some stuff in default isolate.
20179   v8::Persistent<v8::Context> context_default;
20180   {
20181     v8::Isolate* isolate = CcTest::isolate();
20182     v8::Isolate::Scope iscope(isolate);
20183     v8::HandleScope scope(isolate);
20184     context_default.Reset(isolate, Context::New(isolate));
20185   }
20186
20187   {
20188     v8::HandleScope scope(CcTest::isolate());
20189     v8::Local<v8::Context> context =
20190         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20191     v8::Context::Scope context_scope(context);
20192     // Variables in other isolates should be not available, verify there
20193     // is an exception.
20194     ExpectTrue("function f() {"
20195                "  try {"
20196                "    foo;"
20197                "    return false;"
20198                "  } catch(e) {"
20199                "    return true;"
20200                "  }"
20201                "};"
20202                "var isDefaultIsolate = true;"
20203                "f()");
20204   }
20205
20206   isolate1->Enter();
20207
20208   {
20209     v8::Isolate::Scope iscope(isolate2);
20210     v8::HandleScope scope(isolate2);
20211     v8::Local<v8::Context> context =
20212         v8::Local<v8::Context>::New(isolate2, context2);
20213     v8::Context::Scope context_scope(context);
20214     ExpectString("function f() { return foo; }; f()", "isolate 2");
20215   }
20216
20217   {
20218     v8::HandleScope scope(v8::Isolate::GetCurrent());
20219     v8::Local<v8::Context> context =
20220         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
20221     v8::Context::Scope context_scope(context);
20222     ExpectString("function f() { return foo; }; f()", "isolate 1");
20223   }
20224
20225   {
20226     v8::Isolate::Scope iscope(isolate2);
20227     context2.Reset();
20228   }
20229
20230   context1.Reset();
20231   isolate1->Exit();
20232
20233   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20234   last_location = last_message = NULL;
20235
20236   isolate1->Dispose();
20237   CHECK_EQ(last_location, NULL);
20238   CHECK_EQ(last_message, NULL);
20239
20240   isolate2->Dispose();
20241   CHECK_EQ(last_location, NULL);
20242   CHECK_EQ(last_message, NULL);
20243
20244   // Check that default isolate still runs.
20245   {
20246     v8::HandleScope scope(CcTest::isolate());
20247     v8::Local<v8::Context> context =
20248         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20249     v8::Context::Scope context_scope(context);
20250     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
20251   }
20252 }
20253
20254
20255 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
20256   v8::Isolate::Scope isolate_scope(isolate);
20257   v8::HandleScope scope(isolate);
20258   LocalContext context(isolate);
20259   i::ScopedVector<char> code(1024);
20260   i::SNPrintF(code, "function fib(n) {"
20261                     "  if (n <= 2) return 1;"
20262                     "  return fib(n-1) + fib(n-2);"
20263                     "}"
20264                     "fib(%d)", limit);
20265   Local<Value> value = CompileRun(code.start());
20266   CHECK(value->IsNumber());
20267   return static_cast<int>(value->NumberValue());
20268 }
20269
20270 class IsolateThread : public v8::base::Thread {
20271  public:
20272   explicit IsolateThread(int fib_limit)
20273       : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
20274
20275   void Run() {
20276     v8::Isolate* isolate = v8::Isolate::New();
20277     result_ = CalcFibonacci(isolate, fib_limit_);
20278     isolate->Dispose();
20279   }
20280
20281   int result() { return result_; }
20282
20283  private:
20284   int fib_limit_;
20285   int result_;
20286 };
20287
20288
20289 TEST(MultipleIsolatesOnIndividualThreads) {
20290   IsolateThread thread1(21);
20291   IsolateThread thread2(12);
20292
20293   // Compute some fibonacci numbers on 3 threads in 3 isolates.
20294   thread1.Start();
20295   thread2.Start();
20296
20297   int result1 = CalcFibonacci(CcTest::isolate(), 21);
20298   int result2 = CalcFibonacci(CcTest::isolate(), 12);
20299
20300   thread1.Join();
20301   thread2.Join();
20302
20303   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
20304   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
20305   CHECK_EQ(result1, 10946);
20306   CHECK_EQ(result2, 144);
20307   CHECK_EQ(result1, thread1.result());
20308   CHECK_EQ(result2, thread2.result());
20309 }
20310
20311
20312 TEST(IsolateDifferentContexts) {
20313   v8::Isolate* isolate = v8::Isolate::New();
20314   Local<v8::Context> context;
20315   {
20316     v8::Isolate::Scope isolate_scope(isolate);
20317     v8::HandleScope handle_scope(isolate);
20318     context = v8::Context::New(isolate);
20319     v8::Context::Scope context_scope(context);
20320     Local<Value> v = CompileRun("2");
20321     CHECK(v->IsNumber());
20322     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
20323   }
20324   {
20325     v8::Isolate::Scope isolate_scope(isolate);
20326     v8::HandleScope handle_scope(isolate);
20327     context = v8::Context::New(isolate);
20328     v8::Context::Scope context_scope(context);
20329     Local<Value> v = CompileRun("22");
20330     CHECK(v->IsNumber());
20331     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
20332   }
20333   isolate->Dispose();
20334 }
20335
20336 class InitDefaultIsolateThread : public v8::base::Thread {
20337  public:
20338   enum TestCase {
20339     SetResourceConstraints,
20340     SetFatalHandler,
20341     SetCounterFunction,
20342     SetCreateHistogramFunction,
20343     SetAddHistogramSampleFunction
20344   };
20345
20346   explicit InitDefaultIsolateThread(TestCase testCase)
20347       : Thread(Options("InitDefaultIsolateThread")),
20348         testCase_(testCase),
20349         result_(false) {}
20350
20351   void Run() {
20352     v8::Isolate::CreateParams create_params;
20353     switch (testCase_) {
20354       case SetResourceConstraints: {
20355         create_params.constraints.set_max_semi_space_size(1);
20356         create_params.constraints.set_max_old_space_size(4);
20357         break;
20358       }
20359       default:
20360         break;
20361     }
20362     v8::Isolate* isolate = v8::Isolate::New(create_params);
20363     isolate->Enter();
20364     switch (testCase_) {
20365       case SetResourceConstraints:
20366         // Already handled in pre-Isolate-creation block.
20367         break;
20368
20369       case SetFatalHandler:
20370         v8::V8::SetFatalErrorHandler(NULL);
20371         break;
20372
20373       case SetCounterFunction:
20374         CcTest::isolate()->SetCounterFunction(NULL);
20375         break;
20376
20377       case SetCreateHistogramFunction:
20378         CcTest::isolate()->SetCreateHistogramFunction(NULL);
20379         break;
20380
20381       case SetAddHistogramSampleFunction:
20382         CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
20383         break;
20384     }
20385     isolate->Exit();
20386     isolate->Dispose();
20387     result_ = true;
20388   }
20389
20390   bool result() { return result_; }
20391
20392  private:
20393   TestCase testCase_;
20394   bool result_;
20395 };
20396
20397
20398 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
20399   InitDefaultIsolateThread thread(testCase);
20400   thread.Start();
20401   thread.Join();
20402   CHECK_EQ(thread.result(), true);
20403 }
20404
20405
20406 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
20407   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
20408 }
20409
20410
20411 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
20412   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
20413 }
20414
20415
20416 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
20417   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
20418 }
20419
20420
20421 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
20422   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
20423 }
20424
20425
20426 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
20427   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
20428 }
20429
20430
20431 TEST(StringCheckMultipleContexts) {
20432   const char* code =
20433       "(function() { return \"a\".charAt(0); })()";
20434
20435   {
20436     // Run the code twice in the first context to initialize the call IC.
20437     LocalContext context1;
20438     v8::HandleScope scope(context1->GetIsolate());
20439     ExpectString(code, "a");
20440     ExpectString(code, "a");
20441   }
20442
20443   {
20444     // Change the String.prototype in the second context and check
20445     // that the right function gets called.
20446     LocalContext context2;
20447     v8::HandleScope scope(context2->GetIsolate());
20448     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
20449     ExpectString(code, "not a");
20450   }
20451 }
20452
20453
20454 TEST(NumberCheckMultipleContexts) {
20455   const char* code =
20456       "(function() { return (42).toString(); })()";
20457
20458   {
20459     // Run the code twice in the first context to initialize the call IC.
20460     LocalContext context1;
20461     v8::HandleScope scope(context1->GetIsolate());
20462     ExpectString(code, "42");
20463     ExpectString(code, "42");
20464   }
20465
20466   {
20467     // Change the Number.prototype in the second context and check
20468     // that the right function gets called.
20469     LocalContext context2;
20470     v8::HandleScope scope(context2->GetIsolate());
20471     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
20472     ExpectString(code, "not 42");
20473   }
20474 }
20475
20476
20477 TEST(BooleanCheckMultipleContexts) {
20478   const char* code =
20479       "(function() { return true.toString(); })()";
20480
20481   {
20482     // Run the code twice in the first context to initialize the call IC.
20483     LocalContext context1;
20484     v8::HandleScope scope(context1->GetIsolate());
20485     ExpectString(code, "true");
20486     ExpectString(code, "true");
20487   }
20488
20489   {
20490     // Change the Boolean.prototype in the second context and check
20491     // that the right function gets called.
20492     LocalContext context2;
20493     v8::HandleScope scope(context2->GetIsolate());
20494     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
20495     ExpectString(code, "");
20496   }
20497 }
20498
20499
20500 TEST(DontDeleteCellLoadIC) {
20501   const char* function_code =
20502       "function readCell() { while (true) { return cell; } }";
20503
20504   {
20505     // Run the code twice in the first context to initialize the load
20506     // IC for a don't delete cell.
20507     LocalContext context1;
20508     v8::HandleScope scope(context1->GetIsolate());
20509     CompileRun("var cell = \"first\";");
20510     ExpectBoolean("delete cell", false);
20511     CompileRun(function_code);
20512     ExpectString("readCell()", "first");
20513     ExpectString("readCell()", "first");
20514   }
20515
20516   {
20517     // Use a deletable cell in the second context.
20518     LocalContext context2;
20519     v8::HandleScope scope(context2->GetIsolate());
20520     CompileRun("cell = \"second\";");
20521     CompileRun(function_code);
20522     ExpectString("readCell()", "second");
20523     ExpectBoolean("delete cell", true);
20524     ExpectString("(function() {"
20525                  "  try {"
20526                  "    return readCell();"
20527                  "  } catch(e) {"
20528                  "    return e.toString();"
20529                  "  }"
20530                  "})()",
20531                  "ReferenceError: cell is not defined");
20532     CompileRun("cell = \"new_second\";");
20533     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20534     ExpectString("readCell()", "new_second");
20535     ExpectString("readCell()", "new_second");
20536   }
20537 }
20538
20539
20540 TEST(DontDeleteCellLoadICForceDelete) {
20541   const char* function_code =
20542       "function readCell() { while (true) { return cell; } }";
20543
20544   // Run the code twice to initialize the load IC for a don't delete
20545   // cell.
20546   LocalContext context;
20547   v8::HandleScope scope(context->GetIsolate());
20548   CompileRun("var cell = \"value\";");
20549   ExpectBoolean("delete cell", false);
20550   CompileRun(function_code);
20551   ExpectString("readCell()", "value");
20552   ExpectString("readCell()", "value");
20553
20554   // Delete the cell using the API and check the inlined code works
20555   // correctly.
20556   CHECK(context->Global()->ForceDelete(v8_str("cell")));
20557   ExpectString("(function() {"
20558                "  try {"
20559                "    return readCell();"
20560                "  } catch(e) {"
20561                "    return e.toString();"
20562                "  }"
20563                "})()",
20564                "ReferenceError: cell is not defined");
20565 }
20566
20567
20568 TEST(DontDeleteCellLoadICAPI) {
20569   const char* function_code =
20570       "function readCell() { while (true) { return cell; } }";
20571
20572   // Run the code twice to initialize the load IC for a don't delete
20573   // cell created using the API.
20574   LocalContext context;
20575   v8::HandleScope scope(context->GetIsolate());
20576   context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
20577   ExpectBoolean("delete cell", false);
20578   CompileRun(function_code);
20579   ExpectString("readCell()", "value");
20580   ExpectString("readCell()", "value");
20581
20582   // Delete the cell using the API and check the inlined code works
20583   // correctly.
20584   CHECK(context->Global()->ForceDelete(v8_str("cell")));
20585   ExpectString("(function() {"
20586                "  try {"
20587                "    return readCell();"
20588                "  } catch(e) {"
20589                "    return e.toString();"
20590                "  }"
20591                "})()",
20592                "ReferenceError: cell is not defined");
20593 }
20594
20595
20596 class Visitor42 : public v8::PersistentHandleVisitor {
20597  public:
20598   explicit Visitor42(v8::Persistent<v8::Object>* object)
20599       : counter_(0), object_(object) { }
20600
20601   virtual void VisitPersistentHandle(Persistent<Value>* value,
20602                                      uint16_t class_id) {
20603     if (class_id != 42) return;
20604     CHECK_EQ(42, value->WrapperClassId());
20605     v8::Isolate* isolate = CcTest::isolate();
20606     v8::HandleScope handle_scope(isolate);
20607     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
20608     v8::Handle<v8::Value> object =
20609         v8::Local<v8::Object>::New(isolate, *object_);
20610     CHECK(handle->IsObject());
20611     CHECK_EQ(Handle<Object>::Cast(handle), object);
20612     ++counter_;
20613   }
20614
20615   int counter_;
20616   v8::Persistent<v8::Object>* object_;
20617 };
20618
20619
20620 TEST(PersistentHandleVisitor) {
20621   LocalContext context;
20622   v8::Isolate* isolate = context->GetIsolate();
20623   v8::HandleScope scope(isolate);
20624   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20625   CHECK_EQ(0, object.WrapperClassId());
20626   object.SetWrapperClassId(42);
20627   CHECK_EQ(42, object.WrapperClassId());
20628
20629   Visitor42 visitor(&object);
20630   v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
20631   CHECK_EQ(1, visitor.counter_);
20632
20633   object.Reset();
20634 }
20635
20636
20637 TEST(WrapperClassId) {
20638   LocalContext context;
20639   v8::Isolate* isolate = context->GetIsolate();
20640   v8::HandleScope scope(isolate);
20641   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20642   CHECK_EQ(0, object.WrapperClassId());
20643   object.SetWrapperClassId(65535);
20644   CHECK_EQ(65535, object.WrapperClassId());
20645   object.Reset();
20646 }
20647
20648
20649 TEST(PersistentHandleInNewSpaceVisitor) {
20650   LocalContext context;
20651   v8::Isolate* isolate = context->GetIsolate();
20652   v8::HandleScope scope(isolate);
20653   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
20654   CHECK_EQ(0, object1.WrapperClassId());
20655   object1.SetWrapperClassId(42);
20656   CHECK_EQ(42, object1.WrapperClassId());
20657
20658   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20659   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20660
20661   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
20662   CHECK_EQ(0, object2.WrapperClassId());
20663   object2.SetWrapperClassId(42);
20664   CHECK_EQ(42, object2.WrapperClassId());
20665
20666   Visitor42 visitor(&object2);
20667   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
20668   CHECK_EQ(1, visitor.counter_);
20669
20670   object1.Reset();
20671   object2.Reset();
20672 }
20673
20674
20675 TEST(RegExp) {
20676   LocalContext context;
20677   v8::HandleScope scope(context->GetIsolate());
20678
20679   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
20680   CHECK(re->IsRegExp());
20681   CHECK(re->GetSource()->Equals(v8_str("foo")));
20682   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20683
20684   re = v8::RegExp::New(v8_str("bar"),
20685                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20686                                                       v8::RegExp::kGlobal));
20687   CHECK(re->IsRegExp());
20688   CHECK(re->GetSource()->Equals(v8_str("bar")));
20689   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
20690            static_cast<int>(re->GetFlags()));
20691
20692   re = v8::RegExp::New(v8_str("baz"),
20693                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20694                                                       v8::RegExp::kMultiline));
20695   CHECK(re->IsRegExp());
20696   CHECK(re->GetSource()->Equals(v8_str("baz")));
20697   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20698            static_cast<int>(re->GetFlags()));
20699
20700   re = CompileRun("/quux/").As<v8::RegExp>();
20701   CHECK(re->IsRegExp());
20702   CHECK(re->GetSource()->Equals(v8_str("quux")));
20703   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20704
20705   re = CompileRun("/quux/gm").As<v8::RegExp>();
20706   CHECK(re->IsRegExp());
20707   CHECK(re->GetSource()->Equals(v8_str("quux")));
20708   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
20709            static_cast<int>(re->GetFlags()));
20710
20711   // Override the RegExp constructor and check the API constructor
20712   // still works.
20713   CompileRun("RegExp = function() {}");
20714
20715   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
20716   CHECK(re->IsRegExp());
20717   CHECK(re->GetSource()->Equals(v8_str("foobar")));
20718   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20719
20720   re = v8::RegExp::New(v8_str("foobarbaz"),
20721                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20722                                                       v8::RegExp::kMultiline));
20723   CHECK(re->IsRegExp());
20724   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
20725   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20726            static_cast<int>(re->GetFlags()));
20727
20728   context->Global()->Set(v8_str("re"), re);
20729   ExpectTrue("re.test('FoobarbaZ')");
20730
20731   // RegExps are objects on which you can set properties.
20732   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
20733   v8::Handle<v8::Value> value(CompileRun("re.property"));
20734   CHECK_EQ(32, value->Int32Value());
20735
20736   v8::TryCatch try_catch;
20737   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
20738   CHECK(re.IsEmpty());
20739   CHECK(try_catch.HasCaught());
20740   context->Global()->Set(v8_str("ex"), try_catch.Exception());
20741   ExpectTrue("ex instanceof SyntaxError");
20742 }
20743
20744
20745 THREADED_TEST(Equals) {
20746   LocalContext localContext;
20747   v8::HandleScope handleScope(localContext->GetIsolate());
20748
20749   v8::Handle<v8::Object> globalProxy = localContext->Global();
20750   v8::Handle<Value> global = globalProxy->GetPrototype();
20751
20752   CHECK(global->StrictEquals(global));
20753   CHECK(!global->StrictEquals(globalProxy));
20754   CHECK(!globalProxy->StrictEquals(global));
20755   CHECK(globalProxy->StrictEquals(globalProxy));
20756
20757   CHECK(global->Equals(global));
20758   CHECK(!global->Equals(globalProxy));
20759   CHECK(!globalProxy->Equals(global));
20760   CHECK(globalProxy->Equals(globalProxy));
20761 }
20762
20763
20764 static void Getter(v8::Local<v8::String> property,
20765                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
20766   info.GetReturnValue().Set(v8_str("42!"));
20767 }
20768
20769
20770 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20771   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
20772   result->Set(0, v8_str("universalAnswer"));
20773   info.GetReturnValue().Set(result);
20774 }
20775
20776
20777 TEST(NamedEnumeratorAndForIn) {
20778   LocalContext context;
20779   v8::Isolate* isolate = context->GetIsolate();
20780   v8::HandleScope handle_scope(isolate);
20781   v8::Context::Scope context_scope(context.local());
20782
20783   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
20784   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
20785   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
20786   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
20787         "var result = []; for (var k in o) result.push(k); result"));
20788   CHECK_EQ(1, result->Length());
20789   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
20790 }
20791
20792
20793 TEST(DefinePropertyPostDetach) {
20794   LocalContext context;
20795   v8::HandleScope scope(context->GetIsolate());
20796   v8::Handle<v8::Object> proxy = context->Global();
20797   v8::Handle<v8::Function> define_property =
20798       CompileRun("(function() {"
20799                  "  Object.defineProperty("
20800                  "    this,"
20801                  "    1,"
20802                  "    { configurable: true, enumerable: true, value: 3 });"
20803                  "})").As<Function>();
20804   context->DetachGlobal();
20805   define_property->Call(proxy, 0, NULL);
20806 }
20807
20808
20809 static void InstallContextId(v8::Handle<Context> context, int id) {
20810   Context::Scope scope(context);
20811   CompileRun("Object.prototype").As<Object>()->
20812       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
20813 }
20814
20815
20816 static void CheckContextId(v8::Handle<Object> object, int expected) {
20817   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
20818 }
20819
20820
20821 THREADED_TEST(CreationContext) {
20822   v8::Isolate* isolate = CcTest::isolate();
20823   HandleScope handle_scope(isolate);
20824   Handle<Context> context1 = Context::New(isolate);
20825   InstallContextId(context1, 1);
20826   Handle<Context> context2 = Context::New(isolate);
20827   InstallContextId(context2, 2);
20828   Handle<Context> context3 = Context::New(isolate);
20829   InstallContextId(context3, 3);
20830
20831   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20832
20833   Local<Object> object1;
20834   Local<Function> func1;
20835   {
20836     Context::Scope scope(context1);
20837     object1 = Object::New(isolate);
20838     func1 = tmpl->GetFunction();
20839   }
20840
20841   Local<Object> object2;
20842   Local<Function> func2;
20843   {
20844     Context::Scope scope(context2);
20845     object2 = Object::New(isolate);
20846     func2 = tmpl->GetFunction();
20847   }
20848
20849   Local<Object> instance1;
20850   Local<Object> instance2;
20851
20852   {
20853     Context::Scope scope(context3);
20854     instance1 = func1->NewInstance();
20855     instance2 = func2->NewInstance();
20856   }
20857
20858   CHECK(object1->CreationContext() == context1);
20859   CheckContextId(object1, 1);
20860   CHECK(func1->CreationContext() == context1);
20861   CheckContextId(func1, 1);
20862   CHECK(instance1->CreationContext() == context1);
20863   CheckContextId(instance1, 1);
20864   CHECK(object2->CreationContext() == context2);
20865   CheckContextId(object2, 2);
20866   CHECK(func2->CreationContext() == context2);
20867   CheckContextId(func2, 2);
20868   CHECK(instance2->CreationContext() == context2);
20869   CheckContextId(instance2, 2);
20870
20871   {
20872     Context::Scope scope(context1);
20873     CHECK(object1->CreationContext() == context1);
20874     CheckContextId(object1, 1);
20875     CHECK(func1->CreationContext() == context1);
20876     CheckContextId(func1, 1);
20877     CHECK(instance1->CreationContext() == context1);
20878     CheckContextId(instance1, 1);
20879     CHECK(object2->CreationContext() == context2);
20880     CheckContextId(object2, 2);
20881     CHECK(func2->CreationContext() == context2);
20882     CheckContextId(func2, 2);
20883     CHECK(instance2->CreationContext() == context2);
20884     CheckContextId(instance2, 2);
20885   }
20886
20887   {
20888     Context::Scope scope(context2);
20889     CHECK(object1->CreationContext() == context1);
20890     CheckContextId(object1, 1);
20891     CHECK(func1->CreationContext() == context1);
20892     CheckContextId(func1, 1);
20893     CHECK(instance1->CreationContext() == context1);
20894     CheckContextId(instance1, 1);
20895     CHECK(object2->CreationContext() == context2);
20896     CheckContextId(object2, 2);
20897     CHECK(func2->CreationContext() == context2);
20898     CheckContextId(func2, 2);
20899     CHECK(instance2->CreationContext() == context2);
20900     CheckContextId(instance2, 2);
20901   }
20902 }
20903
20904
20905 THREADED_TEST(CreationContextOfJsFunction) {
20906   HandleScope handle_scope(CcTest::isolate());
20907   Handle<Context> context = Context::New(CcTest::isolate());
20908   InstallContextId(context, 1);
20909
20910   Local<Object> function;
20911   {
20912     Context::Scope scope(context);
20913     function = CompileRun("function foo() {}; foo").As<Object>();
20914   }
20915
20916   CHECK(function->CreationContext() == context);
20917   CheckContextId(function, 1);
20918 }
20919
20920
20921 void HasOwnPropertyIndexedPropertyGetter(
20922     uint32_t index,
20923     const v8::PropertyCallbackInfo<v8::Value>& info) {
20924   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20925 }
20926
20927
20928 void HasOwnPropertyNamedPropertyGetter(
20929     Local<String> property,
20930     const v8::PropertyCallbackInfo<v8::Value>& info) {
20931   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20932 }
20933
20934
20935 void HasOwnPropertyIndexedPropertyQuery(
20936     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20937   if (index == 42) info.GetReturnValue().Set(1);
20938 }
20939
20940
20941 void HasOwnPropertyNamedPropertyQuery(
20942     Local<String> property,
20943     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20944   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20945 }
20946
20947
20948 void HasOwnPropertyNamedPropertyQuery2(
20949     Local<String> property,
20950     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20951   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20952 }
20953
20954
20955 void HasOwnPropertyAccessorGetter(
20956     Local<String> property,
20957     const v8::PropertyCallbackInfo<v8::Value>& info) {
20958   info.GetReturnValue().Set(v8_str("yes"));
20959 }
20960
20961
20962 TEST(HasOwnProperty) {
20963   LocalContext env;
20964   v8::Isolate* isolate = env->GetIsolate();
20965   v8::HandleScope scope(isolate);
20966   { // Check normal properties and defined getters.
20967     Handle<Value> value = CompileRun(
20968         "function Foo() {"
20969         "    this.foo = 11;"
20970         "    this.__defineGetter__('baz', function() { return 1; });"
20971         "};"
20972         "function Bar() { "
20973         "    this.bar = 13;"
20974         "    this.__defineGetter__('bla', function() { return 2; });"
20975         "};"
20976         "Bar.prototype = new Foo();"
20977         "new Bar();");
20978     CHECK(value->IsObject());
20979     Handle<Object> object = value->ToObject();
20980     CHECK(object->Has(v8_str("foo")));
20981     CHECK(!object->HasOwnProperty(v8_str("foo")));
20982     CHECK(object->HasOwnProperty(v8_str("bar")));
20983     CHECK(object->Has(v8_str("baz")));
20984     CHECK(!object->HasOwnProperty(v8_str("baz")));
20985     CHECK(object->HasOwnProperty(v8_str("bla")));
20986   }
20987   { // Check named getter interceptors.
20988     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20989     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20990     Handle<Object> instance = templ->NewInstance();
20991     CHECK(!instance->HasOwnProperty(v8_str("42")));
20992     CHECK(instance->HasOwnProperty(v8_str("foo")));
20993     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20994   }
20995   { // Check indexed getter interceptors.
20996     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20997     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20998     Handle<Object> instance = templ->NewInstance();
20999     CHECK(instance->HasOwnProperty(v8_str("42")));
21000     CHECK(!instance->HasOwnProperty(v8_str("43")));
21001     CHECK(!instance->HasOwnProperty(v8_str("foo")));
21002   }
21003   { // Check named query interceptors.
21004     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21005     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
21006     Handle<Object> instance = templ->NewInstance();
21007     CHECK(instance->HasOwnProperty(v8_str("foo")));
21008     CHECK(!instance->HasOwnProperty(v8_str("bar")));
21009   }
21010   { // Check indexed query interceptors.
21011     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21012     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
21013     Handle<Object> instance = templ->NewInstance();
21014     CHECK(instance->HasOwnProperty(v8_str("42")));
21015     CHECK(!instance->HasOwnProperty(v8_str("41")));
21016   }
21017   { // Check callbacks.
21018     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21019     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
21020     Handle<Object> instance = templ->NewInstance();
21021     CHECK(instance->HasOwnProperty(v8_str("foo")));
21022     CHECK(!instance->HasOwnProperty(v8_str("bar")));
21023   }
21024   { // Check that query wins on disagreement.
21025     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21026     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
21027                                    0,
21028                                    HasOwnPropertyNamedPropertyQuery2);
21029     Handle<Object> instance = templ->NewInstance();
21030     CHECK(!instance->HasOwnProperty(v8_str("foo")));
21031     CHECK(instance->HasOwnProperty(v8_str("bar")));
21032   }
21033 }
21034
21035
21036 TEST(IndexedInterceptorWithStringProto) {
21037   v8::Isolate* isolate = CcTest::isolate();
21038   v8::HandleScope scope(isolate);
21039   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21040   templ->SetIndexedPropertyHandler(NULL,
21041                                    NULL,
21042                                    HasOwnPropertyIndexedPropertyQuery);
21043   LocalContext context;
21044   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21045   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
21046   // These should be intercepted.
21047   CHECK(CompileRun("42 in obj")->BooleanValue());
21048   CHECK(CompileRun("'42' in obj")->BooleanValue());
21049   // These should fall through to the String prototype.
21050   CHECK(CompileRun("0 in obj")->BooleanValue());
21051   CHECK(CompileRun("'0' in obj")->BooleanValue());
21052   // And these should both fail.
21053   CHECK(!CompileRun("32 in obj")->BooleanValue());
21054   CHECK(!CompileRun("'32' in obj")->BooleanValue());
21055 }
21056
21057
21058 void CheckCodeGenerationAllowed() {
21059   Handle<Value> result = CompileRun("eval('42')");
21060   CHECK_EQ(42, result->Int32Value());
21061   result = CompileRun("(function(e) { return e('42'); })(eval)");
21062   CHECK_EQ(42, result->Int32Value());
21063   result = CompileRun("var f = new Function('return 42'); f()");
21064   CHECK_EQ(42, result->Int32Value());
21065 }
21066
21067
21068 void CheckCodeGenerationDisallowed() {
21069   TryCatch try_catch;
21070
21071   Handle<Value> result = CompileRun("eval('42')");
21072   CHECK(result.IsEmpty());
21073   CHECK(try_catch.HasCaught());
21074   try_catch.Reset();
21075
21076   result = CompileRun("(function(e) { return e('42'); })(eval)");
21077   CHECK(result.IsEmpty());
21078   CHECK(try_catch.HasCaught());
21079   try_catch.Reset();
21080
21081   result = CompileRun("var f = new Function('return 42'); f()");
21082   CHECK(result.IsEmpty());
21083   CHECK(try_catch.HasCaught());
21084 }
21085
21086
21087 bool CodeGenerationAllowed(Local<Context> context) {
21088   ApiTestFuzzer::Fuzz();
21089   return true;
21090 }
21091
21092
21093 bool CodeGenerationDisallowed(Local<Context> context) {
21094   ApiTestFuzzer::Fuzz();
21095   return false;
21096 }
21097
21098
21099 THREADED_TEST(AllowCodeGenFromStrings) {
21100   LocalContext context;
21101   v8::HandleScope scope(context->GetIsolate());
21102
21103   // eval and the Function constructor allowed by default.
21104   CHECK(context->IsCodeGenerationFromStringsAllowed());
21105   CheckCodeGenerationAllowed();
21106
21107   // Disallow eval and the Function constructor.
21108   context->AllowCodeGenerationFromStrings(false);
21109   CHECK(!context->IsCodeGenerationFromStringsAllowed());
21110   CheckCodeGenerationDisallowed();
21111
21112   // Allow again.
21113   context->AllowCodeGenerationFromStrings(true);
21114   CheckCodeGenerationAllowed();
21115
21116   // Disallow but setting a global callback that will allow the calls.
21117   context->AllowCodeGenerationFromStrings(false);
21118   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
21119   CHECK(!context->IsCodeGenerationFromStringsAllowed());
21120   CheckCodeGenerationAllowed();
21121
21122   // Set a callback that disallows the code generation.
21123   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
21124   CHECK(!context->IsCodeGenerationFromStringsAllowed());
21125   CheckCodeGenerationDisallowed();
21126 }
21127
21128
21129 TEST(SetErrorMessageForCodeGenFromStrings) {
21130   LocalContext context;
21131   v8::HandleScope scope(context->GetIsolate());
21132   TryCatch try_catch;
21133
21134   Handle<String> message = v8_str("Message") ;
21135   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
21136   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
21137   context->AllowCodeGenerationFromStrings(false);
21138   context->SetErrorMessageForCodeGenerationFromStrings(message);
21139   Handle<Value> result = CompileRun("eval('42')");
21140   CHECK(result.IsEmpty());
21141   CHECK(try_catch.HasCaught());
21142   Handle<String> actual_message = try_catch.Message()->Get();
21143   CHECK(expected_message->Equals(actual_message));
21144 }
21145
21146
21147 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
21148 }
21149
21150
21151 THREADED_TEST(CallAPIFunctionOnNonObject) {
21152   LocalContext context;
21153   v8::Isolate* isolate = context->GetIsolate();
21154   v8::HandleScope scope(isolate);
21155   Handle<FunctionTemplate> templ =
21156       v8::FunctionTemplate::New(isolate, NonObjectThis);
21157   Handle<Function> function = templ->GetFunction();
21158   context->Global()->Set(v8_str("f"), function);
21159   TryCatch try_catch;
21160   CompileRun("f.call(2)");
21161 }
21162
21163
21164 // Regression test for issue 1470.
21165 THREADED_TEST(ReadOnlyIndexedProperties) {
21166   v8::Isolate* isolate = CcTest::isolate();
21167   v8::HandleScope scope(isolate);
21168   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21169
21170   LocalContext context;
21171   Local<v8::Object> obj = templ->NewInstance();
21172   context->Global()->Set(v8_str("obj"), obj);
21173   obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
21174   obj->Set(v8_str("1"), v8_str("foobar"));
21175   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
21176   obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
21177   obj->Set(v8_num(2), v8_str("foobar"));
21178   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
21179
21180   // Test non-smi case.
21181   obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
21182   obj->Set(v8_str("2000000000"), v8_str("foobar"));
21183   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
21184 }
21185
21186
21187 THREADED_TEST(Regress1516) {
21188   LocalContext context;
21189   v8::HandleScope scope(context->GetIsolate());
21190
21191   { v8::HandleScope temp_scope(context->GetIsolate());
21192     CompileRun("({'a': 0})");
21193   }
21194
21195   int elements;
21196   { i::MapCache* map_cache =
21197         i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
21198     elements = map_cache->NumberOfElements();
21199     CHECK_LE(1, elements);
21200   }
21201
21202   CcTest::heap()->CollectAllGarbage(
21203       i::Heap::kAbortIncrementalMarkingMask);
21204   { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
21205     if (raw_map_cache != CcTest::heap()->undefined_value()) {
21206       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
21207       CHECK_GT(elements, map_cache->NumberOfElements());
21208     }
21209   }
21210 }
21211
21212
21213 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
21214                                                 Local<Value> name,
21215                                                 v8::AccessType type,
21216                                                 Local<Value> data) {
21217   // Only block read access to __proto__.
21218   if (type == v8::ACCESS_GET &&
21219       name->IsString() &&
21220       name->ToString()->Length() == 9 &&
21221       name->ToString()->Utf8Length() == 9) {
21222     char buffer[10];
21223     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
21224     return strncmp(buffer, "__proto__", 9) != 0;
21225   }
21226
21227   return true;
21228 }
21229
21230
21231 THREADED_TEST(Regress93759) {
21232   v8::Isolate* isolate = CcTest::isolate();
21233   HandleScope scope(isolate);
21234
21235   // Template for object with security check.
21236   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
21237   // We don't do indexing, so any callback can be used for that.
21238   no_proto_template->SetAccessCheckCallbacks(
21239       BlockProtoNamedSecurityTestCallback,
21240       IndexedSecurityTestCallback);
21241
21242   // Templates for objects with hidden prototypes and possibly security check.
21243   Local<FunctionTemplate> hidden_proto_template =
21244       v8::FunctionTemplate::New(isolate);
21245   hidden_proto_template->SetHiddenPrototype(true);
21246
21247   Local<FunctionTemplate> protected_hidden_proto_template =
21248       v8::FunctionTemplate::New(isolate);
21249   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
21250       BlockProtoNamedSecurityTestCallback,
21251       IndexedSecurityTestCallback);
21252   protected_hidden_proto_template->SetHiddenPrototype(true);
21253
21254   // Context for "foreign" objects used in test.
21255   Local<Context> context = v8::Context::New(isolate);
21256   context->Enter();
21257
21258   // Plain object, no security check.
21259   Local<Object> simple_object = Object::New(isolate);
21260
21261   // Object with explicit security check.
21262   Local<Object> protected_object =
21263       no_proto_template->NewInstance();
21264
21265   // JSGlobalProxy object, always have security check.
21266   Local<Object> proxy_object =
21267       context->Global();
21268
21269   // Global object, the  prototype of proxy_object. No security checks.
21270   Local<Object> global_object =
21271       proxy_object->GetPrototype()->ToObject();
21272
21273   // Hidden prototype without security check.
21274   Local<Object> hidden_prototype =
21275       hidden_proto_template->GetFunction()->NewInstance();
21276   Local<Object> object_with_hidden =
21277     Object::New(isolate);
21278   object_with_hidden->SetPrototype(hidden_prototype);
21279
21280   // Hidden prototype with security check on the hidden prototype.
21281   Local<Object> protected_hidden_prototype =
21282       protected_hidden_proto_template->GetFunction()->NewInstance();
21283   Local<Object> object_with_protected_hidden =
21284     Object::New(isolate);
21285   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
21286
21287   context->Exit();
21288
21289   // Template for object for second context. Values to test are put on it as
21290   // properties.
21291   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
21292   global_template->Set(v8_str("simple"), simple_object);
21293   global_template->Set(v8_str("protected"), protected_object);
21294   global_template->Set(v8_str("global"), global_object);
21295   global_template->Set(v8_str("proxy"), proxy_object);
21296   global_template->Set(v8_str("hidden"), object_with_hidden);
21297   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
21298
21299   LocalContext context2(NULL, global_template);
21300
21301   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
21302   CHECK(result1->Equals(simple_object->GetPrototype()));
21303
21304   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
21305   CHECK(result2.IsEmpty());
21306
21307   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
21308   CHECK(result3->Equals(global_object->GetPrototype()));
21309
21310   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
21311   CHECK(result4.IsEmpty());
21312
21313   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
21314   CHECK(result5->Equals(
21315       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
21316
21317   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
21318   CHECK(result6.IsEmpty());
21319 }
21320
21321
21322 THREADED_TEST(Regress125988) {
21323   v8::HandleScope scope(CcTest::isolate());
21324   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
21325   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
21326   LocalContext env;
21327   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
21328   CompileRun("var a = new Object();"
21329              "var b = new Intercept();"
21330              "var c = new Object();"
21331              "c.__proto__ = b;"
21332              "b.__proto__ = a;"
21333              "a.x = 23;"
21334              "for (var i = 0; i < 3; i++) c.x;");
21335   ExpectBoolean("c.hasOwnProperty('x')", false);
21336   ExpectInt32("c.x", 23);
21337   CompileRun("a.y = 42;"
21338              "for (var i = 0; i < 3; i++) c.x;");
21339   ExpectBoolean("c.hasOwnProperty('x')", false);
21340   ExpectInt32("c.x", 23);
21341   ExpectBoolean("c.hasOwnProperty('y')", false);
21342   ExpectInt32("c.y", 42);
21343 }
21344
21345
21346 static void TestReceiver(Local<Value> expected_result,
21347                          Local<Value> expected_receiver,
21348                          const char* code) {
21349   Local<Value> result = CompileRun(code);
21350   CHECK(result->IsObject());
21351   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
21352   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
21353 }
21354
21355
21356 THREADED_TEST(ForeignFunctionReceiver) {
21357   v8::Isolate* isolate = CcTest::isolate();
21358   HandleScope scope(isolate);
21359
21360   // Create two contexts with different "id" properties ('i' and 'o').
21361   // Call a function both from its own context and from a the foreign
21362   // context, and see what "this" is bound to (returning both "this"
21363   // and "this.id" for comparison).
21364
21365   Local<Context> foreign_context = v8::Context::New(isolate);
21366   foreign_context->Enter();
21367   Local<Value> foreign_function =
21368     CompileRun("function func() { return { 0: this.id, "
21369                "                           1: this, "
21370                "                           toString: function() { "
21371                "                               return this[0];"
21372                "                           }"
21373                "                         };"
21374                "}"
21375                "var id = 'i';"
21376                "func;");
21377   CHECK(foreign_function->IsFunction());
21378   foreign_context->Exit();
21379
21380   LocalContext context;
21381
21382   Local<String> password = v8_str("Password");
21383   // Don't get hit by security checks when accessing foreign_context's
21384   // global receiver (aka. global proxy).
21385   context->SetSecurityToken(password);
21386   foreign_context->SetSecurityToken(password);
21387
21388   Local<String> i = v8_str("i");
21389   Local<String> o = v8_str("o");
21390   Local<String> id = v8_str("id");
21391
21392   CompileRun("function ownfunc() { return { 0: this.id, "
21393              "                              1: this, "
21394              "                              toString: function() { "
21395              "                                  return this[0];"
21396              "                              }"
21397              "                             };"
21398              "}"
21399              "var id = 'o';"
21400              "ownfunc");
21401   context->Global()->Set(v8_str("func"), foreign_function);
21402
21403   // Sanity check the contexts.
21404   CHECK(i->Equals(foreign_context->Global()->Get(id)));
21405   CHECK(o->Equals(context->Global()->Get(id)));
21406
21407   // Checking local function's receiver.
21408   // Calling function using its call/apply methods.
21409   TestReceiver(o, context->Global(), "ownfunc.call()");
21410   TestReceiver(o, context->Global(), "ownfunc.apply()");
21411   // Making calls through built-in functions.
21412   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
21413   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
21414   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
21415   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
21416   // Calling with environment record as base.
21417   TestReceiver(o, context->Global(), "ownfunc()");
21418   // Calling with no base.
21419   TestReceiver(o, context->Global(), "(1,ownfunc)()");
21420
21421   // Checking foreign function return value.
21422   // Calling function using its call/apply methods.
21423   TestReceiver(i, foreign_context->Global(), "func.call()");
21424   TestReceiver(i, foreign_context->Global(), "func.apply()");
21425   // Calling function using another context's call/apply methods.
21426   TestReceiver(i, foreign_context->Global(),
21427                "Function.prototype.call.call(func)");
21428   TestReceiver(i, foreign_context->Global(),
21429                "Function.prototype.call.apply(func)");
21430   TestReceiver(i, foreign_context->Global(),
21431                "Function.prototype.apply.call(func)");
21432   TestReceiver(i, foreign_context->Global(),
21433                "Function.prototype.apply.apply(func)");
21434   // Making calls through built-in functions.
21435   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
21436   // ToString(func()) is func()[0], i.e., the returned this.id.
21437   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
21438   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
21439   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
21440
21441   // Calling with environment record as base.
21442   TestReceiver(i, foreign_context->Global(), "func()");
21443   // Calling with no base.
21444   TestReceiver(i, foreign_context->Global(), "(1,func)()");
21445 }
21446
21447
21448 uint8_t callback_fired = 0;
21449
21450
21451 void CallCompletedCallback1() {
21452   v8::base::OS::Print("Firing callback 1.\n");
21453   callback_fired ^= 1;  // Toggle first bit.
21454 }
21455
21456
21457 void CallCompletedCallback2() {
21458   v8::base::OS::Print("Firing callback 2.\n");
21459   callback_fired ^= 2;  // Toggle second bit.
21460 }
21461
21462
21463 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
21464   int32_t level = args[0]->Int32Value();
21465   if (level < 3) {
21466     level++;
21467     v8::base::OS::Print("Entering recursion level %d.\n", level);
21468     char script[64];
21469     i::Vector<char> script_vector(script, sizeof(script));
21470     i::SNPrintF(script_vector, "recursion(%d)", level);
21471     CompileRun(script_vector.start());
21472     v8::base::OS::Print("Leaving recursion level %d.\n", level);
21473     CHECK_EQ(0, callback_fired);
21474   } else {
21475     v8::base::OS::Print("Recursion ends.\n");
21476     CHECK_EQ(0, callback_fired);
21477   }
21478 }
21479
21480
21481 TEST(CallCompletedCallback) {
21482   LocalContext env;
21483   v8::HandleScope scope(env->GetIsolate());
21484   v8::Handle<v8::FunctionTemplate> recursive_runtime =
21485       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
21486   env->Global()->Set(v8_str("recursion"),
21487                      recursive_runtime->GetFunction());
21488   // Adding the same callback a second time has no effect.
21489   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21490   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21491   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
21492   v8::base::OS::Print("--- Script (1) ---\n");
21493   Local<Script> script = v8::Script::Compile(
21494       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
21495   script->Run();
21496   CHECK_EQ(3, callback_fired);
21497
21498   v8::base::OS::Print("\n--- Script (2) ---\n");
21499   callback_fired = 0;
21500   env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
21501   script->Run();
21502   CHECK_EQ(2, callback_fired);
21503
21504   v8::base::OS::Print("\n--- Function ---\n");
21505   callback_fired = 0;
21506   Local<Function> recursive_function =
21507       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
21508   v8::Handle<Value> args[] = { v8_num(0) };
21509   recursive_function->Call(env->Global(), 1, args);
21510   CHECK_EQ(2, callback_fired);
21511 }
21512
21513
21514 void CallCompletedCallbackNoException() {
21515   v8::HandleScope scope(CcTest::isolate());
21516   CompileRun("1+1;");
21517 }
21518
21519
21520 void CallCompletedCallbackException() {
21521   v8::HandleScope scope(CcTest::isolate());
21522   CompileRun("throw 'second exception';");
21523 }
21524
21525
21526 TEST(CallCompletedCallbackOneException) {
21527   LocalContext env;
21528   v8::HandleScope scope(env->GetIsolate());
21529   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
21530   CompileRun("throw 'exception';");
21531 }
21532
21533
21534 TEST(CallCompletedCallbackTwoExceptions) {
21535   LocalContext env;
21536   v8::HandleScope scope(env->GetIsolate());
21537   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
21538   CompileRun("throw 'first exception';");
21539 }
21540
21541
21542 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
21543   v8::HandleScope scope(info.GetIsolate());
21544   CompileRun("ext1Calls++;");
21545 }
21546
21547
21548 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
21549   v8::HandleScope scope(info.GetIsolate());
21550   CompileRun("ext2Calls++;");
21551 }
21552
21553
21554 void* g_passed_to_three = NULL;
21555
21556
21557 static void MicrotaskThree(void* data) {
21558   g_passed_to_three = data;
21559 }
21560
21561
21562 TEST(EnqueueMicrotask) {
21563   LocalContext env;
21564   v8::HandleScope scope(env->GetIsolate());
21565   CompileRun(
21566       "var ext1Calls = 0;"
21567       "var ext2Calls = 0;");
21568   CompileRun("1+1;");
21569   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
21570   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21571
21572   env->GetIsolate()->EnqueueMicrotask(
21573       Function::New(env->GetIsolate(), MicrotaskOne));
21574   CompileRun("1+1;");
21575   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21576   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21577
21578   env->GetIsolate()->EnqueueMicrotask(
21579       Function::New(env->GetIsolate(), MicrotaskOne));
21580   env->GetIsolate()->EnqueueMicrotask(
21581       Function::New(env->GetIsolate(), MicrotaskTwo));
21582   CompileRun("1+1;");
21583   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21584   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21585
21586   env->GetIsolate()->EnqueueMicrotask(
21587       Function::New(env->GetIsolate(), MicrotaskTwo));
21588   CompileRun("1+1;");
21589   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21590   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21591
21592   CompileRun("1+1;");
21593   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21594   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21595
21596   g_passed_to_three = NULL;
21597   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
21598   CompileRun("1+1;");
21599   CHECK_EQ(NULL, g_passed_to_three);
21600   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21601   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21602
21603   int dummy;
21604   env->GetIsolate()->EnqueueMicrotask(
21605       Function::New(env->GetIsolate(), MicrotaskOne));
21606   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
21607   env->GetIsolate()->EnqueueMicrotask(
21608       Function::New(env->GetIsolate(), MicrotaskTwo));
21609   CompileRun("1+1;");
21610   CHECK_EQ(&dummy, g_passed_to_three);
21611   CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
21612   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21613   g_passed_to_three = NULL;
21614 }
21615
21616
21617 static void MicrotaskExceptionOne(
21618     const v8::FunctionCallbackInfo<Value>& info) {
21619   v8::HandleScope scope(info.GetIsolate());
21620   CompileRun("exception1Calls++;");
21621   info.GetIsolate()->ThrowException(
21622       v8::Exception::Error(v8_str("first")));
21623 }
21624
21625
21626 static void MicrotaskExceptionTwo(
21627     const v8::FunctionCallbackInfo<Value>& info) {
21628   v8::HandleScope scope(info.GetIsolate());
21629   CompileRun("exception2Calls++;");
21630   info.GetIsolate()->ThrowException(
21631       v8::Exception::Error(v8_str("second")));
21632 }
21633
21634
21635 TEST(RunMicrotasksIgnoresThrownExceptions) {
21636   LocalContext env;
21637   v8::Isolate* isolate = env->GetIsolate();
21638   v8::HandleScope scope(isolate);
21639   CompileRun(
21640       "var exception1Calls = 0;"
21641       "var exception2Calls = 0;");
21642   isolate->EnqueueMicrotask(
21643       Function::New(isolate, MicrotaskExceptionOne));
21644   isolate->EnqueueMicrotask(
21645       Function::New(isolate, MicrotaskExceptionTwo));
21646   TryCatch try_catch;
21647   CompileRun("1+1;");
21648   CHECK(!try_catch.HasCaught());
21649   CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
21650   CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
21651 }
21652
21653
21654 TEST(SetAutorunMicrotasks) {
21655   LocalContext env;
21656   v8::HandleScope scope(env->GetIsolate());
21657   CompileRun(
21658       "var ext1Calls = 0;"
21659       "var ext2Calls = 0;");
21660   CompileRun("1+1;");
21661   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
21662   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21663
21664   env->GetIsolate()->EnqueueMicrotask(
21665       Function::New(env->GetIsolate(), MicrotaskOne));
21666   CompileRun("1+1;");
21667   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21668   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21669
21670   env->GetIsolate()->SetAutorunMicrotasks(false);
21671   env->GetIsolate()->EnqueueMicrotask(
21672       Function::New(env->GetIsolate(), MicrotaskOne));
21673   env->GetIsolate()->EnqueueMicrotask(
21674       Function::New(env->GetIsolate(), MicrotaskTwo));
21675   CompileRun("1+1;");
21676   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21677   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21678
21679   env->GetIsolate()->RunMicrotasks();
21680   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21681   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21682
21683   env->GetIsolate()->EnqueueMicrotask(
21684       Function::New(env->GetIsolate(), MicrotaskTwo));
21685   CompileRun("1+1;");
21686   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21687   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21688
21689   env->GetIsolate()->RunMicrotasks();
21690   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21691   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21692
21693   env->GetIsolate()->SetAutorunMicrotasks(true);
21694   env->GetIsolate()->EnqueueMicrotask(
21695       Function::New(env->GetIsolate(), MicrotaskTwo));
21696   CompileRun("1+1;");
21697   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21698   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21699
21700   env->GetIsolate()->EnqueueMicrotask(
21701       Function::New(env->GetIsolate(), MicrotaskTwo));
21702   {
21703     v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
21704     CompileRun("1+1;");
21705     CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21706     CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21707   }
21708
21709   CompileRun("1+1;");
21710   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21711   CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
21712 }
21713
21714
21715 TEST(RunMicrotasksWithoutEnteringContext) {
21716   v8::Isolate* isolate = CcTest::isolate();
21717   HandleScope handle_scope(isolate);
21718   isolate->SetAutorunMicrotasks(false);
21719   Handle<Context> context = Context::New(isolate);
21720   {
21721     Context::Scope context_scope(context);
21722     CompileRun("var ext1Calls = 0;");
21723     isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
21724   }
21725   isolate->RunMicrotasks();
21726   {
21727     Context::Scope context_scope(context);
21728     CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21729   }
21730   isolate->SetAutorunMicrotasks(true);
21731 }
21732
21733
21734 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
21735   v8::DebugEvent event = event_details.GetEvent();
21736   if (event != v8::Break) return;
21737   Handle<Object> exec_state = event_details.GetExecutionState();
21738   Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
21739   CompileRun("function f(id) { new FrameDetails(id, 0); }");
21740   Handle<Function> fun = Handle<Function>::Cast(
21741       CcTest::global()->Get(v8_str("f"))->ToObject());
21742   fun->Call(CcTest::global(), 1, &break_id);
21743 }
21744
21745
21746 TEST(Regress385349) {
21747   i::FLAG_allow_natives_syntax = true;
21748   v8::Isolate* isolate = CcTest::isolate();
21749   HandleScope handle_scope(isolate);
21750   isolate->SetAutorunMicrotasks(false);
21751   Handle<Context> context = Context::New(isolate);
21752   v8::Debug::SetDebugEventListener(DebugEventInObserver);
21753   {
21754     Context::Scope context_scope(context);
21755     CompileRun("var obj = {};"
21756                "Object.observe(obj, function(changes) { debugger; });"
21757                "obj.a = 0;");
21758   }
21759   isolate->RunMicrotasks();
21760   isolate->SetAutorunMicrotasks(true);
21761   v8::Debug::SetDebugEventListener(NULL);
21762 }
21763
21764
21765 #ifdef DEBUG
21766 static int probes_counter = 0;
21767 static int misses_counter = 0;
21768 static int updates_counter = 0;
21769
21770
21771 static int* LookupCounter(const char* name) {
21772   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
21773     return &probes_counter;
21774   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
21775     return &misses_counter;
21776   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
21777     return &updates_counter;
21778   }
21779   return NULL;
21780 }
21781
21782
21783 static const char* kMegamorphicTestProgram =
21784     "function ClassA() { };"
21785     "function ClassB() { };"
21786     "ClassA.prototype.foo = function() { };"
21787     "ClassB.prototype.foo = function() { };"
21788     "function fooify(obj) { obj.foo(); };"
21789     "var a = new ClassA();"
21790     "var b = new ClassB();"
21791     "for (var i = 0; i < 10000; i++) {"
21792     "  fooify(a);"
21793     "  fooify(b);"
21794     "}";
21795 #endif
21796
21797
21798 static void StubCacheHelper(bool primary) {
21799 #ifdef DEBUG
21800   i::FLAG_native_code_counters = true;
21801   if (primary) {
21802     i::FLAG_test_primary_stub_cache = true;
21803   } else {
21804     i::FLAG_test_secondary_stub_cache = true;
21805   }
21806   i::FLAG_crankshaft = false;
21807   LocalContext env;
21808   env->GetIsolate()->SetCounterFunction(LookupCounter);
21809   v8::HandleScope scope(env->GetIsolate());
21810   int initial_probes = probes_counter;
21811   int initial_misses = misses_counter;
21812   int initial_updates = updates_counter;
21813   CompileRun(kMegamorphicTestProgram);
21814   int probes = probes_counter - initial_probes;
21815   int misses = misses_counter - initial_misses;
21816   int updates = updates_counter - initial_updates;
21817   CHECK_LT(updates, 10);
21818   CHECK_LT(misses, 10);
21819   // TODO(verwaest): Update this test to overflow the degree of polymorphism
21820   // before megamorphism. The number of probes will only work once we teach the
21821   // serializer to embed references to counters in the stubs, given that the
21822   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
21823   CHECK_GE(probes, 0);
21824 #endif
21825 }
21826
21827
21828 TEST(SecondaryStubCache) {
21829   StubCacheHelper(true);
21830 }
21831
21832
21833 TEST(PrimaryStubCache) {
21834   StubCacheHelper(false);
21835 }
21836
21837
21838 #ifdef DEBUG
21839 static int cow_arrays_created_runtime = 0;
21840
21841
21842 static int* LookupCounterCOWArrays(const char* name) {
21843   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
21844     return &cow_arrays_created_runtime;
21845   }
21846   return NULL;
21847 }
21848 #endif
21849
21850
21851 TEST(CheckCOWArraysCreatedRuntimeCounter) {
21852 #ifdef DEBUG
21853   i::FLAG_native_code_counters = true;
21854   LocalContext env;
21855   env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
21856   v8::HandleScope scope(env->GetIsolate());
21857   int initial_cow_arrays = cow_arrays_created_runtime;
21858   CompileRun("var o = [1, 2, 3];");
21859   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
21860   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
21861   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
21862   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
21863   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
21864 #endif
21865 }
21866
21867
21868 TEST(StaticGetters) {
21869   LocalContext context;
21870   i::Factory* factory = CcTest::i_isolate()->factory();
21871   v8::Isolate* isolate = CcTest::isolate();
21872   v8::HandleScope scope(isolate);
21873   i::Handle<i::Object> undefined_value = factory->undefined_value();
21874   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21875   i::Handle<i::Object> null_value = factory->null_value();
21876   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21877   i::Handle<i::Object> true_value = factory->true_value();
21878   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21879   i::Handle<i::Object> false_value = factory->false_value();
21880   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21881 }
21882
21883
21884 UNINITIALIZED_TEST(IsolateEmbedderData) {
21885   CcTest::DisableAutomaticDispose();
21886   v8::Isolate* isolate = v8::Isolate::New();
21887   isolate->Enter();
21888   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21889   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21890     CHECK_EQ(NULL, isolate->GetData(slot));
21891     CHECK_EQ(NULL, i_isolate->GetData(slot));
21892   }
21893   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21894     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21895     isolate->SetData(slot, data);
21896   }
21897   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21898     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21899     CHECK_EQ(data, isolate->GetData(slot));
21900     CHECK_EQ(data, i_isolate->GetData(slot));
21901   }
21902   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21903     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21904     isolate->SetData(slot, data);
21905   }
21906   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21907     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21908     CHECK_EQ(data, isolate->GetData(slot));
21909     CHECK_EQ(data, i_isolate->GetData(slot));
21910   }
21911   isolate->Exit();
21912   isolate->Dispose();
21913 }
21914
21915
21916 TEST(StringEmpty) {
21917   LocalContext context;
21918   i::Factory* factory = CcTest::i_isolate()->factory();
21919   v8::Isolate* isolate = CcTest::isolate();
21920   v8::HandleScope scope(isolate);
21921   i::Handle<i::Object> empty_string = factory->empty_string();
21922   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21923 }
21924
21925
21926 static int instance_checked_getter_count = 0;
21927 static void InstanceCheckedGetter(
21928     Local<String> name,
21929     const v8::PropertyCallbackInfo<v8::Value>& info) {
21930   CHECK_EQ(name, v8_str("foo"));
21931   instance_checked_getter_count++;
21932   info.GetReturnValue().Set(v8_num(11));
21933 }
21934
21935
21936 static int instance_checked_setter_count = 0;
21937 static void InstanceCheckedSetter(Local<String> name,
21938                       Local<Value> value,
21939                       const v8::PropertyCallbackInfo<void>& info) {
21940   CHECK_EQ(name, v8_str("foo"));
21941   CHECK_EQ(value, v8_num(23));
21942   instance_checked_setter_count++;
21943 }
21944
21945
21946 static void CheckInstanceCheckedResult(int getters, int setters,
21947                                        bool expects_callbacks,
21948                                        TryCatch* try_catch) {
21949   if (expects_callbacks) {
21950     CHECK(!try_catch->HasCaught());
21951     CHECK_EQ(getters, instance_checked_getter_count);
21952     CHECK_EQ(setters, instance_checked_setter_count);
21953   } else {
21954     CHECK(try_catch->HasCaught());
21955     CHECK_EQ(0, instance_checked_getter_count);
21956     CHECK_EQ(0, instance_checked_setter_count);
21957   }
21958   try_catch->Reset();
21959 }
21960
21961
21962 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21963   instance_checked_getter_count = 0;
21964   instance_checked_setter_count = 0;
21965   TryCatch try_catch;
21966
21967   // Test path through generic runtime code.
21968   CompileRun("obj.foo");
21969   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21970   CompileRun("obj.foo = 23");
21971   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21972
21973   // Test path through generated LoadIC and StoredIC.
21974   CompileRun("function test_get(o) { o.foo; }"
21975              "test_get(obj);");
21976   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21977   CompileRun("test_get(obj);");
21978   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21979   CompileRun("test_get(obj);");
21980   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21981   CompileRun("function test_set(o) { o.foo = 23; }"
21982              "test_set(obj);");
21983   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21984   CompileRun("test_set(obj);");
21985   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21986   CompileRun("test_set(obj);");
21987   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21988
21989   // Test path through optimized code.
21990   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21991              "test_get(obj);");
21992   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21993   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21994              "test_set(obj);");
21995   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21996
21997   // Cleanup so that closures start out fresh in next check.
21998   CompileRun("%DeoptimizeFunction(test_get);"
21999              "%ClearFunctionTypeFeedback(test_get);"
22000              "%DeoptimizeFunction(test_set);"
22001              "%ClearFunctionTypeFeedback(test_set);");
22002 }
22003
22004
22005 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
22006   v8::internal::FLAG_allow_natives_syntax = true;
22007   LocalContext context;
22008   v8::HandleScope scope(context->GetIsolate());
22009
22010   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22011   Local<ObjectTemplate> inst = templ->InstanceTemplate();
22012   inst->SetAccessor(v8_str("foo"),
22013                     InstanceCheckedGetter, InstanceCheckedSetter,
22014                     Handle<Value>(),
22015                     v8::DEFAULT,
22016                     v8::None,
22017                     v8::AccessorSignature::New(context->GetIsolate(), templ));
22018   context->Global()->Set(v8_str("f"), templ->GetFunction());
22019
22020   printf("Testing positive ...\n");
22021   CompileRun("var obj = new f();");
22022   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22023   CheckInstanceCheckedAccessors(true);
22024
22025   printf("Testing negative ...\n");
22026   CompileRun("var obj = {};"
22027              "obj.__proto__ = new f();");
22028   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22029   CheckInstanceCheckedAccessors(false);
22030 }
22031
22032
22033 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
22034   v8::internal::FLAG_allow_natives_syntax = true;
22035   LocalContext context;
22036   v8::HandleScope scope(context->GetIsolate());
22037
22038   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22039   Local<ObjectTemplate> inst = templ->InstanceTemplate();
22040   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22041   inst->SetAccessor(v8_str("foo"),
22042                     InstanceCheckedGetter, InstanceCheckedSetter,
22043                     Handle<Value>(),
22044                     v8::DEFAULT,
22045                     v8::None,
22046                     v8::AccessorSignature::New(context->GetIsolate(), templ));
22047   context->Global()->Set(v8_str("f"), templ->GetFunction());
22048
22049   printf("Testing positive ...\n");
22050   CompileRun("var obj = new f();");
22051   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22052   CheckInstanceCheckedAccessors(true);
22053
22054   printf("Testing negative ...\n");
22055   CompileRun("var obj = {};"
22056              "obj.__proto__ = new f();");
22057   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22058   CheckInstanceCheckedAccessors(false);
22059 }
22060
22061
22062 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
22063   v8::internal::FLAG_allow_natives_syntax = true;
22064   LocalContext context;
22065   v8::HandleScope scope(context->GetIsolate());
22066
22067   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22068   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
22069   proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
22070                      InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
22071                      v8::None,
22072                      v8::AccessorSignature::New(context->GetIsolate(), templ));
22073   context->Global()->Set(v8_str("f"), templ->GetFunction());
22074
22075   printf("Testing positive ...\n");
22076   CompileRun("var obj = new f();");
22077   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22078   CheckInstanceCheckedAccessors(true);
22079
22080   printf("Testing negative ...\n");
22081   CompileRun("var obj = {};"
22082              "obj.__proto__ = new f();");
22083   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22084   CheckInstanceCheckedAccessors(false);
22085
22086   printf("Testing positive with modified prototype chain ...\n");
22087   CompileRun("var obj = new f();"
22088              "var pro = {};"
22089              "pro.__proto__ = obj.__proto__;"
22090              "obj.__proto__ = pro;");
22091   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22092   CheckInstanceCheckedAccessors(true);
22093 }
22094
22095
22096 TEST(TryFinallyMessage) {
22097   LocalContext context;
22098   v8::HandleScope scope(context->GetIsolate());
22099   {
22100     // Test that the original error message is not lost if there is a
22101     // recursive call into Javascript is done in the finally block, e.g. to
22102     // initialize an IC. (crbug.com/129171)
22103     TryCatch try_catch;
22104     const char* trigger_ic =
22105         "try {                      \n"
22106         "  throw new Error('test'); \n"
22107         "} finally {                \n"
22108         "  var x = 0;               \n"
22109         "  x++;                     \n"  // Trigger an IC initialization here.
22110         "}                          \n";
22111     CompileRun(trigger_ic);
22112     CHECK(try_catch.HasCaught());
22113     Local<Message> message = try_catch.Message();
22114     CHECK(!message.IsEmpty());
22115     CHECK_EQ(2, message->GetLineNumber());
22116   }
22117
22118   {
22119     // Test that the original exception message is indeed overwritten if
22120     // a new error is thrown in the finally block.
22121     TryCatch try_catch;
22122     const char* throw_again =
22123         "try {                       \n"
22124         "  throw new Error('test');  \n"
22125         "} finally {                 \n"
22126         "  var x = 0;                \n"
22127         "  x++;                      \n"
22128         "  throw new Error('again'); \n"  // This is the new uncaught error.
22129         "}                           \n";
22130     CompileRun(throw_again);
22131     CHECK(try_catch.HasCaught());
22132     Local<Message> message = try_catch.Message();
22133     CHECK(!message.IsEmpty());
22134     CHECK_EQ(6, message->GetLineNumber());
22135   }
22136 }
22137
22138
22139 static void Helper137002(bool do_store,
22140                          bool polymorphic,
22141                          bool remove_accessor,
22142                          bool interceptor) {
22143   LocalContext context;
22144   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
22145   if (interceptor) {
22146     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
22147   } else {
22148     templ->SetAccessor(v8_str("foo"),
22149                        GetterWhichReturns42,
22150                        SetterWhichSetsYOnThisTo23);
22151   }
22152   context->Global()->Set(v8_str("obj"), templ->NewInstance());
22153
22154   // Turn monomorphic on slow object with native accessor, then turn
22155   // polymorphic, finally optimize to create negative lookup and fail.
22156   CompileRun(do_store ?
22157              "function f(x) { x.foo = void 0; }" :
22158              "function f(x) { return x.foo; }");
22159   CompileRun("obj.y = void 0;");
22160   if (!interceptor) {
22161     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
22162   }
22163   CompileRun("obj.__proto__ = null;"
22164              "f(obj); f(obj); f(obj);");
22165   if (polymorphic) {
22166     CompileRun("f({});");
22167   }
22168   CompileRun("obj.y = void 0;"
22169              "%OptimizeFunctionOnNextCall(f);");
22170   if (remove_accessor) {
22171     CompileRun("delete obj.foo;");
22172   }
22173   CompileRun("var result = f(obj);");
22174   if (do_store) {
22175     CompileRun("result = obj.y;");
22176   }
22177   if (remove_accessor && !interceptor) {
22178     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
22179   } else {
22180     CHECK_EQ(do_store ? 23 : 42,
22181              context->Global()->Get(v8_str("result"))->Int32Value());
22182   }
22183 }
22184
22185
22186 THREADED_TEST(Regress137002a) {
22187   i::FLAG_allow_natives_syntax = true;
22188   i::FLAG_compilation_cache = false;
22189   v8::HandleScope scope(CcTest::isolate());
22190   for (int i = 0; i < 16; i++) {
22191     Helper137002(i & 8, i & 4, i & 2, i & 1);
22192   }
22193 }
22194
22195
22196 THREADED_TEST(Regress137002b) {
22197   i::FLAG_allow_natives_syntax = true;
22198   LocalContext context;
22199   v8::Isolate* isolate = context->GetIsolate();
22200   v8::HandleScope scope(isolate);
22201   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22202   templ->SetAccessor(v8_str("foo"),
22203                      GetterWhichReturns42,
22204                      SetterWhichSetsYOnThisTo23);
22205   context->Global()->Set(v8_str("obj"), templ->NewInstance());
22206
22207   // Turn monomorphic on slow object with native accessor, then just
22208   // delete the property and fail.
22209   CompileRun("function load(x) { return x.foo; }"
22210              "function store(x) { x.foo = void 0; }"
22211              "function keyed_load(x, key) { return x[key]; }"
22212              // Second version of function has a different source (add void 0)
22213              // so that it does not share code with the first version.  This
22214              // ensures that the ICs are monomorphic.
22215              "function load2(x) { void 0; return x.foo; }"
22216              "function store2(x) { void 0; x.foo = void 0; }"
22217              "function keyed_load2(x, key) { void 0; return x[key]; }"
22218
22219              "obj.y = void 0;"
22220              "obj.__proto__ = null;"
22221              "var subobj = {};"
22222              "subobj.y = void 0;"
22223              "subobj.__proto__ = obj;"
22224              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22225
22226              // Make the ICs monomorphic.
22227              "load(obj); load(obj);"
22228              "load2(subobj); load2(subobj);"
22229              "store(obj); store(obj);"
22230              "store2(subobj); store2(subobj);"
22231              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
22232              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
22233
22234              // Actually test the shiny new ICs and better not crash. This
22235              // serves as a regression test for issue 142088 as well.
22236              "load(obj);"
22237              "load2(subobj);"
22238              "store(obj);"
22239              "store2(subobj);"
22240              "keyed_load(obj, 'foo');"
22241              "keyed_load2(subobj, 'foo');"
22242
22243              // Delete the accessor.  It better not be called any more now.
22244              "delete obj.foo;"
22245              "obj.y = void 0;"
22246              "subobj.y = void 0;"
22247
22248              "var load_result = load(obj);"
22249              "var load_result2 = load2(subobj);"
22250              "var keyed_load_result = keyed_load(obj, 'foo');"
22251              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
22252              "store(obj);"
22253              "store2(subobj);"
22254              "var y_from_obj = obj.y;"
22255              "var y_from_subobj = subobj.y;");
22256   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
22257   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
22258   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
22259   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
22260   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
22261   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
22262 }
22263
22264
22265 THREADED_TEST(Regress142088) {
22266   i::FLAG_allow_natives_syntax = true;
22267   LocalContext context;
22268   v8::Isolate* isolate = context->GetIsolate();
22269   v8::HandleScope scope(isolate);
22270   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22271   templ->SetAccessor(v8_str("foo"),
22272                      GetterWhichReturns42,
22273                      SetterWhichSetsYOnThisTo23);
22274   context->Global()->Set(v8_str("obj"), templ->NewInstance());
22275
22276   CompileRun("function load(x) { return x.foo; }"
22277              "var o = Object.create(obj);"
22278              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22279              "load(o); load(o); load(o); load(o);");
22280 }
22281
22282
22283 THREADED_TEST(Regress3337) {
22284   LocalContext context;
22285   v8::Isolate* isolate = context->GetIsolate();
22286   v8::HandleScope scope(isolate);
22287   Local<v8::Object> o1 = Object::New(isolate);
22288   Local<v8::Object> o2 = Object::New(isolate);
22289   i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
22290   i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
22291   CHECK(io1->map() == io2->map());
22292   o1->SetIndexedPropertiesToExternalArrayData(
22293       NULL, v8::kExternalUint32Array, 0);
22294   o2->SetIndexedPropertiesToExternalArrayData(
22295       NULL, v8::kExternalUint32Array, 0);
22296   CHECK(io1->map() == io2->map());
22297 }
22298
22299
22300 THREADED_TEST(Regress137496) {
22301   i::FLAG_expose_gc = true;
22302   LocalContext context;
22303   v8::HandleScope scope(context->GetIsolate());
22304
22305   // Compile a try-finally clause where the finally block causes a GC
22306   // while there still is a message pending for external reporting.
22307   TryCatch try_catch;
22308   try_catch.SetVerbose(true);
22309   CompileRun("try { throw new Error(); } finally { gc(); }");
22310   CHECK(try_catch.HasCaught());
22311 }
22312
22313
22314 THREADED_TEST(Regress149912) {
22315   LocalContext context;
22316   v8::HandleScope scope(context->GetIsolate());
22317   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22318   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22319   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
22320   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
22321 }
22322
22323
22324 THREADED_TEST(Regress157124) {
22325   LocalContext context;
22326   v8::Isolate* isolate = context->GetIsolate();
22327   v8::HandleScope scope(isolate);
22328   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22329   Local<Object> obj = templ->NewInstance();
22330   obj->GetIdentityHash();
22331   obj->DeleteHiddenValue(v8_str("Bug"));
22332 }
22333
22334
22335 THREADED_TEST(Regress2535) {
22336   LocalContext context;
22337   v8::HandleScope scope(context->GetIsolate());
22338   Local<Value> set_value = CompileRun("new Set();");
22339   Local<Object> set_object(Local<Object>::Cast(set_value));
22340   CHECK_EQ(0, set_object->InternalFieldCount());
22341   Local<Value> map_value = CompileRun("new Map();");
22342   Local<Object> map_object(Local<Object>::Cast(map_value));
22343   CHECK_EQ(0, map_object->InternalFieldCount());
22344 }
22345
22346
22347 THREADED_TEST(Regress2746) {
22348   LocalContext context;
22349   v8::Isolate* isolate = context->GetIsolate();
22350   v8::HandleScope scope(isolate);
22351   Local<Object> obj = Object::New(isolate);
22352   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
22353   obj->SetHiddenValue(key, v8::Undefined(isolate));
22354   Local<Value> value = obj->GetHiddenValue(key);
22355   CHECK(!value.IsEmpty());
22356   CHECK(value->IsUndefined());
22357 }
22358
22359
22360 THREADED_TEST(Regress260106) {
22361   LocalContext context;
22362   v8::Isolate* isolate = context->GetIsolate();
22363   v8::HandleScope scope(isolate);
22364   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
22365                                                         DummyCallHandler);
22366   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
22367   Local<Function> function = templ->GetFunction();
22368   CHECK(!function.IsEmpty());
22369   CHECK(function->IsFunction());
22370 }
22371
22372
22373 THREADED_TEST(JSONParseObject) {
22374   LocalContext context;
22375   HandleScope scope(context->GetIsolate());
22376   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
22377   Handle<Object> global = context->Global();
22378   global->Set(v8_str("obj"), obj);
22379   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
22380 }
22381
22382
22383 THREADED_TEST(JSONParseNumber) {
22384   LocalContext context;
22385   HandleScope scope(context->GetIsolate());
22386   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
22387   Handle<Object> global = context->Global();
22388   global->Set(v8_str("obj"), obj);
22389   ExpectString("JSON.stringify(obj)", "42");
22390 }
22391
22392
22393 #if V8_OS_POSIX && !V8_OS_NACL
22394 class ThreadInterruptTest {
22395  public:
22396   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
22397   ~ThreadInterruptTest() {}
22398
22399   void RunTest() {
22400     InterruptThread i_thread(this);
22401     i_thread.Start();
22402
22403     sem_.Wait();
22404     CHECK_EQ(kExpectedValue, sem_value_);
22405   }
22406
22407  private:
22408   static const int kExpectedValue = 1;
22409
22410   class InterruptThread : public v8::base::Thread {
22411    public:
22412     explicit InterruptThread(ThreadInterruptTest* test)
22413         : Thread(Options("InterruptThread")), test_(test) {}
22414
22415     virtual void Run() {
22416       struct sigaction action;
22417
22418       // Ensure that we'll enter waiting condition
22419       v8::base::OS::Sleep(100);
22420
22421       // Setup signal handler
22422       memset(&action, 0, sizeof(action));
22423       action.sa_handler = SignalHandler;
22424       sigaction(SIGCHLD, &action, NULL);
22425
22426       // Send signal
22427       kill(getpid(), SIGCHLD);
22428
22429       // Ensure that if wait has returned because of error
22430       v8::base::OS::Sleep(100);
22431
22432       // Set value and signal semaphore
22433       test_->sem_value_ = 1;
22434       test_->sem_.Signal();
22435     }
22436
22437     static void SignalHandler(int signal) {
22438     }
22439
22440    private:
22441      ThreadInterruptTest* test_;
22442   };
22443
22444   v8::base::Semaphore sem_;
22445   volatile int sem_value_;
22446 };
22447
22448
22449 THREADED_TEST(SemaphoreInterruption) {
22450   ThreadInterruptTest().RunTest();
22451 }
22452
22453
22454 #endif  // V8_OS_POSIX
22455
22456
22457 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
22458                                      Local<Value> name,
22459                                      v8::AccessType type,
22460                                      Local<Value> data) {
22461   i::PrintF("Named access blocked.\n");
22462   return false;
22463 }
22464
22465
22466 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
22467                                      uint32_t key,
22468                                      v8::AccessType type,
22469                                      Local<Value> data) {
22470   i::PrintF("Indexed access blocked.\n");
22471   return false;
22472 }
22473
22474
22475 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22476   CHECK(false);
22477 }
22478
22479
22480 TEST(JSONStringifyAccessCheck) {
22481   v8::V8::Initialize();
22482   v8::Isolate* isolate = CcTest::isolate();
22483   v8::HandleScope scope(isolate);
22484
22485   // Create an ObjectTemplate for global objects and install access
22486   // check callbacks that will block access.
22487   v8::Handle<v8::ObjectTemplate> global_template =
22488       v8::ObjectTemplate::New(isolate);
22489   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
22490                                            IndexAccessAlwaysBlocked);
22491
22492   // Create a context and set an x property on it's global object.
22493   LocalContext context0(NULL, global_template);
22494   v8::Handle<v8::Object> global0 = context0->Global();
22495   global0->Set(v8_str("x"), v8_num(42));
22496   ExpectString("JSON.stringify(this)", "{\"x\":42}");
22497
22498   for (int i = 0; i < 2; i++) {
22499     if (i == 1) {
22500       // Install a toJSON function on the second run.
22501       v8::Handle<v8::FunctionTemplate> toJSON =
22502           v8::FunctionTemplate::New(isolate, UnreachableCallback);
22503
22504       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
22505     }
22506     // Create a context with a different security token so that the
22507     // failed access check callback will be called on each access.
22508     LocalContext context1(NULL, global_template);
22509     context1->Global()->Set(v8_str("other"), global0);
22510
22511     CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
22512     CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
22513     CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
22514
22515     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
22516     array->Set(0, v8_str("a"));
22517     array->Set(1, v8_str("b"));
22518     context1->Global()->Set(v8_str("array"), array);
22519     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
22520     array->TurnOnAccessCheck();
22521     CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
22522     CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
22523     CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
22524   }
22525 }
22526
22527
22528 bool access_check_fail_thrown = false;
22529 bool catch_callback_called = false;
22530
22531
22532 // Failed access check callback that performs a GC on each invocation.
22533 void FailedAccessCheckThrows(Local<v8::Object> target,
22534                              v8::AccessType type,
22535                              Local<v8::Value> data) {
22536   access_check_fail_thrown = true;
22537   i::PrintF("Access check failed. Error thrown.\n");
22538   CcTest::isolate()->ThrowException(
22539       v8::Exception::Error(v8_str("cross context")));
22540 }
22541
22542
22543 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22544   for (int i = 0; i < args.Length(); i++) {
22545     i::PrintF("%s\n", *String::Utf8Value(args[i]));
22546   }
22547   catch_callback_called = true;
22548 }
22549
22550
22551 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22552   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
22553 }
22554
22555
22556 void CheckCorrectThrow(const char* script) {
22557   // Test that the script, when wrapped into a try-catch, triggers the catch
22558   // clause due to failed access check throwing an exception.
22559   // The subsequent try-catch should run without any exception.
22560   access_check_fail_thrown = false;
22561   catch_callback_called = false;
22562   i::ScopedVector<char> source(1024);
22563   i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
22564   CompileRun(source.start());
22565   CHECK(access_check_fail_thrown);
22566   CHECK(catch_callback_called);
22567
22568   access_check_fail_thrown = false;
22569   catch_callback_called = false;
22570   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
22571   CHECK(!access_check_fail_thrown);
22572   CHECK(!catch_callback_called);
22573 }
22574
22575
22576 TEST(AccessCheckThrows) {
22577   i::FLAG_allow_natives_syntax = true;
22578   v8::V8::Initialize();
22579   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
22580   v8::Isolate* isolate = CcTest::isolate();
22581   v8::HandleScope scope(isolate);
22582
22583   // Create an ObjectTemplate for global objects and install access
22584   // check callbacks that will block access.
22585   v8::Handle<v8::ObjectTemplate> global_template =
22586       v8::ObjectTemplate::New(isolate);
22587   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
22588                                            IndexAccessAlwaysBlocked);
22589
22590   // Create a context and set an x property on it's global object.
22591   LocalContext context0(NULL, global_template);
22592   v8::Handle<v8::Object> global0 = context0->Global();
22593
22594   // Create a context with a different security token so that the
22595   // failed access check callback will be called on each access.
22596   LocalContext context1(NULL, global_template);
22597   context1->Global()->Set(v8_str("other"), global0);
22598
22599   v8::Handle<v8::FunctionTemplate> catcher_fun =
22600       v8::FunctionTemplate::New(isolate, CatcherCallback);
22601   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
22602
22603   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
22604       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
22605   context1->Global()->Set(v8_str("has_own_property"),
22606                           has_own_property_fun->GetFunction());
22607
22608   { v8::TryCatch try_catch;
22609     access_check_fail_thrown = false;
22610     CompileRun("other.x;");
22611     CHECK(access_check_fail_thrown);
22612     CHECK(try_catch.HasCaught());
22613   }
22614
22615   CheckCorrectThrow("other.x");
22616   CheckCorrectThrow("other[1]");
22617   CheckCorrectThrow("JSON.stringify(other)");
22618   CheckCorrectThrow("has_own_property(other, 'x')");
22619   CheckCorrectThrow("%GetProperty(other, 'x')");
22620   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
22621   CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
22622   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
22623   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
22624   CheckCorrectThrow("%HasOwnProperty(other, 'x')");
22625   CheckCorrectThrow("%HasProperty(other, 'x')");
22626   CheckCorrectThrow("%HasElement(other, 1)");
22627   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
22628   CheckCorrectThrow("%GetPropertyNames(other)");
22629   // PROPERTY_ATTRIBUTES_NONE = 0
22630   CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
22631   CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
22632                         "other, 'x', null, null, 1)");
22633
22634   // Reset the failed access check callback so it does not influence
22635   // the other tests.
22636   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
22637 }
22638
22639
22640 THREADED_TEST(Regress256330) {
22641   i::FLAG_allow_natives_syntax = true;
22642   LocalContext context;
22643   v8::HandleScope scope(context->GetIsolate());
22644   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22645   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22646   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
22647   CompileRun("\"use strict\"; var o = new Bug;"
22648              "function f(o) { o.x = 10; };"
22649              "f(o); f(o); f(o);"
22650              "%OptimizeFunctionOnNextCall(f);"
22651              "f(o);");
22652   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
22653 }
22654
22655
22656 THREADED_TEST(CrankshaftInterceptorSetter) {
22657   i::FLAG_allow_natives_syntax = true;
22658   v8::HandleScope scope(CcTest::isolate());
22659   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22660   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22661   LocalContext env;
22662   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22663   CompileRun("var obj = new Obj;"
22664              // Initialize fields to avoid transitions later.
22665              "obj.age = 0;"
22666              "obj.accessor_age = 42;"
22667              "function setter(i) { this.accessor_age = i; };"
22668              "function getter() { return this.accessor_age; };"
22669              "function setAge(i) { obj.age = i; };"
22670              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
22671              "setAge(1);"
22672              "setAge(2);"
22673              "setAge(3);"
22674              "%OptimizeFunctionOnNextCall(setAge);"
22675              "setAge(4);");
22676   // All stores went through the interceptor.
22677   ExpectInt32("obj.interceptor_age", 4);
22678   ExpectInt32("obj.accessor_age", 42);
22679 }
22680
22681
22682 THREADED_TEST(CrankshaftInterceptorGetter) {
22683   i::FLAG_allow_natives_syntax = true;
22684   v8::HandleScope scope(CcTest::isolate());
22685   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22686   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22687   LocalContext env;
22688   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22689   CompileRun("var obj = new Obj;"
22690              // Initialize fields to avoid transitions later.
22691              "obj.age = 1;"
22692              "obj.accessor_age = 42;"
22693              "function getter() { return this.accessor_age; };"
22694              "function getAge() { return obj.interceptor_age; };"
22695              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
22696              "getAge();"
22697              "getAge();"
22698              "getAge();"
22699              "%OptimizeFunctionOnNextCall(getAge);");
22700   // Access through interceptor.
22701   ExpectInt32("getAge()", 1);
22702 }
22703
22704
22705 THREADED_TEST(CrankshaftInterceptorFieldRead) {
22706   i::FLAG_allow_natives_syntax = true;
22707   v8::HandleScope scope(CcTest::isolate());
22708   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22709   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22710   LocalContext env;
22711   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22712   CompileRun("var obj = new Obj;"
22713              "obj.__proto__.interceptor_age = 42;"
22714              "obj.age = 100;"
22715              "function getAge() { return obj.interceptor_age; };");
22716   ExpectInt32("getAge();", 100);
22717   ExpectInt32("getAge();", 100);
22718   ExpectInt32("getAge();", 100);
22719   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
22720   // Access through interceptor.
22721   ExpectInt32("getAge();", 100);
22722 }
22723
22724
22725 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
22726   i::FLAG_allow_natives_syntax = true;
22727   v8::HandleScope scope(CcTest::isolate());
22728   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22729   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22730   LocalContext env;
22731   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22732   CompileRun("var obj = new Obj;"
22733              "obj.age = 100000;"
22734              "function setAge(i) { obj.age = i };"
22735              "setAge(100);"
22736              "setAge(101);"
22737              "setAge(102);"
22738              "%OptimizeFunctionOnNextCall(setAge);"
22739              "setAge(103);");
22740   ExpectInt32("obj.age", 100000);
22741   ExpectInt32("obj.interceptor_age", 103);
22742 }
22743
22744
22745 class RequestInterruptTestBase {
22746  public:
22747   RequestInterruptTestBase()
22748       : env_(),
22749         isolate_(env_->GetIsolate()),
22750         sem_(0),
22751         warmup_(20000),
22752         should_continue_(true) {
22753   }
22754
22755   virtual ~RequestInterruptTestBase() { }
22756
22757   virtual void StartInterruptThread() = 0;
22758
22759   virtual void TestBody() = 0;
22760
22761   void RunTest() {
22762     StartInterruptThread();
22763
22764     v8::HandleScope handle_scope(isolate_);
22765
22766     TestBody();
22767
22768     isolate_->ClearInterrupt();
22769
22770     // Verify we arrived here because interruptor was called
22771     // not due to a bug causing us to exit the loop too early.
22772     CHECK(!should_continue());
22773   }
22774
22775   void WakeUpInterruptor() {
22776     sem_.Signal();
22777   }
22778
22779   bool should_continue() const { return should_continue_; }
22780
22781   bool ShouldContinue() {
22782     if (warmup_ > 0) {
22783       if (--warmup_ == 0) {
22784         WakeUpInterruptor();
22785       }
22786     }
22787
22788     return should_continue_;
22789   }
22790
22791   static void ShouldContinueCallback(
22792       const v8::FunctionCallbackInfo<Value>& info) {
22793     RequestInterruptTestBase* test =
22794         reinterpret_cast<RequestInterruptTestBase*>(
22795             info.Data().As<v8::External>()->Value());
22796     info.GetReturnValue().Set(test->ShouldContinue());
22797   }
22798
22799   LocalContext env_;
22800   v8::Isolate* isolate_;
22801   v8::base::Semaphore sem_;
22802   int warmup_;
22803   bool should_continue_;
22804 };
22805
22806
22807 class RequestInterruptTestBaseWithSimpleInterrupt
22808     : public RequestInterruptTestBase {
22809  public:
22810   RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
22811
22812   virtual void StartInterruptThread() {
22813     i_thread.Start();
22814   }
22815
22816  private:
22817   class InterruptThread : public v8::base::Thread {
22818    public:
22819     explicit InterruptThread(RequestInterruptTestBase* test)
22820         : Thread(Options("RequestInterruptTest")), test_(test) {}
22821
22822     virtual void Run() {
22823       test_->sem_.Wait();
22824       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22825     }
22826
22827     static void OnInterrupt(v8::Isolate* isolate, void* data) {
22828       reinterpret_cast<RequestInterruptTestBase*>(data)->
22829           should_continue_ = false;
22830     }
22831
22832    private:
22833      RequestInterruptTestBase* test_;
22834   };
22835
22836   InterruptThread i_thread;
22837 };
22838
22839
22840 class RequestInterruptTestWithFunctionCall
22841     : public RequestInterruptTestBaseWithSimpleInterrupt {
22842  public:
22843   virtual void TestBody() {
22844     Local<Function> func = Function::New(
22845         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22846     env_->Global()->Set(v8_str("ShouldContinue"), func);
22847
22848     CompileRun("while (ShouldContinue()) { }");
22849   }
22850 };
22851
22852
22853 class RequestInterruptTestWithMethodCall
22854     : public RequestInterruptTestBaseWithSimpleInterrupt {
22855  public:
22856   virtual void TestBody() {
22857     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22858     v8::Local<v8::Template> proto = t->PrototypeTemplate();
22859     proto->Set(v8_str("shouldContinue"), Function::New(
22860         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22861     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22862
22863     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22864   }
22865 };
22866
22867
22868 class RequestInterruptTestWithAccessor
22869     : public RequestInterruptTestBaseWithSimpleInterrupt {
22870  public:
22871   virtual void TestBody() {
22872     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22873     v8::Local<v8::Template> proto = t->PrototypeTemplate();
22874     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
22875         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22876     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22877
22878     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22879   }
22880 };
22881
22882
22883 class RequestInterruptTestWithNativeAccessor
22884     : public RequestInterruptTestBaseWithSimpleInterrupt {
22885  public:
22886   virtual void TestBody() {
22887     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22888     t->InstanceTemplate()->SetNativeDataProperty(
22889         v8_str("shouldContinue"),
22890         &ShouldContinueNativeGetter,
22891         NULL,
22892         v8::External::New(isolate_, this));
22893     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22894
22895     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22896   }
22897
22898  private:
22899   static void ShouldContinueNativeGetter(
22900       Local<String> property,
22901       const v8::PropertyCallbackInfo<v8::Value>& info) {
22902     RequestInterruptTestBase* test =
22903         reinterpret_cast<RequestInterruptTestBase*>(
22904             info.Data().As<v8::External>()->Value());
22905     info.GetReturnValue().Set(test->ShouldContinue());
22906   }
22907 };
22908
22909
22910 class RequestInterruptTestWithMethodCallAndInterceptor
22911     : public RequestInterruptTestBaseWithSimpleInterrupt {
22912  public:
22913   virtual void TestBody() {
22914     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22915     v8::Local<v8::Template> proto = t->PrototypeTemplate();
22916     proto->Set(v8_str("shouldContinue"), Function::New(
22917         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22918     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
22919     instance_template->SetNamedPropertyHandler(EmptyInterceptor);
22920
22921     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22922
22923     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22924   }
22925
22926  private:
22927   static void EmptyInterceptor(
22928       Local<String> property,
22929       const v8::PropertyCallbackInfo<v8::Value>& info) {
22930   }
22931 };
22932
22933
22934 class RequestInterruptTestWithMathAbs
22935     : public RequestInterruptTestBaseWithSimpleInterrupt {
22936  public:
22937   virtual void TestBody() {
22938     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
22939         isolate_,
22940         WakeUpInterruptorCallback,
22941         v8::External::New(isolate_, this)));
22942
22943     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
22944         isolate_,
22945         ShouldContinueCallback,
22946         v8::External::New(isolate_, this)));
22947
22948     i::FLAG_allow_natives_syntax = true;
22949     CompileRun("function loopish(o) {"
22950                "  var pre = 10;"
22951                "  while (o.abs(1) > 0) {"
22952                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
22953                "    if (pre > 0) {"
22954                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
22955                "    }"
22956                "  }"
22957                "}"
22958                "var i = 50;"
22959                "var obj = {abs: function () { return i-- }, x: null};"
22960                "delete obj.x;"
22961                "loopish(obj);"
22962                "%OptimizeFunctionOnNextCall(loopish);"
22963                "loopish(Math);");
22964
22965     i::FLAG_allow_natives_syntax = false;
22966   }
22967
22968  private:
22969   static void WakeUpInterruptorCallback(
22970       const v8::FunctionCallbackInfo<Value>& info) {
22971     if (!info[0]->BooleanValue()) return;
22972
22973     RequestInterruptTestBase* test =
22974         reinterpret_cast<RequestInterruptTestBase*>(
22975             info.Data().As<v8::External>()->Value());
22976     test->WakeUpInterruptor();
22977   }
22978
22979   static void ShouldContinueCallback(
22980       const v8::FunctionCallbackInfo<Value>& info) {
22981     RequestInterruptTestBase* test =
22982         reinterpret_cast<RequestInterruptTestBase*>(
22983             info.Data().As<v8::External>()->Value());
22984     info.GetReturnValue().Set(test->should_continue());
22985   }
22986 };
22987
22988
22989 TEST(RequestInterruptTestWithFunctionCall) {
22990   RequestInterruptTestWithFunctionCall().RunTest();
22991 }
22992
22993
22994 TEST(RequestInterruptTestWithMethodCall) {
22995   RequestInterruptTestWithMethodCall().RunTest();
22996 }
22997
22998
22999 TEST(RequestInterruptTestWithAccessor) {
23000   RequestInterruptTestWithAccessor().RunTest();
23001 }
23002
23003
23004 TEST(RequestInterruptTestWithNativeAccessor) {
23005   RequestInterruptTestWithNativeAccessor().RunTest();
23006 }
23007
23008
23009 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
23010   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
23011 }
23012
23013
23014 TEST(RequestInterruptTestWithMathAbs) {
23015   RequestInterruptTestWithMathAbs().RunTest();
23016 }
23017
23018
23019 class ClearInterruptFromAnotherThread
23020     : public RequestInterruptTestBase {
23021  public:
23022   ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
23023
23024   virtual void StartInterruptThread() {
23025     i_thread.Start();
23026   }
23027
23028   virtual void TestBody() {
23029     Local<Function> func = Function::New(
23030         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
23031     env_->Global()->Set(v8_str("ShouldContinue"), func);
23032
23033     CompileRun("while (ShouldContinue()) { }");
23034   }
23035
23036  private:
23037   class InterruptThread : public v8::base::Thread {
23038    public:
23039     explicit InterruptThread(ClearInterruptFromAnotherThread* test)
23040         : Thread(Options("RequestInterruptTest")), test_(test) {}
23041
23042     virtual void Run() {
23043       test_->sem_.Wait();
23044       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23045       test_->sem_.Wait();
23046       test_->isolate_->ClearInterrupt();
23047       test_->sem2_.Signal();
23048     }
23049
23050     static void OnInterrupt(v8::Isolate* isolate, void* data) {
23051       ClearInterruptFromAnotherThread* test =
23052           reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
23053       test->sem_.Signal();
23054       bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2));
23055       // Crash instead of timeout to make this failure more prominent.
23056       CHECK(success);
23057       test->should_continue_ = false;
23058     }
23059
23060    private:
23061      ClearInterruptFromAnotherThread* test_;
23062   };
23063
23064   InterruptThread i_thread;
23065   v8::base::Semaphore sem2_;
23066 };
23067
23068
23069 TEST(ClearInterruptFromAnotherThread) {
23070   ClearInterruptFromAnotherThread().RunTest();
23071 }
23072
23073
23074 static Local<Value> function_new_expected_env;
23075 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
23076   CHECK_EQ(function_new_expected_env, info.Data());
23077   info.GetReturnValue().Set(17);
23078 }
23079
23080
23081 THREADED_TEST(FunctionNew) {
23082   LocalContext env;
23083   v8::Isolate* isolate = env->GetIsolate();
23084   v8::HandleScope scope(isolate);
23085   Local<Object> data = v8::Object::New(isolate);
23086   function_new_expected_env = data;
23087   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
23088   env->Global()->Set(v8_str("func"), func);
23089   Local<Value> result = CompileRun("func();");
23090   CHECK_EQ(v8::Integer::New(isolate, 17), result);
23091   // Verify function not cached
23092   int serial_number =
23093       i::Smi::cast(v8::Utils::OpenHandle(*func)
23094           ->shared()->get_api_func_data()->serial_number())->value();
23095   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
23096   i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
23097   i::Handle<i::Object> elm =
23098       i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
23099   CHECK(elm->IsUndefined());
23100   // Verify that each Function::New creates a new function instance
23101   Local<Object> data2 = v8::Object::New(isolate);
23102   function_new_expected_env = data2;
23103   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
23104   CHECK(!func2->IsNull());
23105   CHECK_NE(func, func2);
23106   env->Global()->Set(v8_str("func2"), func2);
23107   Local<Value> result2 = CompileRun("func2();");
23108   CHECK_EQ(v8::Integer::New(isolate, 17), result2);
23109 }
23110
23111
23112 TEST(EscapeableHandleScope) {
23113   HandleScope outer_scope(CcTest::isolate());
23114   LocalContext context;
23115   const int runs = 10;
23116   Local<String> values[runs];
23117   for (int i = 0; i < runs; i++) {
23118     v8::EscapableHandleScope inner_scope(CcTest::isolate());
23119     Local<String> value;
23120     if (i != 0) value = v8_str("escape value");
23121     values[i] = inner_scope.Escape(value);
23122   }
23123   for (int i = 0; i < runs; i++) {
23124     Local<String> expected;
23125     if (i != 0) {
23126       CHECK_EQ(v8_str("escape value"), values[i]);
23127     } else {
23128       CHECK(values[i].IsEmpty());
23129     }
23130   }
23131 }
23132
23133
23134 static void SetterWhichExpectsThisAndHolderToDiffer(
23135     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
23136   CHECK(info.Holder() != info.This());
23137 }
23138
23139
23140 TEST(Regress239669) {
23141   LocalContext context;
23142   v8::Isolate* isolate = context->GetIsolate();
23143   v8::HandleScope scope(isolate);
23144   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23145   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
23146   context->Global()->Set(v8_str("P"), templ->NewInstance());
23147   CompileRun(
23148       "function C1() {"
23149       "  this.x = 23;"
23150       "};"
23151       "C1.prototype = P;"
23152       "for (var i = 0; i < 4; i++ ) {"
23153       "  new C1();"
23154       "}");
23155 }
23156
23157
23158 class ApiCallOptimizationChecker {
23159  private:
23160   static Local<Object> data;
23161   static Local<Object> receiver;
23162   static Local<Object> holder;
23163   static Local<Object> callee;
23164   static int count;
23165
23166   static void OptimizationCallback(
23167       const v8::FunctionCallbackInfo<v8::Value>& info) {
23168     CHECK(callee == info.Callee());
23169     CHECK(data == info.Data());
23170     CHECK(receiver == info.This());
23171     if (info.Length() == 1) {
23172       CHECK_EQ(v8_num(1), info[0]);
23173     }
23174     CHECK(holder == info.Holder());
23175     count++;
23176     info.GetReturnValue().Set(v8_str("returned"));
23177   }
23178
23179  public:
23180   enum SignatureType {
23181     kNoSignature,
23182     kSignatureOnReceiver,
23183     kSignatureOnPrototype
23184   };
23185
23186   void RunAll() {
23187     SignatureType signature_types[] =
23188       {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
23189     for (unsigned i = 0; i < arraysize(signature_types); i++) {
23190       SignatureType signature_type = signature_types[i];
23191       for (int j = 0; j < 2; j++) {
23192         bool global = j == 0;
23193         int key = signature_type +
23194             arraysize(signature_types) * (global ? 1 : 0);
23195         Run(signature_type, global, key);
23196       }
23197     }
23198   }
23199
23200   void Run(SignatureType signature_type, bool global, int key) {
23201     v8::Isolate* isolate = CcTest::isolate();
23202     v8::HandleScope scope(isolate);
23203     // Build a template for signature checks.
23204     Local<v8::ObjectTemplate> signature_template;
23205     Local<v8::Signature> signature;
23206     {
23207       Local<v8::FunctionTemplate> parent_template =
23208         FunctionTemplate::New(isolate);
23209       parent_template->SetHiddenPrototype(true);
23210       Local<v8::FunctionTemplate> function_template
23211           = FunctionTemplate::New(isolate);
23212       function_template->Inherit(parent_template);
23213       switch (signature_type) {
23214         case kNoSignature:
23215           break;
23216         case kSignatureOnReceiver:
23217           signature = v8::Signature::New(isolate, function_template);
23218           break;
23219         case kSignatureOnPrototype:
23220           signature = v8::Signature::New(isolate, parent_template);
23221           break;
23222       }
23223       signature_template = function_template->InstanceTemplate();
23224     }
23225     // Global object must pass checks.
23226     Local<v8::Context> context =
23227         v8::Context::New(isolate, NULL, signature_template);
23228     v8::Context::Scope context_scope(context);
23229     // Install regular object that can pass signature checks.
23230     Local<Object> function_receiver = signature_template->NewInstance();
23231     context->Global()->Set(v8_str("function_receiver"), function_receiver);
23232     // Get the holder objects.
23233     Local<Object> inner_global =
23234         Local<Object>::Cast(context->Global()->GetPrototype());
23235     // Install functions on hidden prototype object if there is one.
23236     data = Object::New(isolate);
23237     Local<FunctionTemplate> function_template = FunctionTemplate::New(
23238         isolate, OptimizationCallback, data, signature);
23239     Local<Function> function = function_template->GetFunction();
23240     Local<Object> global_holder = inner_global;
23241     Local<Object> function_holder = function_receiver;
23242     if (signature_type == kSignatureOnPrototype) {
23243       function_holder = Local<Object>::Cast(function_holder->GetPrototype());
23244       global_holder = Local<Object>::Cast(global_holder->GetPrototype());
23245     }
23246     global_holder->Set(v8_str("g_f"), function);
23247     global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
23248     function_holder->Set(v8_str("f"), function);
23249     function_holder->SetAccessorProperty(v8_str("acc"), function, function);
23250     // Initialize expected values.
23251     callee = function;
23252     count = 0;
23253     if (global) {
23254       receiver = context->Global();
23255       holder = inner_global;
23256     } else {
23257       holder = function_receiver;
23258       // If not using a signature, add something else to the prototype chain
23259       // to test the case that holder != receiver
23260       if (signature_type == kNoSignature) {
23261         receiver = Local<Object>::Cast(CompileRun(
23262             "var receiver_subclass = {};\n"
23263             "receiver_subclass.__proto__ = function_receiver;\n"
23264             "receiver_subclass"));
23265       } else {
23266         receiver = Local<Object>::Cast(CompileRun(
23267           "var receiver_subclass = function_receiver;\n"
23268           "receiver_subclass"));
23269       }
23270     }
23271     // With no signature, the holder is not set.
23272     if (signature_type == kNoSignature) holder = receiver;
23273     // build wrap_function
23274     i::ScopedVector<char> wrap_function(200);
23275     if (global) {
23276       i::SNPrintF(
23277           wrap_function,
23278           "function wrap_f_%d() { var f = g_f; return f(); }\n"
23279           "function wrap_get_%d() { return this.g_acc; }\n"
23280           "function wrap_set_%d() { return this.g_acc = 1; }\n",
23281           key, key, key);
23282     } else {
23283       i::SNPrintF(
23284           wrap_function,
23285           "function wrap_f_%d() { return receiver_subclass.f(); }\n"
23286           "function wrap_get_%d() { return receiver_subclass.acc; }\n"
23287           "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
23288           key, key, key);
23289     }
23290     // build source string
23291     i::ScopedVector<char> source(1000);
23292     i::SNPrintF(
23293         source,
23294         "%s\n"  // wrap functions
23295         "function wrap_f() { return wrap_f_%d(); }\n"
23296         "function wrap_get() { return wrap_get_%d(); }\n"
23297         "function wrap_set() { return wrap_set_%d(); }\n"
23298         "check = function(returned) {\n"
23299         "  if (returned !== 'returned') { throw returned; }\n"
23300         "}\n"
23301         "\n"
23302         "check(wrap_f());\n"
23303         "check(wrap_f());\n"
23304         "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
23305         "check(wrap_f());\n"
23306         "\n"
23307         "check(wrap_get());\n"
23308         "check(wrap_get());\n"
23309         "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
23310         "check(wrap_get());\n"
23311         "\n"
23312         "check = function(returned) {\n"
23313         "  if (returned !== 1) { throw returned; }\n"
23314         "}\n"
23315         "check(wrap_set());\n"
23316         "check(wrap_set());\n"
23317         "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
23318         "check(wrap_set());\n",
23319         wrap_function.start(), key, key, key, key, key, key);
23320     v8::TryCatch try_catch;
23321     CompileRun(source.start());
23322     DCHECK(!try_catch.HasCaught());
23323     CHECK_EQ(9, count);
23324   }
23325 };
23326
23327
23328 Local<Object> ApiCallOptimizationChecker::data;
23329 Local<Object> ApiCallOptimizationChecker::receiver;
23330 Local<Object> ApiCallOptimizationChecker::holder;
23331 Local<Object> ApiCallOptimizationChecker::callee;
23332 int ApiCallOptimizationChecker::count = 0;
23333
23334
23335 TEST(TestFunctionCallOptimization) {
23336   i::FLAG_allow_natives_syntax = true;
23337   ApiCallOptimizationChecker checker;
23338   checker.RunAll();
23339 }
23340
23341
23342 static const char* last_event_message;
23343 static int last_event_status;
23344 void StoringEventLoggerCallback(const char* message, int status) {
23345     last_event_message = message;
23346     last_event_status = status;
23347 }
23348
23349
23350 TEST(EventLogging) {
23351   v8::Isolate* isolate = CcTest::isolate();
23352   isolate->SetEventLogger(StoringEventLoggerCallback);
23353   v8::internal::HistogramTimer histogramTimer(
23354       "V8.Test", 0, 10000, 50,
23355       reinterpret_cast<v8::internal::Isolate*>(isolate));
23356   histogramTimer.Start();
23357   CHECK_EQ("V8.Test", last_event_message);
23358   CHECK_EQ(0, last_event_status);
23359   histogramTimer.Stop();
23360   CHECK_EQ("V8.Test", last_event_message);
23361   CHECK_EQ(1, last_event_status);
23362 }
23363
23364
23365 TEST(Promises) {
23366   LocalContext context;
23367   v8::Isolate* isolate = context->GetIsolate();
23368   v8::HandleScope scope(isolate);
23369   Handle<Object> global = context->Global();
23370
23371   // Creation.
23372   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
23373   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
23374   Handle<v8::Promise> p = pr->GetPromise();
23375   Handle<v8::Promise> r = rr->GetPromise();
23376   CHECK_EQ(isolate, p->GetIsolate());
23377
23378   // IsPromise predicate.
23379   CHECK(p->IsPromise());
23380   CHECK(r->IsPromise());
23381   Handle<Value> o = v8::Object::New(isolate);
23382   CHECK(!o->IsPromise());
23383
23384   // Resolution and rejection.
23385   pr->Resolve(v8::Integer::New(isolate, 1));
23386   CHECK(p->IsPromise());
23387   rr->Reject(v8::Integer::New(isolate, 2));
23388   CHECK(r->IsPromise());
23389
23390   // Chaining non-pending promises.
23391   CompileRun(
23392       "var x1 = 0;\n"
23393       "var x2 = 0;\n"
23394       "function f1(x) { x1 = x; return x+1 };\n"
23395       "function f2(x) { x2 = x; return x+1 };\n");
23396   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
23397   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
23398
23399   p->Chain(f1);
23400   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23401   isolate->RunMicrotasks();
23402   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23403
23404   p->Catch(f2);
23405   isolate->RunMicrotasks();
23406   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23407
23408   r->Catch(f2);
23409   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23410   isolate->RunMicrotasks();
23411   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
23412
23413   r->Chain(f1);
23414   isolate->RunMicrotasks();
23415   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23416
23417   // Chaining pending promises.
23418   CompileRun("x1 = x2 = 0;");
23419   pr = v8::Promise::Resolver::New(isolate);
23420   rr = v8::Promise::Resolver::New(isolate);
23421
23422   pr->GetPromise()->Chain(f1);
23423   rr->GetPromise()->Catch(f2);
23424   isolate->RunMicrotasks();
23425   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23426   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23427
23428   pr->Resolve(v8::Integer::New(isolate, 1));
23429   rr->Reject(v8::Integer::New(isolate, 2));
23430   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23431   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23432
23433   isolate->RunMicrotasks();
23434   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23435   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
23436
23437   // Multi-chaining.
23438   CompileRun("x1 = x2 = 0;");
23439   pr = v8::Promise::Resolver::New(isolate);
23440   pr->GetPromise()->Chain(f1)->Chain(f2);
23441   pr->Resolve(v8::Integer::New(isolate, 3));
23442   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23443   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23444   isolate->RunMicrotasks();
23445   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23446   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23447
23448   CompileRun("x1 = x2 = 0;");
23449   rr = v8::Promise::Resolver::New(isolate);
23450   rr->GetPromise()->Catch(f1)->Chain(f2);
23451   rr->Reject(v8::Integer::New(isolate, 3));
23452   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23453   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23454   isolate->RunMicrotasks();
23455   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23456   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23457 }
23458
23459
23460 TEST(PromiseThen) {
23461   LocalContext context;
23462   v8::Isolate* isolate = context->GetIsolate();
23463   v8::HandleScope scope(isolate);
23464   Handle<Object> global = context->Global();
23465
23466   // Creation.
23467   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
23468   Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
23469   Handle<v8::Promise> p = pr->GetPromise();
23470   Handle<v8::Promise> q = qr->GetPromise();
23471
23472   CHECK(p->IsPromise());
23473   CHECK(q->IsPromise());
23474
23475   pr->Resolve(v8::Integer::New(isolate, 1));
23476   qr->Resolve(p);
23477
23478   // Chaining non-pending promises.
23479   CompileRun(
23480       "var x1 = 0;\n"
23481       "var x2 = 0;\n"
23482       "function f1(x) { x1 = x; return x+1 };\n"
23483       "function f2(x) { x2 = x; return x+1 };\n");
23484   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
23485   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
23486
23487   // Chain
23488   q->Chain(f1);
23489   CHECK(global->Get(v8_str("x1"))->IsNumber());
23490   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23491   isolate->RunMicrotasks();
23492   CHECK(!global->Get(v8_str("x1"))->IsNumber());
23493   CHECK_EQ(p, global->Get(v8_str("x1")));
23494
23495   // Then
23496   CompileRun("x1 = x2 = 0;");
23497   q->Then(f1);
23498   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23499   isolate->RunMicrotasks();
23500   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23501
23502   // Then
23503   CompileRun("x1 = x2 = 0;");
23504   pr = v8::Promise::Resolver::New(isolate);
23505   qr = v8::Promise::Resolver::New(isolate);
23506
23507   qr->Resolve(pr);
23508   qr->GetPromise()->Then(f1)->Then(f2);
23509
23510   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23511   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23512   isolate->RunMicrotasks();
23513   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23514   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23515
23516   pr->Resolve(v8::Integer::New(isolate, 3));
23517
23518   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23519   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23520   isolate->RunMicrotasks();
23521   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23522   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23523 }
23524
23525
23526 TEST(DisallowJavascriptExecutionScope) {
23527   LocalContext context;
23528   v8::Isolate* isolate = context->GetIsolate();
23529   v8::HandleScope scope(isolate);
23530   v8::Isolate::DisallowJavascriptExecutionScope no_js(
23531       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23532   CompileRun("2+2");
23533 }
23534
23535
23536 TEST(AllowJavascriptExecutionScope) {
23537   LocalContext context;
23538   v8::Isolate* isolate = context->GetIsolate();
23539   v8::HandleScope scope(isolate);
23540   v8::Isolate::DisallowJavascriptExecutionScope no_js(
23541       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23542   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23543       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23544   { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
23545     CompileRun("1+1");
23546   }
23547 }
23548
23549
23550 TEST(ThrowOnJavascriptExecution) {
23551   LocalContext context;
23552   v8::Isolate* isolate = context->GetIsolate();
23553   v8::HandleScope scope(isolate);
23554   v8::TryCatch try_catch;
23555   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23556       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23557   CompileRun("1+1");
23558   CHECK(try_catch.HasCaught());
23559 }
23560
23561
23562 TEST(Regress354123) {
23563   LocalContext current;
23564   v8::Isolate* isolate = current->GetIsolate();
23565   v8::HandleScope scope(isolate);
23566
23567   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
23568   templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
23569   current->Global()->Set(v8_str("friend"), templ->NewInstance());
23570
23571   // Test access using __proto__ from the prototype chain.
23572   named_access_count = 0;
23573   CompileRun("friend.__proto__ = {};");
23574   CHECK_EQ(2, named_access_count);
23575   CompileRun("friend.__proto__;");
23576   CHECK_EQ(4, named_access_count);
23577
23578   // Test access using __proto__ as a hijacked function (A).
23579   named_access_count = 0;
23580   CompileRun("var p = Object.prototype;"
23581              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
23582              "f.call(friend, {});");
23583   CHECK_EQ(1, named_access_count);
23584   CompileRun("var p = Object.prototype;"
23585              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
23586              "f.call(friend);");
23587   CHECK_EQ(2, named_access_count);
23588
23589   // Test access using __proto__ as a hijacked function (B).
23590   named_access_count = 0;
23591   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
23592              "f.call(friend, {});");
23593   CHECK_EQ(1, named_access_count);
23594   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
23595              "f.call(friend);");
23596   CHECK_EQ(2, named_access_count);
23597
23598   // Test access using Object.setPrototypeOf reflective method.
23599   named_access_count = 0;
23600   CompileRun("Object.setPrototypeOf(friend, {});");
23601   CHECK_EQ(1, named_access_count);
23602   CompileRun("Object.getPrototypeOf(friend);");
23603   CHECK_EQ(2, named_access_count);
23604 }
23605
23606
23607 TEST(CaptureStackTraceForStackOverflow) {
23608   v8::internal::FLAG_stack_size = 150;
23609   LocalContext current;
23610   v8::Isolate* isolate = current->GetIsolate();
23611   v8::HandleScope scope(isolate);
23612   V8::SetCaptureStackTraceForUncaughtExceptions(
23613       true, 10, v8::StackTrace::kDetailed);
23614   v8::TryCatch try_catch;
23615   CompileRun("(function f(x) { f(x+1); })(0)");
23616   CHECK(try_catch.HasCaught());
23617 }
23618
23619
23620 TEST(ScriptNameAndLineNumber) {
23621   LocalContext env;
23622   v8::Isolate* isolate = env->GetIsolate();
23623   v8::HandleScope scope(isolate);
23624   const char* url = "http://www.foo.com/foo.js";
23625   v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
23626   v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
23627   Local<Script> script = v8::ScriptCompiler::Compile(
23628       isolate, &script_source);
23629   Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
23630   CHECK(!script_name.IsEmpty());
23631   CHECK(script_name->IsString());
23632   String::Utf8Value utf8_name(script_name);
23633   CHECK_EQ(url, *utf8_name);
23634   int line_number = script->GetUnboundScript()->GetLineNumber(0);
23635   CHECK_EQ(13, line_number);
23636 }
23637
23638
23639 void SourceURLHelper(const char* source, const char* expected_source_url,
23640                      const char* expected_source_mapping_url) {
23641   Local<Script> script = v8_compile(source);
23642   if (expected_source_url != NULL) {
23643     v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
23644     CHECK_EQ(expected_source_url, *url);
23645   } else {
23646     CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
23647   }
23648   if (expected_source_mapping_url != NULL) {
23649     v8::String::Utf8Value url(
23650         script->GetUnboundScript()->GetSourceMappingURL());
23651     CHECK_EQ(expected_source_mapping_url, *url);
23652   } else {
23653     CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
23654   }
23655 }
23656
23657
23658 TEST(ScriptSourceURLAndSourceMappingURL) {
23659   LocalContext env;
23660   v8::Isolate* isolate = env->GetIsolate();
23661   v8::HandleScope scope(isolate);
23662   SourceURLHelper("function foo() {}\n"
23663                   "//# sourceURL=bar1.js\n", "bar1.js", NULL);
23664   SourceURLHelper("function foo() {}\n"
23665                   "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
23666
23667   // Both sourceURL and sourceMappingURL.
23668   SourceURLHelper("function foo() {}\n"
23669                   "//# sourceURL=bar3.js\n"
23670                   "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
23671
23672   // Two source URLs; the first one is ignored.
23673   SourceURLHelper("function foo() {}\n"
23674                   "//# sourceURL=ignoreme.js\n"
23675                   "//# sourceURL=bar5.js\n", "bar5.js", NULL);
23676   SourceURLHelper("function foo() {}\n"
23677                   "//# sourceMappingURL=ignoreme.js\n"
23678                   "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
23679
23680   // SourceURL or sourceMappingURL in the middle of the script.
23681   SourceURLHelper("function foo() {}\n"
23682                   "//# sourceURL=bar7.js\n"
23683                   "function baz() {}\n", "bar7.js", NULL);
23684   SourceURLHelper("function foo() {}\n"
23685                   "//# sourceMappingURL=bar8.js\n"
23686                   "function baz() {}\n", NULL, "bar8.js");
23687
23688   // Too much whitespace.
23689   SourceURLHelper("function foo() {}\n"
23690                   "//#  sourceURL=bar9.js\n"
23691                   "//#  sourceMappingURL=bar10.js\n", NULL, NULL);
23692   SourceURLHelper("function foo() {}\n"
23693                   "//# sourceURL =bar11.js\n"
23694                   "//# sourceMappingURL =bar12.js\n", NULL, NULL);
23695
23696   // Disallowed characters in value.
23697   SourceURLHelper("function foo() {}\n"
23698                   "//# sourceURL=bar13 .js   \n"
23699                   "//# sourceMappingURL=bar14 .js \n",
23700                   NULL, NULL);
23701   SourceURLHelper("function foo() {}\n"
23702                   "//# sourceURL=bar15\t.js   \n"
23703                   "//# sourceMappingURL=bar16\t.js \n",
23704                   NULL, NULL);
23705   SourceURLHelper("function foo() {}\n"
23706                   "//# sourceURL=bar17'.js   \n"
23707                   "//# sourceMappingURL=bar18'.js \n",
23708                   NULL, NULL);
23709   SourceURLHelper("function foo() {}\n"
23710                   "//# sourceURL=bar19\".js   \n"
23711                   "//# sourceMappingURL=bar20\".js \n",
23712                   NULL, NULL);
23713
23714   // Not too much whitespace.
23715   SourceURLHelper("function foo() {}\n"
23716                   "//# sourceURL=  bar21.js   \n"
23717                   "//# sourceMappingURL=  bar22.js \n", "bar21.js", "bar22.js");
23718 }
23719
23720
23721 TEST(GetOwnPropertyDescriptor) {
23722   LocalContext env;
23723   v8::Isolate* isolate = env->GetIsolate();
23724   v8::HandleScope scope(isolate);
23725   CompileRun(
23726     "var x = { value : 13};"
23727     "Object.defineProperty(x, 'p0', {value : 12});"
23728     "Object.defineProperty(x, 'p1', {"
23729     "  set : function(value) { this.value = value; },"
23730     "  get : function() { return this.value; },"
23731     "});");
23732   Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
23733   Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
23734   CHECK(desc->IsUndefined());
23735   desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
23736   CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value")));
23737   desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
23738   Local<Function> set =
23739     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
23740   Local<Function> get =
23741     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
23742   CHECK_EQ(v8_num(13), get->Call(x, 0, NULL));
23743   Handle<Value> args[] = { v8_num(14) };
23744   set->Call(x, 1, args);
23745   CHECK_EQ(v8_num(14), get->Call(x, 0, NULL));
23746 }
23747
23748
23749 TEST(Regress411877) {
23750   v8::Isolate* isolate = CcTest::isolate();
23751   v8::HandleScope handle_scope(isolate);
23752   v8::Handle<v8::ObjectTemplate> object_template =
23753       v8::ObjectTemplate::New(isolate);
23754   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23755                                            IndexedAccessCounter);
23756
23757   v8::Handle<Context> context = Context::New(isolate);
23758   v8::Context::Scope context_scope(context);
23759
23760   context->Global()->Set(v8_str("o"), object_template->NewInstance());
23761   CompileRun("Object.getOwnPropertyNames(o)");
23762 }
23763
23764
23765 TEST(GetHiddenPropertyTableAfterAccessCheck) {
23766   v8::Isolate* isolate = CcTest::isolate();
23767   v8::HandleScope handle_scope(isolate);
23768   v8::Handle<v8::ObjectTemplate> object_template =
23769       v8::ObjectTemplate::New(isolate);
23770   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23771                                            IndexedAccessCounter);
23772
23773   v8::Handle<Context> context = Context::New(isolate);
23774   v8::Context::Scope context_scope(context);
23775
23776   v8::Handle<v8::Object> obj = object_template->NewInstance();
23777   obj->Set(v8_str("key"), v8_str("value"));
23778   obj->Delete(v8_str("key"));
23779
23780   obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
23781 }
23782
23783
23784 TEST(Regress411793) {
23785   v8::Isolate* isolate = CcTest::isolate();
23786   v8::HandleScope handle_scope(isolate);
23787   v8::Handle<v8::ObjectTemplate> object_template =
23788       v8::ObjectTemplate::New(isolate);
23789   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23790                                            IndexedAccessCounter);
23791
23792   v8::Handle<Context> context = Context::New(isolate);
23793   v8::Context::Scope context_scope(context);
23794
23795   context->Global()->Set(v8_str("o"), object_template->NewInstance());
23796   CompileRun(
23797       "Object.defineProperty(o, 'key', "
23798       "    { get: function() {}, set: function() {} });");
23799 }
23800
23801 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
23802  public:
23803   explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
23804
23805   virtual size_t GetMoreData(const uint8_t** src) {
23806     // Unlike in real use cases, this function will never block.
23807     if (chunks_[index_] == NULL) {
23808       return 0;
23809     }
23810     // Copy the data, since the caller takes ownership of it.
23811     size_t len = strlen(chunks_[index_]);
23812     // We don't need to zero-terminate since we return the length.
23813     uint8_t* copy = new uint8_t[len];
23814     memcpy(copy, chunks_[index_], len);
23815     *src = copy;
23816     ++index_;
23817     return len;
23818   }
23819
23820   // Helper for constructing a string from chunks (the compilation needs it
23821   // too).
23822   static char* FullSourceString(const char** chunks) {
23823     size_t total_len = 0;
23824     for (size_t i = 0; chunks[i] != NULL; ++i) {
23825       total_len += strlen(chunks[i]);
23826     }
23827     char* full_string = new char[total_len + 1];
23828     size_t offset = 0;
23829     for (size_t i = 0; chunks[i] != NULL; ++i) {
23830       size_t len = strlen(chunks[i]);
23831       memcpy(full_string + offset, chunks[i], len);
23832       offset += len;
23833     }
23834     full_string[total_len] = 0;
23835     return full_string;
23836   }
23837
23838  private:
23839   const char** chunks_;
23840   unsigned index_;
23841 };
23842
23843
23844 // Helper function for running streaming tests.
23845 void RunStreamingTest(const char** chunks,
23846                       v8::ScriptCompiler::StreamedSource::Encoding encoding =
23847                           v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23848                       bool expected_success = true) {
23849   LocalContext env;
23850   v8::Isolate* isolate = env->GetIsolate();
23851   v8::HandleScope scope(isolate);
23852   v8::TryCatch try_catch;
23853
23854   v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
23855                                             encoding);
23856   v8::ScriptCompiler::ScriptStreamingTask* task =
23857       v8::ScriptCompiler::StartStreamingScript(isolate, &source);
23858
23859   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
23860   // task here in the main thread.
23861   task->Run();
23862   delete task;
23863
23864   v8::ScriptOrigin origin(v8_str("http://foo.com"));
23865   char* full_source = TestSourceStream::FullSourceString(chunks);
23866
23867   // The possible errors are only produced while compiling.
23868   CHECK_EQ(false, try_catch.HasCaught());
23869
23870   v8::Handle<Script> script = v8::ScriptCompiler::Compile(
23871       isolate, &source, v8_str(full_source), origin);
23872   if (expected_success) {
23873     CHECK(!script.IsEmpty());
23874     v8::Handle<Value> result(script->Run());
23875     // All scripts are supposed to return the fixed value 13 when ran.
23876     CHECK_EQ(13, result->Int32Value());
23877   } else {
23878     CHECK(script.IsEmpty());
23879     CHECK(try_catch.HasCaught());
23880   }
23881   delete[] full_source;
23882 }
23883
23884
23885 TEST(StreamingSimpleScript) {
23886   // This script is unrealistically small, since no one chunk is enough to fill
23887   // the backing buffer of Scanner, let alone overflow it.
23888   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
23889                           NULL};
23890   RunStreamingTest(chunks);
23891 }
23892
23893
23894 TEST(StreamingBiggerScript) {
23895   const char* chunk1 =
23896       "function foo() {\n"
23897       "  // Make this chunk sufficiently long so that it will overflow the\n"
23898       "  // backing buffer of the Scanner.\n"
23899       "  var i = 0;\n"
23900       "  var result = 0;\n"
23901       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23902       "  result = 0;\n"
23903       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23904       "  result = 0;\n"
23905       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23906       "  result = 0;\n"
23907       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23908       "  return result;\n"
23909       "}\n";
23910   const char* chunks[] = {chunk1, "foo(); ", NULL};
23911   RunStreamingTest(chunks);
23912 }
23913
23914
23915 TEST(StreamingScriptWithParseError) {
23916   // Test that parse errors from streamed scripts are propagated correctly.
23917   {
23918     char chunk1[] =
23919         "  // This will result in a parse error.\n"
23920         "  var if else then foo";
23921     char chunk2[] = "  13\n";
23922     const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23923
23924     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23925                      false);
23926   }
23927   // Test that the next script succeeds normally.
23928   {
23929     char chunk1[] =
23930         "  // This will be parsed successfully.\n"
23931         "  function foo() { return ";
23932     char chunk2[] = "  13; }\n";
23933     const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23934
23935     RunStreamingTest(chunks);
23936   }
23937 }
23938
23939
23940 TEST(StreamingUtf8Script) {
23941   // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
23942   // don't like it.
23943   const char* chunk1 =
23944       "function foo() {\n"
23945       "  // This function will contain an UTF-8 character which is not in\n"
23946       "  // ASCII.\n"
23947       "  var foob\xec\x92\x81r = 13;\n"
23948       "  return foob\xec\x92\x81r;\n"
23949       "}\n";
23950   const char* chunks[] = {chunk1, "foo(); ", NULL};
23951   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23952 }
23953
23954
23955 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
23956   // A sanity check to prove that the approach of splitting UTF-8
23957   // characters is correct. Here is an UTF-8 character which will take three
23958   // bytes.
23959   const char* reference = "\xec\x92\x81";
23960   CHECK(3u == strlen(reference));  // NOLINT - no CHECK_EQ for unsigned.
23961
23962   char chunk1[] =
23963       "function foo() {\n"
23964       "  // This function will contain an UTF-8 character which is not in\n"
23965       "  // ASCII.\n"
23966       "  var foob";
23967   char chunk2[] =
23968       "XXXr = 13;\n"
23969       "  return foob\xec\x92\x81r;\n"
23970       "}\n";
23971   for (int i = 0; i < 3; ++i) {
23972     chunk2[i] = reference[i];
23973   }
23974   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23975   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23976 }
23977
23978
23979 TEST(StreamingUtf8ScriptWithSplitCharacters) {
23980   // Stream data where a multi-byte UTF-8 character is split between two data
23981   // chunks.
23982   const char* reference = "\xec\x92\x81";
23983   char chunk1[] =
23984       "function foo() {\n"
23985       "  // This function will contain an UTF-8 character which is not in\n"
23986       "  // ASCII.\n"
23987       "  var foobX";
23988   char chunk2[] =
23989       "XXr = 13;\n"
23990       "  return foob\xec\x92\x81r;\n"
23991       "}\n";
23992   chunk1[strlen(chunk1) - 1] = reference[0];
23993   chunk2[0] = reference[1];
23994   chunk2[1] = reference[2];
23995   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23996   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23997 }
23998
23999
24000 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
24001   // Tests edge cases which should still be decoded correctly.
24002
24003   // Case 1: a chunk contains only bytes for a split character (and no other
24004   // data). This kind of a chunk would be exceptionally small, but we should
24005   // still decode it correctly.
24006   const char* reference = "\xec\x92\x81";
24007   // The small chunk is at the beginning of the split character
24008   {
24009     char chunk1[] =
24010         "function foo() {\n"
24011         "  // This function will contain an UTF-8 character which is not in\n"
24012         "  // ASCII.\n"
24013         "  var foob";
24014     char chunk2[] = "XX";
24015     char chunk3[] =
24016         "Xr = 13;\n"
24017         "  return foob\xec\x92\x81r;\n"
24018         "}\n";
24019     chunk2[0] = reference[0];
24020     chunk2[1] = reference[1];
24021     chunk3[0] = reference[2];
24022     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24023     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24024   }
24025   // The small chunk is at the end of a character
24026   {
24027     char chunk1[] =
24028         "function foo() {\n"
24029         "  // This function will contain an UTF-8 character which is not in\n"
24030         "  // ASCII.\n"
24031         "  var foobX";
24032     char chunk2[] = "XX";
24033     char chunk3[] =
24034         "r = 13;\n"
24035         "  return foob\xec\x92\x81r;\n"
24036         "}\n";
24037     chunk1[strlen(chunk1) - 1] = reference[0];
24038     chunk2[0] = reference[1];
24039     chunk2[1] = reference[2];
24040     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24041     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24042   }
24043   // Case 2: the script ends with a multi-byte character. Make sure that it's
24044   // decoded correctly and not just ignored.
24045   {
24046     char chunk1[] =
24047         "var foob\xec\x92\x81 = 13;\n"
24048         "foob\xec\x92\x81";
24049     const char* chunks[] = {chunk1, NULL};
24050     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24051   }
24052 }
24053
24054
24055 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
24056   // Test cases where a UTF-8 character is split over several chunks. Those
24057   // cases are not supported (the embedder should give the data in big enough
24058   // chunks), but we shouldn't crash, just produce a parse error.
24059   const char* reference = "\xec\x92\x81";
24060   char chunk1[] =
24061       "function foo() {\n"
24062       "  // This function will contain an UTF-8 character which is not in\n"
24063       "  // ASCII.\n"
24064       "  var foobX";
24065   char chunk2[] = "X";
24066   char chunk3[] =
24067       "Xr = 13;\n"
24068       "  return foob\xec\x92\x81r;\n"
24069       "}\n";
24070   chunk1[strlen(chunk1) - 1] = reference[0];
24071   chunk2[0] = reference[1];
24072   chunk3[0] = reference[2];
24073   const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24074
24075   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24076 }
24077
24078
24079 TEST(StreamingProducesParserCache) {
24080   i::FLAG_min_preparse_length = 0;
24081   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24082                           NULL};
24083
24084   LocalContext env;
24085   v8::Isolate* isolate = env->GetIsolate();
24086   v8::HandleScope scope(isolate);
24087
24088   v8::ScriptCompiler::StreamedSource source(
24089       new TestSourceStream(chunks),
24090       v8::ScriptCompiler::StreamedSource::ONE_BYTE);
24091   v8::ScriptCompiler::ScriptStreamingTask* task =
24092       v8::ScriptCompiler::StartStreamingScript(
24093           isolate, &source, v8::ScriptCompiler::kProduceParserCache);
24094
24095   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24096   // task here in the main thread.
24097   task->Run();
24098   delete task;
24099
24100   const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
24101   CHECK(cached_data != NULL);
24102   CHECK(cached_data->data != NULL);
24103   CHECK_GT(cached_data->length, 0);
24104 }
24105
24106
24107 TEST(StreamingScriptWithInvalidUtf8) {
24108   // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
24109   // chunk don't produce a crash.
24110   const char* reference = "\xec\x92\x81\x80\x80";
24111   char chunk1[] =
24112       "function foo() {\n"
24113       "  // This function will contain an UTF-8 character which is not in\n"
24114       "  // ASCII.\n"
24115       "  var foobXXXXX";  // Too many bytes which look like incomplete chars!
24116   char chunk2[] =
24117       "r = 13;\n"
24118       "  return foob\xec\x92\x81\x80\x80r;\n"
24119       "}\n";
24120   for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
24121
24122   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24123   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24124 }
24125
24126
24127 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
24128   // Regression test: Stream data where there are several multi-byte UTF-8
24129   // characters in a sequence and one of them is split between two data chunks.
24130   const char* reference = "\xec\x92\x81";
24131   char chunk1[] =
24132       "function foo() {\n"
24133       "  // This function will contain an UTF-8 character which is not in\n"
24134       "  // ASCII.\n"
24135       "  var foob\xec\x92\x81X";
24136   char chunk2[] =
24137       "XXr = 13;\n"
24138       "  return foob\xec\x92\x81\xec\x92\x81r;\n"
24139       "}\n";
24140   chunk1[strlen(chunk1) - 1] = reference[0];
24141   chunk2[0] = reference[1];
24142   chunk2[1] = reference[2];
24143   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24144   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24145 }
24146
24147
24148 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
24149   // Another regression test, similar to the previous one. The difference is
24150   // that the split character is not the last one in the sequence.
24151   const char* reference = "\xec\x92\x81";
24152   char chunk1[] =
24153       "function foo() {\n"
24154       "  // This function will contain an UTF-8 character which is not in\n"
24155       "  // ASCII.\n"
24156       "  var foobX";
24157   char chunk2[] =
24158       "XX\xec\x92\x81r = 13;\n"
24159       "  return foob\xec\x92\x81\xec\x92\x81r;\n"
24160       "}\n";
24161   chunk1[strlen(chunk1) - 1] = reference[0];
24162   chunk2[0] = reference[1];
24163   chunk2[1] = reference[2];
24164   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24165   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24166 }