Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-api.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <climits>
29 #include <csignal>
30 #include <string>
31 #include <map>
32
33 #include "v8.h"
34
35 #if V8_OS_POSIX
36 #include <unistd.h>  // NOLINT
37 #endif
38
39 #include "api.h"
40 #include "arguments.h"
41 #include "cctest.h"
42 #include "compilation-cache.h"
43 #include "cpu-profiler.h"
44 #include "execution.h"
45 #include "isolate.h"
46 #include "objects.h"
47 #include "parser.h"
48 #include "platform.h"
49 #include "snapshot.h"
50 #include "unicode-inl.h"
51 #include "utils.h"
52 #include "vm-state.h"
53 #include "../include/v8-util.h"
54
55 static const bool kLogThreading = false;
56
57 using ::v8::Boolean;
58 using ::v8::BooleanObject;
59 using ::v8::Context;
60 using ::v8::Extension;
61 using ::v8::Function;
62 using ::v8::FunctionTemplate;
63 using ::v8::Handle;
64 using ::v8::HandleScope;
65 using ::v8::Local;
66 using ::v8::Message;
67 using ::v8::MessageCallback;
68 using ::v8::Object;
69 using ::v8::ObjectTemplate;
70 using ::v8::Persistent;
71 using ::v8::Script;
72 using ::v8::StackTrace;
73 using ::v8::String;
74 using ::v8::TryCatch;
75 using ::v8::Undefined;
76 using ::v8::UniqueId;
77 using ::v8::V8;
78 using ::v8::Value;
79
80
81 #define THREADED_PROFILED_TEST(Name)                                 \
82   static void Test##Name();                                          \
83   TEST(Name##WithProfiler) {                                         \
84     RunWithProfiler(&Test##Name);                                    \
85   }                                                                  \
86   THREADED_TEST(Name)
87
88
89 void RunWithProfiler(void (*test)()) {
90   LocalContext env;
91   v8::HandleScope scope(env->GetIsolate());
92   v8::Local<v8::String> profile_name =
93       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
94   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
95
96   cpu_profiler->StartCpuProfiling(profile_name);
97   (*test)();
98   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
99 }
100
101
102 static void ExpectString(const char* code, const char* expected) {
103   Local<Value> result = CompileRun(code);
104   CHECK(result->IsString());
105   String::Utf8Value utf8(result);
106   CHECK_EQ(expected, *utf8);
107 }
108
109
110 static void ExpectInt32(const char* code, int expected) {
111   Local<Value> result = CompileRun(code);
112   CHECK(result->IsInt32());
113   CHECK_EQ(expected, result->Int32Value());
114 }
115
116
117 static void ExpectBoolean(const char* code, bool expected) {
118   Local<Value> result = CompileRun(code);
119   CHECK(result->IsBoolean());
120   CHECK_EQ(expected, result->BooleanValue());
121 }
122
123
124 static void ExpectTrue(const char* code) {
125   ExpectBoolean(code, true);
126 }
127
128
129 static void ExpectFalse(const char* code) {
130   ExpectBoolean(code, false);
131 }
132
133
134 static void ExpectObject(const char* code, Local<Value> expected) {
135   Local<Value> result = CompileRun(code);
136   CHECK(result->Equals(expected));
137 }
138
139
140 static void ExpectUndefined(const char* code) {
141   Local<Value> result = CompileRun(code);
142   CHECK(result->IsUndefined());
143 }
144
145
146 static int signature_callback_count;
147 static Local<Value> signature_expected_receiver;
148 static void IncrementingSignatureCallback(
149     const v8::FunctionCallbackInfo<v8::Value>& args) {
150   ApiTestFuzzer::Fuzz();
151   signature_callback_count++;
152   CHECK_EQ(signature_expected_receiver, args.Holder());
153   CHECK_EQ(signature_expected_receiver, args.This());
154   v8::Handle<v8::Array> result =
155       v8::Array::New(args.GetIsolate(), args.Length());
156   for (int i = 0; i < args.Length(); i++)
157     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
158   args.GetReturnValue().Set(result);
159 }
160
161
162 static void SignatureCallback(
163     const v8::FunctionCallbackInfo<v8::Value>& args) {
164   ApiTestFuzzer::Fuzz();
165   v8::Handle<v8::Array> result =
166       v8::Array::New(args.GetIsolate(), args.Length());
167   for (int i = 0; i < args.Length(); i++) {
168     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
169   }
170   args.GetReturnValue().Set(result);
171 }
172
173
174 // Tests that call v8::V8::Dispose() cannot be threaded.
175 TEST(InitializeAndDisposeOnce) {
176   CHECK(v8::V8::Initialize());
177   CHECK(v8::V8::Dispose());
178 }
179
180
181 // Tests that call v8::V8::Dispose() cannot be threaded.
182 TEST(InitializeAndDisposeMultiple) {
183   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
184   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
185   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
186   // TODO(mstarzinger): This should fail gracefully instead of asserting.
187   // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
188   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
189 }
190
191
192 THREADED_TEST(Handles) {
193   v8::HandleScope scope(CcTest::isolate());
194   Local<Context> local_env;
195   {
196     LocalContext env;
197     local_env = env.local();
198   }
199
200   // Local context should still be live.
201   CHECK(!local_env.IsEmpty());
202   local_env->Enter();
203
204   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
205   CHECK(!undef.IsEmpty());
206   CHECK(undef->IsUndefined());
207
208   const char* source = "1 + 2 + 3";
209   Local<Script> script = v8_compile(source);
210   CHECK_EQ(6, script->Run()->Int32Value());
211
212   local_env->Exit();
213 }
214
215
216 THREADED_TEST(IsolateOfContext) {
217   v8::HandleScope scope(CcTest::isolate());
218   v8::Handle<Context> env = Context::New(CcTest::isolate());
219
220   CHECK(!env->GetIsolate()->InContext());
221   CHECK(env->GetIsolate() == CcTest::isolate());
222   env->Enter();
223   CHECK(env->GetIsolate()->InContext());
224   CHECK(env->GetIsolate() == CcTest::isolate());
225   env->Exit();
226   CHECK(!env->GetIsolate()->InContext());
227   CHECK(env->GetIsolate() == CcTest::isolate());
228 }
229
230
231 static void TestSignature(const char* loop_js, Local<Value> receiver) {
232   i::ScopedVector<char> source(200);
233   i::OS::SNPrintF(source,
234                   "for (var i = 0; i < 10; i++) {"
235                   "  %s"
236                   "}",
237                   loop_js);
238   signature_callback_count = 0;
239   signature_expected_receiver = receiver;
240   bool expected_to_throw = receiver.IsEmpty();
241   v8::TryCatch try_catch;
242   CompileRun(source.start());
243   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
244   if (!expected_to_throw) {
245     CHECK_EQ(10, signature_callback_count);
246   } else {
247     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
248              try_catch.Exception()->ToString());
249   }
250 }
251
252
253 THREADED_TEST(ReceiverSignature) {
254   LocalContext env;
255   v8::Isolate* isolate = env->GetIsolate();
256   v8::HandleScope scope(isolate);
257   // Setup templates.
258   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
259   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
260   v8::Handle<v8::FunctionTemplate> callback_sig =
261       v8::FunctionTemplate::New(
262           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
263   v8::Handle<v8::FunctionTemplate> callback =
264       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
265   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
266   sub_fun->Inherit(fun);
267   v8::Handle<v8::FunctionTemplate> unrel_fun =
268       v8::FunctionTemplate::New(isolate);
269   // Install properties.
270   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
271   fun_proto->Set(v8_str("prop_sig"), callback_sig);
272   fun_proto->Set(v8_str("prop"), callback);
273   fun_proto->SetAccessorProperty(
274       v8_str("accessor_sig"), callback_sig, callback_sig);
275   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
276   // Instantiate templates.
277   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
278   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
279   // Setup global variables.
280   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
281   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
282   env->Global()->Set(v8_str("fun_instance"), fun_instance);
283   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
284   CompileRun(
285       "var accessor_sig_key = 'accessor_sig';"
286       "var accessor_key = 'accessor';"
287       "var prop_sig_key = 'prop_sig';"
288       "var prop_key = 'prop';"
289       ""
290       "function copy_props(obj) {"
291       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
292       "  var source = Fun.prototype;"
293       "  for (var i in keys) {"
294       "    var key = keys[i];"
295       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
296       "    Object.defineProperty(obj, key, desc);"
297       "  }"
298       "}"
299       ""
300       "var obj = {};"
301       "copy_props(obj);"
302       "var unrel = new UnrelFun();"
303       "copy_props(unrel);");
304   // Test with and without ICs
305   const char* test_objects[] = {
306       "fun_instance", "sub_fun_instance", "obj", "unrel" };
307   unsigned bad_signature_start_offset = 2;
308   for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
309     i::ScopedVector<char> source(200);
310     i::OS::SNPrintF(
311         source, "var test_object = %s; test_object", test_objects[i]);
312     Local<Value> test_object = CompileRun(source.start());
313     TestSignature("test_object.prop();", test_object);
314     TestSignature("test_object.accessor;", test_object);
315     TestSignature("test_object[accessor_key];", test_object);
316     TestSignature("test_object.accessor = 1;", test_object);
317     TestSignature("test_object[accessor_key] = 1;", test_object);
318     if (i >= bad_signature_start_offset) test_object = Local<Value>();
319     TestSignature("test_object.prop_sig();", test_object);
320     TestSignature("test_object.accessor_sig;", test_object);
321     TestSignature("test_object[accessor_sig_key];", test_object);
322     TestSignature("test_object.accessor_sig = 1;", test_object);
323     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
324   }
325 }
326
327
328 THREADED_TEST(ArgumentSignature) {
329   LocalContext env;
330   v8::Isolate* isolate = env->GetIsolate();
331   v8::HandleScope scope(isolate);
332   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
333   cons->SetClassName(v8_str("Cons"));
334   v8::Handle<v8::Signature> sig = v8::Signature::New(
335       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
336   v8::Handle<v8::FunctionTemplate> fun =
337       v8::FunctionTemplate::New(isolate,
338                                 SignatureCallback,
339                                 v8::Handle<Value>(),
340                                 sig);
341   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
342   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
343
344   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
345   CHECK(value1->IsTrue());
346
347   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
348   CHECK(value2->IsTrue());
349
350   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
351   CHECK(value3->IsTrue());
352
353   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
354   cons1->SetClassName(v8_str("Cons1"));
355   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
356   cons2->SetClassName(v8_str("Cons2"));
357   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
358   cons3->SetClassName(v8_str("Cons3"));
359
360   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
361   v8::Handle<v8::Signature> wsig = v8::Signature::New(
362       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
363   v8::Handle<v8::FunctionTemplate> fun2 =
364       v8::FunctionTemplate::New(isolate,
365                                 SignatureCallback,
366                                 v8::Handle<Value>(),
367                                 wsig);
368
369   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
370   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
371   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
372   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
373   v8::Handle<Value> value4 = CompileRun(
374       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
375       "'[object Cons1],[object Cons2],[object Cons3]'");
376   CHECK(value4->IsTrue());
377
378   v8::Handle<Value> value5 = CompileRun(
379       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
380   CHECK(value5->IsTrue());
381
382   v8::Handle<Value> value6 = CompileRun(
383       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
384   CHECK(value6->IsTrue());
385
386   v8::Handle<Value> value7 = CompileRun(
387       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
388       "'[object Cons1],[object Cons2],[object Cons3],d';");
389   CHECK(value7->IsTrue());
390
391   v8::Handle<Value> value8 = CompileRun(
392       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
393   CHECK(value8->IsTrue());
394 }
395
396
397 THREADED_TEST(HulIgennem) {
398   LocalContext env;
399   v8::Isolate* isolate = env->GetIsolate();
400   v8::HandleScope scope(isolate);
401   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
402   Local<String> undef_str = undef->ToString();
403   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
404   undef_str->WriteUtf8(value);
405   CHECK_EQ(0, strcmp(value, "undefined"));
406   i::DeleteArray(value);
407 }
408
409
410 THREADED_TEST(Access) {
411   LocalContext env;
412   v8::Isolate* isolate = env->GetIsolate();
413   v8::HandleScope scope(isolate);
414   Local<v8::Object> obj = v8::Object::New(isolate);
415   Local<Value> foo_before = obj->Get(v8_str("foo"));
416   CHECK(foo_before->IsUndefined());
417   Local<String> bar_str = v8_str("bar");
418   obj->Set(v8_str("foo"), bar_str);
419   Local<Value> foo_after = obj->Get(v8_str("foo"));
420   CHECK(!foo_after->IsUndefined());
421   CHECK(foo_after->IsString());
422   CHECK_EQ(bar_str, foo_after);
423 }
424
425
426 THREADED_TEST(AccessElement) {
427   LocalContext env;
428   v8::HandleScope scope(env->GetIsolate());
429   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
430   Local<Value> before = obj->Get(1);
431   CHECK(before->IsUndefined());
432   Local<String> bar_str = v8_str("bar");
433   obj->Set(1, bar_str);
434   Local<Value> after = obj->Get(1);
435   CHECK(!after->IsUndefined());
436   CHECK(after->IsString());
437   CHECK_EQ(bar_str, after);
438
439   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
440   CHECK_EQ(v8_str("a"), value->Get(0));
441   CHECK_EQ(v8_str("b"), value->Get(1));
442 }
443
444
445 THREADED_TEST(Script) {
446   LocalContext env;
447   v8::HandleScope scope(env->GetIsolate());
448   const char* source = "1 + 2 + 3";
449   Local<Script> script = v8_compile(source);
450   CHECK_EQ(6, script->Run()->Int32Value());
451 }
452
453
454 static uint16_t* AsciiToTwoByteString(const char* source) {
455   int array_length = i::StrLength(source) + 1;
456   uint16_t* converted = i::NewArray<uint16_t>(array_length);
457   for (int i = 0; i < array_length; i++) converted[i] = source[i];
458   return converted;
459 }
460
461
462 class TestResource: public String::ExternalStringResource {
463  public:
464   TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true)
465       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
466     while (data[length_]) ++length_;
467   }
468
469   ~TestResource() {
470     if (owning_data_) i::DeleteArray(data_);
471     if (counter_ != NULL) ++*counter_;
472   }
473
474   const uint16_t* data() const {
475     return data_;
476   }
477
478   size_t length() const {
479     return length_;
480   }
481
482  private:
483   uint16_t* data_;
484   size_t length_;
485   int* counter_;
486   bool owning_data_;
487 };
488
489
490 class TestAsciiResource: public String::ExternalAsciiStringResource {
491  public:
492   TestAsciiResource(const char* data, int* counter = NULL, size_t offset = 0)
493       : orig_data_(data),
494         data_(data + offset),
495         length_(strlen(data) - offset),
496         counter_(counter) { }
497
498   ~TestAsciiResource() {
499     i::DeleteArray(orig_data_);
500     if (counter_ != NULL) ++*counter_;
501   }
502
503   const char* data() const {
504     return data_;
505   }
506
507   size_t length() const {
508     return length_;
509   }
510
511  private:
512   const char* orig_data_;
513   const char* data_;
514   size_t length_;
515   int* counter_;
516 };
517
518
519 THREADED_TEST(ScriptUsingStringResource) {
520   int dispose_count = 0;
521   const char* c_source = "1 + 2 * 3";
522   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
523   {
524     LocalContext env;
525     v8::HandleScope scope(env->GetIsolate());
526     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
527     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
528     Local<Script> script = v8_compile(source);
529     Local<Value> value = script->Run();
530     CHECK(value->IsNumber());
531     CHECK_EQ(7, value->Int32Value());
532     CHECK(source->IsExternal());
533     CHECK_EQ(resource,
534              static_cast<TestResource*>(source->GetExternalStringResource()));
535     String::Encoding encoding = String::UNKNOWN_ENCODING;
536     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
537              source->GetExternalStringResourceBase(&encoding));
538     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
539     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
540     CHECK_EQ(0, dispose_count);
541   }
542   CcTest::i_isolate()->compilation_cache()->Clear();
543   CcTest::heap()->CollectAllAvailableGarbage();
544   CHECK_EQ(1, dispose_count);
545 }
546
547
548 THREADED_TEST(ScriptUsingAsciiStringResource) {
549   int dispose_count = 0;
550   const char* c_source = "1 + 2 * 3";
551   {
552     LocalContext env;
553     v8::HandleScope scope(env->GetIsolate());
554     TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
555                                                         &dispose_count);
556     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
557     CHECK(source->IsExternalAscii());
558     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
559              source->GetExternalAsciiStringResource());
560     String::Encoding encoding = String::UNKNOWN_ENCODING;
561     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
562              source->GetExternalStringResourceBase(&encoding));
563     CHECK_EQ(String::ASCII_ENCODING, encoding);
564     Local<Script> script = v8_compile(source);
565     Local<Value> value = script->Run();
566     CHECK(value->IsNumber());
567     CHECK_EQ(7, value->Int32Value());
568     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
569     CHECK_EQ(0, dispose_count);
570   }
571   CcTest::i_isolate()->compilation_cache()->Clear();
572   CcTest::heap()->CollectAllAvailableGarbage();
573   CHECK_EQ(1, dispose_count);
574 }
575
576
577 THREADED_TEST(ScriptMakingExternalString) {
578   int dispose_count = 0;
579   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
580   {
581     LocalContext env;
582     v8::HandleScope scope(env->GetIsolate());
583     Local<String> source =
584         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
585     // Trigger GCs so that the newly allocated string moves to old gen.
586     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
587     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
588     CHECK_EQ(source->IsExternal(), false);
589     CHECK_EQ(source->IsExternalAscii(), false);
590     String::Encoding encoding = String::UNKNOWN_ENCODING;
591     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
592     CHECK_EQ(String::ASCII_ENCODING, encoding);
593     bool success = source->MakeExternal(new TestResource(two_byte_source,
594                                                          &dispose_count));
595     CHECK(success);
596     Local<Script> script = v8_compile(source);
597     Local<Value> value = script->Run();
598     CHECK(value->IsNumber());
599     CHECK_EQ(7, value->Int32Value());
600     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
601     CHECK_EQ(0, dispose_count);
602   }
603   CcTest::i_isolate()->compilation_cache()->Clear();
604   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
605   CHECK_EQ(1, dispose_count);
606 }
607
608
609 THREADED_TEST(ScriptMakingExternalAsciiString) {
610   int dispose_count = 0;
611   const char* c_source = "1 + 2 * 3";
612   {
613     LocalContext env;
614     v8::HandleScope scope(env->GetIsolate());
615     Local<String> source = v8_str(c_source);
616     // Trigger GCs so that the newly allocated string moves to old gen.
617     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
618     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
619     bool success = source->MakeExternal(
620         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
621     CHECK(success);
622     Local<Script> script = v8_compile(source);
623     Local<Value> value = script->Run();
624     CHECK(value->IsNumber());
625     CHECK_EQ(7, value->Int32Value());
626     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
627     CHECK_EQ(0, dispose_count);
628   }
629   CcTest::i_isolate()->compilation_cache()->Clear();
630   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
631   CHECK_EQ(1, dispose_count);
632 }
633
634
635 TEST(MakingExternalStringConditions) {
636   LocalContext env;
637   v8::HandleScope scope(env->GetIsolate());
638
639   // Free some space in the new space so that we can check freshness.
640   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
642
643   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
644   Local<String> small_string =
645       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
646   i::DeleteArray(two_byte_string);
647
648   // We should refuse to externalize newly created small string.
649   CHECK(!small_string->CanMakeExternal());
650   // Trigger GCs so that the newly allocated string moves to old gen.
651   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
652   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
653   // Old space strings should be accepted.
654   CHECK(small_string->CanMakeExternal());
655
656   two_byte_string = AsciiToTwoByteString("small string 2");
657   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
658   i::DeleteArray(two_byte_string);
659
660   // We should refuse externalizing newly created small string.
661   CHECK(!small_string->CanMakeExternal());
662   for (int i = 0; i < 100; i++) {
663     String::Value value(small_string);
664   }
665   // Frequently used strings should be accepted.
666   CHECK(small_string->CanMakeExternal());
667
668   const int buf_size = 10 * 1024;
669   char* buf = i::NewArray<char>(buf_size);
670   memset(buf, 'a', buf_size);
671   buf[buf_size - 1] = '\0';
672
673   two_byte_string = AsciiToTwoByteString(buf);
674   Local<String> large_string =
675       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
676   i::DeleteArray(buf);
677   i::DeleteArray(two_byte_string);
678   // Large strings should be immediately accepted.
679   CHECK(large_string->CanMakeExternal());
680 }
681
682
683 TEST(MakingExternalAsciiStringConditions) {
684   LocalContext env;
685   v8::HandleScope scope(env->GetIsolate());
686
687   // Free some space in the new space so that we can check freshness.
688   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
689   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
690
691   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
692   // We should refuse to externalize newly created small string.
693   CHECK(!small_string->CanMakeExternal());
694   // Trigger GCs so that the newly allocated string moves to old gen.
695   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
696   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
697   // Old space strings should be accepted.
698   CHECK(small_string->CanMakeExternal());
699
700   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
701   // We should refuse externalizing newly created small string.
702   CHECK(!small_string->CanMakeExternal());
703   for (int i = 0; i < 100; i++) {
704     String::Value value(small_string);
705   }
706   // Frequently used strings should be accepted.
707   CHECK(small_string->CanMakeExternal());
708
709   const int buf_size = 10 * 1024;
710   char* buf = i::NewArray<char>(buf_size);
711   memset(buf, 'a', buf_size);
712   buf[buf_size - 1] = '\0';
713   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
714   i::DeleteArray(buf);
715   // Large strings should be immediately accepted.
716   CHECK(large_string->CanMakeExternal());
717 }
718
719
720 TEST(MakingExternalUnalignedAsciiString) {
721   LocalContext env;
722   v8::HandleScope scope(env->GetIsolate());
723
724   CompileRun("function cons(a, b) { return a + b; }"
725              "function slice(a) { return a.substring(1); }");
726   // Create a cons string that will land in old pointer space.
727   Local<String> cons = Local<String>::Cast(CompileRun(
728       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
729   // Create a sliced string that will land in old pointer space.
730   Local<String> slice = Local<String>::Cast(CompileRun(
731       "slice('abcdefghijklmnopqrstuvwxyz');"));
732
733   // Trigger GCs so that the newly allocated string moves to old gen.
734   SimulateFullSpace(CcTest::heap()->old_pointer_space());
735   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
736   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
737
738   // Turn into external string with unaligned resource data.
739   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
740   bool success = cons->MakeExternal(
741       new TestAsciiResource(i::StrDup(c_cons), NULL, 1));
742   CHECK(success);
743   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
744   success = slice->MakeExternal(
745       new TestAsciiResource(i::StrDup(c_slice), NULL, 1));
746   CHECK(success);
747
748   // Trigger GCs and force evacuation.
749   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
750   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
751 }
752
753
754 THREADED_TEST(UsingExternalString) {
755   i::Factory* factory = CcTest::i_isolate()->factory();
756   {
757     v8::HandleScope scope(CcTest::isolate());
758     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
759     Local<String> string = String::NewExternal(
760         CcTest::isolate(), new TestResource(two_byte_string));
761     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
762     // Trigger GCs so that the newly allocated string moves to old gen.
763     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
764     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
765     i::Handle<i::String> isymbol =
766         factory->InternalizeString(istring);
767     CHECK(isymbol->IsInternalizedString());
768   }
769   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
770   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
771 }
772
773
774 THREADED_TEST(UsingExternalAsciiString) {
775   i::Factory* factory = CcTest::i_isolate()->factory();
776   {
777     v8::HandleScope scope(CcTest::isolate());
778     const char* one_byte_string = "test string";
779     Local<String> string = String::NewExternal(
780         CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
781     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
782     // Trigger GCs so that the newly allocated string moves to old gen.
783     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
784     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
785     i::Handle<i::String> isymbol =
786         factory->InternalizeString(istring);
787     CHECK(isymbol->IsInternalizedString());
788   }
789   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
790   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
791 }
792
793
794 THREADED_TEST(ScavengeExternalString) {
795   i::FLAG_stress_compaction = false;
796   i::FLAG_gc_global = false;
797   int dispose_count = 0;
798   bool in_new_space = false;
799   {
800     v8::HandleScope scope(CcTest::isolate());
801     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
802     Local<String> string = String::NewExternal(
803         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
804     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
805     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
806     in_new_space = CcTest::heap()->InNewSpace(*istring);
807     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
808     CHECK_EQ(0, dispose_count);
809   }
810   CcTest::heap()->CollectGarbage(
811       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
812   CHECK_EQ(1, dispose_count);
813 }
814
815
816 THREADED_TEST(ScavengeExternalAsciiString) {
817   i::FLAG_stress_compaction = false;
818   i::FLAG_gc_global = false;
819   int dispose_count = 0;
820   bool in_new_space = false;
821   {
822     v8::HandleScope scope(CcTest::isolate());
823     const char* one_byte_string = "test string";
824     Local<String> string = String::NewExternal(
825         CcTest::isolate(),
826         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
827     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
828     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
829     in_new_space = CcTest::heap()->InNewSpace(*istring);
830     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
831     CHECK_EQ(0, dispose_count);
832   }
833   CcTest::heap()->CollectGarbage(
834       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
835   CHECK_EQ(1, dispose_count);
836 }
837
838
839 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
840  public:
841   // Only used by non-threaded tests, so it can use static fields.
842   static int dispose_calls;
843   static int dispose_count;
844
845   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
846       : TestAsciiResource(data, &dispose_count),
847         dispose_(dispose) { }
848
849   void Dispose() {
850     ++dispose_calls;
851     if (dispose_) delete this;
852   }
853  private:
854   bool dispose_;
855 };
856
857
858 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
859 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
860
861
862 TEST(ExternalStringWithDisposeHandling) {
863   const char* c_source = "1 + 2 * 3";
864
865   // Use a stack allocated external string resource allocated object.
866   TestAsciiResourceWithDisposeControl::dispose_count = 0;
867   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
868   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
869   {
870     LocalContext env;
871     v8::HandleScope scope(env->GetIsolate());
872     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
873     Local<Script> script = v8_compile(source);
874     Local<Value> value = script->Run();
875     CHECK(value->IsNumber());
876     CHECK_EQ(7, value->Int32Value());
877     CcTest::heap()->CollectAllAvailableGarbage();
878     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
879   }
880   CcTest::i_isolate()->compilation_cache()->Clear();
881   CcTest::heap()->CollectAllAvailableGarbage();
882   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
883   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
884
885   // Use a heap allocated external string resource allocated object.
886   TestAsciiResourceWithDisposeControl::dispose_count = 0;
887   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
888   TestAsciiResource* res_heap =
889       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
890   {
891     LocalContext env;
892     v8::HandleScope scope(env->GetIsolate());
893     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
894     Local<Script> script = v8_compile(source);
895     Local<Value> value = script->Run();
896     CHECK(value->IsNumber());
897     CHECK_EQ(7, value->Int32Value());
898     CcTest::heap()->CollectAllAvailableGarbage();
899     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
900   }
901   CcTest::i_isolate()->compilation_cache()->Clear();
902   CcTest::heap()->CollectAllAvailableGarbage();
903   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
904   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
905 }
906
907
908 THREADED_TEST(StringConcat) {
909   {
910     LocalContext env;
911     v8::HandleScope scope(env->GetIsolate());
912     const char* one_byte_string_1 = "function a_times_t";
913     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
914     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
915     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
916     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
917     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
918     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
919     Local<String> left = v8_str(one_byte_string_1);
920
921     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
922     Local<String> right =
923         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
924     i::DeleteArray(two_byte_source);
925
926     Local<String> source = String::Concat(left, right);
927     right = String::NewExternal(
928         env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
929     source = String::Concat(source, right);
930     right = String::NewExternal(
931         env->GetIsolate(),
932         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
933     source = String::Concat(source, right);
934     right = v8_str(one_byte_string_2);
935     source = String::Concat(source, right);
936
937     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
938     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
939     i::DeleteArray(two_byte_source);
940
941     source = String::Concat(source, right);
942     right = String::NewExternal(
943         env->GetIsolate(),
944         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
945     source = String::Concat(source, right);
946     Local<Script> script = v8_compile(source);
947     Local<Value> value = script->Run();
948     CHECK(value->IsNumber());
949     CHECK_EQ(68, value->Int32Value());
950   }
951   CcTest::i_isolate()->compilation_cache()->Clear();
952   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
953   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
954 }
955
956
957 THREADED_TEST(GlobalProperties) {
958   LocalContext env;
959   v8::HandleScope scope(env->GetIsolate());
960   v8::Handle<v8::Object> global = env->Global();
961   global->Set(v8_str("pi"), v8_num(3.1415926));
962   Local<Value> pi = global->Get(v8_str("pi"));
963   CHECK_EQ(3.1415926, pi->NumberValue());
964 }
965
966
967 template<typename T>
968 static void CheckReturnValue(const T& t, i::Address callback) {
969   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
970   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
971   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
972   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
973   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
974   // Verify reset
975   bool is_runtime = (*o)->IsTheHole();
976   rv.Set(true);
977   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
978   rv.Set(v8::Handle<v8::Object>());
979   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
980   CHECK_EQ(is_runtime, (*o)->IsTheHole());
981
982   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
983   // If CPU profiler is active check that when API callback is invoked
984   // VMState is set to EXTERNAL.
985   if (isolate->cpu_profiler()->is_profiling()) {
986     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
987     CHECK(isolate->external_callback_scope());
988     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
989   }
990 }
991
992
993 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
994                                  i::Address callback) {
995   ApiTestFuzzer::Fuzz();
996   CheckReturnValue(info, callback);
997   info.GetReturnValue().Set(v8_str("bad value"));
998   info.GetReturnValue().Set(v8_num(102));
999 }
1000
1001
1002 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1003   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1004 }
1005
1006
1007 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1008   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1009 }
1010
1011 static void construct_callback(
1012     const v8::FunctionCallbackInfo<Value>& info) {
1013   ApiTestFuzzer::Fuzz();
1014   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1015   info.This()->Set(v8_str("x"), v8_num(1));
1016   info.This()->Set(v8_str("y"), v8_num(2));
1017   info.GetReturnValue().Set(v8_str("bad value"));
1018   info.GetReturnValue().Set(info.This());
1019 }
1020
1021
1022 static void Return239Callback(
1023     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1024   ApiTestFuzzer::Fuzz();
1025   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1026   info.GetReturnValue().Set(v8_str("bad value"));
1027   info.GetReturnValue().Set(v8_num(239));
1028 }
1029
1030
1031 template<typename Handler>
1032 static void TestFunctionTemplateInitializer(Handler handler,
1033                                             Handler handler_2) {
1034   // Test constructor calls.
1035   {
1036     LocalContext env;
1037     v8::Isolate* isolate = env->GetIsolate();
1038     v8::HandleScope scope(isolate);
1039
1040     Local<v8::FunctionTemplate> fun_templ =
1041         v8::FunctionTemplate::New(isolate, handler);
1042     Local<Function> fun = fun_templ->GetFunction();
1043     env->Global()->Set(v8_str("obj"), fun);
1044     Local<Script> script = v8_compile("obj()");
1045     for (int i = 0; i < 30; i++) {
1046       CHECK_EQ(102, script->Run()->Int32Value());
1047     }
1048   }
1049   // Use SetCallHandler to initialize a function template, should work like
1050   // the previous one.
1051   {
1052     LocalContext env;
1053     v8::Isolate* isolate = env->GetIsolate();
1054     v8::HandleScope scope(isolate);
1055
1056     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1057     fun_templ->SetCallHandler(handler_2);
1058     Local<Function> fun = fun_templ->GetFunction();
1059     env->Global()->Set(v8_str("obj"), fun);
1060     Local<Script> script = v8_compile("obj()");
1061     for (int i = 0; i < 30; i++) {
1062       CHECK_EQ(102, script->Run()->Int32Value());
1063     }
1064   }
1065 }
1066
1067
1068 template<typename Constructor, typename Accessor>
1069 static void TestFunctionTemplateAccessor(Constructor constructor,
1070                                          Accessor accessor) {
1071   LocalContext env;
1072   v8::HandleScope scope(env->GetIsolate());
1073
1074   Local<v8::FunctionTemplate> fun_templ =
1075       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1076   fun_templ->SetClassName(v8_str("funky"));
1077   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1078   Local<Function> fun = fun_templ->GetFunction();
1079   env->Global()->Set(v8_str("obj"), fun);
1080   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1081   CHECK_EQ(v8_str("[object funky]"), result);
1082   CompileRun("var obj_instance = new obj();");
1083   Local<Script> script;
1084   script = v8_compile("obj_instance.x");
1085   for (int i = 0; i < 30; i++) {
1086     CHECK_EQ(1, script->Run()->Int32Value());
1087   }
1088   script = v8_compile("obj_instance.m");
1089   for (int i = 0; i < 30; i++) {
1090     CHECK_EQ(239, script->Run()->Int32Value());
1091   }
1092 }
1093
1094
1095 THREADED_PROFILED_TEST(FunctionTemplate) {
1096   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1097   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1098 }
1099
1100
1101 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1102   ApiTestFuzzer::Fuzz();
1103   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1104   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1105 }
1106
1107
1108 template<typename Callback>
1109 static void TestSimpleCallback(Callback callback) {
1110   LocalContext env;
1111   v8::Isolate* isolate = env->GetIsolate();
1112   v8::HandleScope scope(isolate);
1113
1114   v8::Handle<v8::ObjectTemplate> object_template =
1115       v8::ObjectTemplate::New(isolate);
1116   object_template->Set(isolate, "callback",
1117                        v8::FunctionTemplate::New(isolate, callback));
1118   v8::Local<v8::Object> object = object_template->NewInstance();
1119   (*env)->Global()->Set(v8_str("callback_object"), object);
1120   v8::Handle<v8::Script> script;
1121   script = v8_compile("callback_object.callback(17)");
1122   for (int i = 0; i < 30; i++) {
1123     CHECK_EQ(51424, script->Run()->Int32Value());
1124   }
1125   script = v8_compile("callback_object.callback(17, 24)");
1126   for (int i = 0; i < 30; i++) {
1127     CHECK_EQ(51425, script->Run()->Int32Value());
1128   }
1129 }
1130
1131
1132 THREADED_PROFILED_TEST(SimpleCallback) {
1133   TestSimpleCallback(SimpleCallback);
1134 }
1135
1136
1137 template<typename T>
1138 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1139
1140 // constant return values
1141 static int32_t fast_return_value_int32 = 471;
1142 static uint32_t fast_return_value_uint32 = 571;
1143 static const double kFastReturnValueDouble = 2.7;
1144 // variable return values
1145 static bool fast_return_value_bool = false;
1146 enum ReturnValueOddball {
1147   kNullReturnValue,
1148   kUndefinedReturnValue,
1149   kEmptyStringReturnValue
1150 };
1151 static ReturnValueOddball fast_return_value_void;
1152 static bool fast_return_value_object_is_empty = false;
1153
1154 // Helper function to avoid compiler error: insufficient contextual information
1155 // to determine type when applying FUNCTION_ADDR to a template function.
1156 static i::Address address_of(v8::FunctionCallback callback) {
1157   return FUNCTION_ADDR(callback);
1158 }
1159
1160 template<>
1161 void FastReturnValueCallback<int32_t>(
1162     const v8::FunctionCallbackInfo<v8::Value>& info) {
1163   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1164   info.GetReturnValue().Set(fast_return_value_int32);
1165 }
1166
1167 template<>
1168 void FastReturnValueCallback<uint32_t>(
1169     const v8::FunctionCallbackInfo<v8::Value>& info) {
1170   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1171   info.GetReturnValue().Set(fast_return_value_uint32);
1172 }
1173
1174 template<>
1175 void FastReturnValueCallback<double>(
1176     const v8::FunctionCallbackInfo<v8::Value>& info) {
1177   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1178   info.GetReturnValue().Set(kFastReturnValueDouble);
1179 }
1180
1181 template<>
1182 void FastReturnValueCallback<bool>(
1183     const v8::FunctionCallbackInfo<v8::Value>& info) {
1184   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1185   info.GetReturnValue().Set(fast_return_value_bool);
1186 }
1187
1188 template<>
1189 void FastReturnValueCallback<void>(
1190     const v8::FunctionCallbackInfo<v8::Value>& info) {
1191   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1192   switch (fast_return_value_void) {
1193     case kNullReturnValue:
1194       info.GetReturnValue().SetNull();
1195       break;
1196     case kUndefinedReturnValue:
1197       info.GetReturnValue().SetUndefined();
1198       break;
1199     case kEmptyStringReturnValue:
1200       info.GetReturnValue().SetEmptyString();
1201       break;
1202   }
1203 }
1204
1205 template<>
1206 void FastReturnValueCallback<Object>(
1207     const v8::FunctionCallbackInfo<v8::Value>& info) {
1208   v8::Handle<v8::Object> object;
1209   if (!fast_return_value_object_is_empty) {
1210     object = Object::New(info.GetIsolate());
1211   }
1212   info.GetReturnValue().Set(object);
1213 }
1214
1215 template<typename T>
1216 Handle<Value> TestFastReturnValues() {
1217   LocalContext env;
1218   v8::Isolate* isolate = env->GetIsolate();
1219   v8::EscapableHandleScope scope(isolate);
1220   v8::Handle<v8::ObjectTemplate> object_template =
1221       v8::ObjectTemplate::New(isolate);
1222   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1223   object_template->Set(isolate, "callback",
1224                        v8::FunctionTemplate::New(isolate, callback));
1225   v8::Local<v8::Object> object = object_template->NewInstance();
1226   (*env)->Global()->Set(v8_str("callback_object"), object);
1227   return scope.Escape(CompileRun("callback_object.callback()"));
1228 }
1229
1230
1231 THREADED_PROFILED_TEST(FastReturnValues) {
1232   LocalContext env;
1233   v8::HandleScope scope(CcTest::isolate());
1234   v8::Handle<v8::Value> value;
1235   // check int32_t and uint32_t
1236   int32_t int_values[] = {
1237       0, 234, -723,
1238       i::Smi::kMinValue, i::Smi::kMaxValue
1239   };
1240   for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1241     for (int modifier = -1; modifier <= 1; modifier++) {
1242       int int_value = int_values[i] + modifier;
1243       // check int32_t
1244       fast_return_value_int32 = int_value;
1245       value = TestFastReturnValues<int32_t>();
1246       CHECK(value->IsInt32());
1247       CHECK(fast_return_value_int32 == value->Int32Value());
1248       // check uint32_t
1249       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1250       value = TestFastReturnValues<uint32_t>();
1251       CHECK(value->IsUint32());
1252       CHECK(fast_return_value_uint32 == value->Uint32Value());
1253     }
1254   }
1255   // check double
1256   value = TestFastReturnValues<double>();
1257   CHECK(value->IsNumber());
1258   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1259   // check bool values
1260   for (int i = 0; i < 2; i++) {
1261     fast_return_value_bool = i == 0;
1262     value = TestFastReturnValues<bool>();
1263     CHECK(value->IsBoolean());
1264     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1265   }
1266   // check oddballs
1267   ReturnValueOddball oddballs[] = {
1268       kNullReturnValue,
1269       kUndefinedReturnValue,
1270       kEmptyStringReturnValue
1271   };
1272   for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1273     fast_return_value_void = oddballs[i];
1274     value = TestFastReturnValues<void>();
1275     switch (fast_return_value_void) {
1276       case kNullReturnValue:
1277         CHECK(value->IsNull());
1278         break;
1279       case kUndefinedReturnValue:
1280         CHECK(value->IsUndefined());
1281         break;
1282       case kEmptyStringReturnValue:
1283         CHECK(value->IsString());
1284         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1285         break;
1286     }
1287   }
1288   // check handles
1289   fast_return_value_object_is_empty = false;
1290   value = TestFastReturnValues<Object>();
1291   CHECK(value->IsObject());
1292   fast_return_value_object_is_empty = true;
1293   value = TestFastReturnValues<Object>();
1294   CHECK(value->IsUndefined());
1295 }
1296
1297
1298 THREADED_TEST(FunctionTemplateSetLength) {
1299   LocalContext env;
1300   v8::Isolate* isolate = env->GetIsolate();
1301   v8::HandleScope scope(isolate);
1302   {
1303     Local<v8::FunctionTemplate> fun_templ =
1304         v8::FunctionTemplate::New(isolate,
1305                                   handle_callback,
1306                                   Handle<v8::Value>(),
1307                                   Handle<v8::Signature>(),
1308                                   23);
1309     Local<Function> fun = fun_templ->GetFunction();
1310     env->Global()->Set(v8_str("obj"), fun);
1311     Local<Script> script = v8_compile("obj.length");
1312     CHECK_EQ(23, script->Run()->Int32Value());
1313   }
1314   {
1315     Local<v8::FunctionTemplate> fun_templ =
1316         v8::FunctionTemplate::New(isolate, handle_callback);
1317     fun_templ->SetLength(22);
1318     Local<Function> fun = fun_templ->GetFunction();
1319     env->Global()->Set(v8_str("obj"), fun);
1320     Local<Script> script = v8_compile("obj.length");
1321     CHECK_EQ(22, script->Run()->Int32Value());
1322   }
1323   {
1324     // Without setting length it defaults to 0.
1325     Local<v8::FunctionTemplate> fun_templ =
1326         v8::FunctionTemplate::New(isolate, handle_callback);
1327     Local<Function> fun = fun_templ->GetFunction();
1328     env->Global()->Set(v8_str("obj"), fun);
1329     Local<Script> script = v8_compile("obj.length");
1330     CHECK_EQ(0, script->Run()->Int32Value());
1331   }
1332 }
1333
1334
1335 static void* expected_ptr;
1336 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1337   void* ptr = v8::External::Cast(*args.Data())->Value();
1338   CHECK_EQ(expected_ptr, ptr);
1339   args.GetReturnValue().Set(true);
1340 }
1341
1342
1343 static void TestExternalPointerWrapping() {
1344   LocalContext env;
1345   v8::Isolate* isolate = env->GetIsolate();
1346   v8::HandleScope scope(isolate);
1347
1348   v8::Handle<v8::Value> data =
1349       v8::External::New(isolate, expected_ptr);
1350
1351   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1352   obj->Set(v8_str("func"),
1353            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1354   env->Global()->Set(v8_str("obj"), obj);
1355
1356   CHECK(CompileRun(
1357         "function foo() {\n"
1358         "  for (var i = 0; i < 13; i++) obj.func();\n"
1359         "}\n"
1360         "foo(), true")->BooleanValue());
1361 }
1362
1363
1364 THREADED_TEST(ExternalWrap) {
1365   // Check heap allocated object.
1366   int* ptr = new int;
1367   expected_ptr = ptr;
1368   TestExternalPointerWrapping();
1369   delete ptr;
1370
1371   // Check stack allocated object.
1372   int foo;
1373   expected_ptr = &foo;
1374   TestExternalPointerWrapping();
1375
1376   // Check not aligned addresses.
1377   const int n = 100;
1378   char* s = new char[n];
1379   for (int i = 0; i < n; i++) {
1380     expected_ptr = s + i;
1381     TestExternalPointerWrapping();
1382   }
1383
1384   delete[] s;
1385
1386   // Check several invalid addresses.
1387   expected_ptr = reinterpret_cast<void*>(1);
1388   TestExternalPointerWrapping();
1389
1390   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1391   TestExternalPointerWrapping();
1392
1393   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1394   TestExternalPointerWrapping();
1395
1396 #if defined(V8_HOST_ARCH_X64)
1397   // Check a value with a leading 1 bit in x64 Smi encoding.
1398   expected_ptr = reinterpret_cast<void*>(0x400000000);
1399   TestExternalPointerWrapping();
1400
1401   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1402   TestExternalPointerWrapping();
1403
1404   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1405   TestExternalPointerWrapping();
1406 #endif
1407 }
1408
1409
1410 THREADED_TEST(FindInstanceInPrototypeChain) {
1411   LocalContext env;
1412   v8::Isolate* isolate = env->GetIsolate();
1413   v8::HandleScope scope(isolate);
1414
1415   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1416   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1417   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1418   derived->Inherit(base);
1419
1420   Local<v8::Function> base_function = base->GetFunction();
1421   Local<v8::Function> derived_function = derived->GetFunction();
1422   Local<v8::Function> other_function = other->GetFunction();
1423
1424   Local<v8::Object> base_instance = base_function->NewInstance();
1425   Local<v8::Object> derived_instance = derived_function->NewInstance();
1426   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1427   Local<v8::Object> other_instance = other_function->NewInstance();
1428   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1429   other_instance->Set(v8_str("__proto__"), derived_instance2);
1430
1431   // base_instance is only an instance of base.
1432   CHECK_EQ(base_instance,
1433            base_instance->FindInstanceInPrototypeChain(base));
1434   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1435   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1436
1437   // derived_instance is an instance of base and derived.
1438   CHECK_EQ(derived_instance,
1439            derived_instance->FindInstanceInPrototypeChain(base));
1440   CHECK_EQ(derived_instance,
1441            derived_instance->FindInstanceInPrototypeChain(derived));
1442   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1443
1444   // other_instance is an instance of other and its immediate
1445   // prototype derived_instance2 is an instance of base and derived.
1446   // Note, derived_instance is an instance of base and derived too,
1447   // but it comes after derived_instance2 in the prototype chain of
1448   // other_instance.
1449   CHECK_EQ(derived_instance2,
1450            other_instance->FindInstanceInPrototypeChain(base));
1451   CHECK_EQ(derived_instance2,
1452            other_instance->FindInstanceInPrototypeChain(derived));
1453   CHECK_EQ(other_instance,
1454            other_instance->FindInstanceInPrototypeChain(other));
1455 }
1456
1457
1458 THREADED_TEST(TinyInteger) {
1459   LocalContext env;
1460   v8::Isolate* isolate = env->GetIsolate();
1461   v8::HandleScope scope(isolate);
1462
1463   int32_t value = 239;
1464   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1465   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1466
1467   value_obj = v8::Integer::New(isolate, value);
1468   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1469 }
1470
1471
1472 THREADED_TEST(BigSmiInteger) {
1473   LocalContext env;
1474   v8::HandleScope scope(env->GetIsolate());
1475   v8::Isolate* isolate = CcTest::isolate();
1476
1477   int32_t value = i::Smi::kMaxValue;
1478   // We cannot add one to a Smi::kMaxValue without wrapping.
1479   if (i::SmiValuesAre31Bits()) {
1480     CHECK(i::Smi::IsValid(value));
1481     CHECK(!i::Smi::IsValid(value + 1));
1482
1483     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1484     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1485
1486     value_obj = v8::Integer::New(isolate, value);
1487     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1488   }
1489 }
1490
1491
1492 THREADED_TEST(BigInteger) {
1493   LocalContext env;
1494   v8::HandleScope scope(env->GetIsolate());
1495   v8::Isolate* isolate = CcTest::isolate();
1496
1497   // We cannot add one to a Smi::kMaxValue without wrapping.
1498   if (i::SmiValuesAre31Bits()) {
1499     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1500     // The code will not be run in that case, due to the "if" guard.
1501     int32_t value =
1502         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1503     CHECK(value > i::Smi::kMaxValue);
1504     CHECK(!i::Smi::IsValid(value));
1505
1506     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1507     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1508
1509     value_obj = v8::Integer::New(isolate, value);
1510     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1511   }
1512 }
1513
1514
1515 THREADED_TEST(TinyUnsignedInteger) {
1516   LocalContext env;
1517   v8::HandleScope scope(env->GetIsolate());
1518   v8::Isolate* isolate = CcTest::isolate();
1519
1520   uint32_t value = 239;
1521
1522   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1523   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1524
1525   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1526   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1527 }
1528
1529
1530 THREADED_TEST(BigUnsignedSmiInteger) {
1531   LocalContext env;
1532   v8::HandleScope scope(env->GetIsolate());
1533   v8::Isolate* isolate = CcTest::isolate();
1534
1535   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1536   CHECK(i::Smi::IsValid(value));
1537   CHECK(!i::Smi::IsValid(value + 1));
1538
1539   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1540   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1541
1542   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1543   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1544 }
1545
1546
1547 THREADED_TEST(BigUnsignedInteger) {
1548   LocalContext env;
1549   v8::HandleScope scope(env->GetIsolate());
1550   v8::Isolate* isolate = CcTest::isolate();
1551
1552   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1553   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1554   CHECK(!i::Smi::IsValid(value));
1555
1556   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1557   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1558
1559   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1560   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1561 }
1562
1563
1564 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1565   LocalContext env;
1566   v8::HandleScope scope(env->GetIsolate());
1567   v8::Isolate* isolate = CcTest::isolate();
1568
1569   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1570   uint32_t value = INT32_MAX_AS_UINT + 1;
1571   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1572
1573   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1574   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1575
1576   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1577   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1578 }
1579
1580
1581 THREADED_TEST(IsNativeError) {
1582   LocalContext env;
1583   v8::HandleScope scope(env->GetIsolate());
1584   v8::Handle<Value> syntax_error = CompileRun(
1585       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1586   CHECK(syntax_error->IsNativeError());
1587   v8::Handle<Value> not_error = CompileRun("{a:42}");
1588   CHECK(!not_error->IsNativeError());
1589   v8::Handle<Value> not_object = CompileRun("42");
1590   CHECK(!not_object->IsNativeError());
1591 }
1592
1593
1594 THREADED_TEST(StringObject) {
1595   LocalContext env;
1596   v8::HandleScope scope(env->GetIsolate());
1597   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1598   CHECK(boxed_string->IsStringObject());
1599   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1600   CHECK(!unboxed_string->IsStringObject());
1601   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1602   CHECK(!boxed_not_string->IsStringObject());
1603   v8::Handle<Value> not_object = CompileRun("0");
1604   CHECK(!not_object->IsStringObject());
1605   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1606   CHECK(!as_boxed.IsEmpty());
1607   Local<v8::String> the_string = as_boxed->ValueOf();
1608   CHECK(!the_string.IsEmpty());
1609   ExpectObject("\"test\"", the_string);
1610   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1611   CHECK(new_boxed_string->IsStringObject());
1612   as_boxed = new_boxed_string.As<v8::StringObject>();
1613   the_string = as_boxed->ValueOf();
1614   CHECK(!the_string.IsEmpty());
1615   ExpectObject("\"test\"", the_string);
1616 }
1617
1618
1619 THREADED_TEST(NumberObject) {
1620   LocalContext env;
1621   v8::HandleScope scope(env->GetIsolate());
1622   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1623   CHECK(boxed_number->IsNumberObject());
1624   v8::Handle<Value> unboxed_number = CompileRun("42");
1625   CHECK(!unboxed_number->IsNumberObject());
1626   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1627   CHECK(!boxed_not_number->IsNumberObject());
1628   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1629   CHECK(!as_boxed.IsEmpty());
1630   double the_number = as_boxed->ValueOf();
1631   CHECK_EQ(42.0, the_number);
1632   v8::Handle<v8::Value> new_boxed_number =
1633       v8::NumberObject::New(env->GetIsolate(), 43);
1634   CHECK(new_boxed_number->IsNumberObject());
1635   as_boxed = new_boxed_number.As<v8::NumberObject>();
1636   the_number = as_boxed->ValueOf();
1637   CHECK_EQ(43.0, the_number);
1638 }
1639
1640
1641 THREADED_TEST(BooleanObject) {
1642   LocalContext env;
1643   v8::HandleScope scope(env->GetIsolate());
1644   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1645   CHECK(boxed_boolean->IsBooleanObject());
1646   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1647   CHECK(!unboxed_boolean->IsBooleanObject());
1648   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1649   CHECK(!boxed_not_boolean->IsBooleanObject());
1650   v8::Handle<v8::BooleanObject> as_boxed =
1651       boxed_boolean.As<v8::BooleanObject>();
1652   CHECK(!as_boxed.IsEmpty());
1653   bool the_boolean = as_boxed->ValueOf();
1654   CHECK_EQ(true, the_boolean);
1655   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1656   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1657   CHECK(boxed_true->IsBooleanObject());
1658   CHECK(boxed_false->IsBooleanObject());
1659   as_boxed = boxed_true.As<v8::BooleanObject>();
1660   CHECK_EQ(true, as_boxed->ValueOf());
1661   as_boxed = boxed_false.As<v8::BooleanObject>();
1662   CHECK_EQ(false, as_boxed->ValueOf());
1663 }
1664
1665
1666 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1667   LocalContext env;
1668   v8::HandleScope scope(env->GetIsolate());
1669
1670   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1671   CHECK(primitive_false->IsBoolean());
1672   CHECK(!primitive_false->IsBooleanObject());
1673   CHECK(!primitive_false->BooleanValue());
1674   CHECK(!primitive_false->IsTrue());
1675   CHECK(primitive_false->IsFalse());
1676
1677   Local<Value> false_value = BooleanObject::New(false);
1678   CHECK(!false_value->IsBoolean());
1679   CHECK(false_value->IsBooleanObject());
1680   CHECK(false_value->BooleanValue());
1681   CHECK(!false_value->IsTrue());
1682   CHECK(!false_value->IsFalse());
1683
1684   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1685   CHECK(!false_boolean_object->IsBoolean());
1686   CHECK(false_boolean_object->IsBooleanObject());
1687   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1688   // CHECK(false_boolean_object->BooleanValue());
1689   CHECK(!false_boolean_object->ValueOf());
1690   CHECK(!false_boolean_object->IsTrue());
1691   CHECK(!false_boolean_object->IsFalse());
1692
1693   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1694   CHECK(primitive_true->IsBoolean());
1695   CHECK(!primitive_true->IsBooleanObject());
1696   CHECK(primitive_true->BooleanValue());
1697   CHECK(primitive_true->IsTrue());
1698   CHECK(!primitive_true->IsFalse());
1699
1700   Local<Value> true_value = BooleanObject::New(true);
1701   CHECK(!true_value->IsBoolean());
1702   CHECK(true_value->IsBooleanObject());
1703   CHECK(true_value->BooleanValue());
1704   CHECK(!true_value->IsTrue());
1705   CHECK(!true_value->IsFalse());
1706
1707   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1708   CHECK(!true_boolean_object->IsBoolean());
1709   CHECK(true_boolean_object->IsBooleanObject());
1710   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1711   // CHECK(true_boolean_object->BooleanValue());
1712   CHECK(true_boolean_object->ValueOf());
1713   CHECK(!true_boolean_object->IsTrue());
1714   CHECK(!true_boolean_object->IsFalse());
1715 }
1716
1717
1718 THREADED_TEST(Number) {
1719   LocalContext env;
1720   v8::HandleScope scope(env->GetIsolate());
1721   double PI = 3.1415926;
1722   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1723   CHECK_EQ(PI, pi_obj->NumberValue());
1724 }
1725
1726
1727 THREADED_TEST(ToNumber) {
1728   LocalContext env;
1729   v8::Isolate* isolate = CcTest::isolate();
1730   v8::HandleScope scope(isolate);
1731   Local<String> str = v8_str("3.1415926");
1732   CHECK_EQ(3.1415926, str->NumberValue());
1733   v8::Handle<v8::Boolean> t = v8::True(isolate);
1734   CHECK_EQ(1.0, t->NumberValue());
1735   v8::Handle<v8::Boolean> f = v8::False(isolate);
1736   CHECK_EQ(0.0, f->NumberValue());
1737 }
1738
1739
1740 THREADED_TEST(Date) {
1741   LocalContext env;
1742   v8::HandleScope scope(env->GetIsolate());
1743   double PI = 3.1415926;
1744   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1745   CHECK_EQ(3.0, date->NumberValue());
1746   date.As<v8::Date>()->Set(v8_str("property"),
1747                            v8::Integer::New(env->GetIsolate(), 42));
1748   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1749 }
1750
1751
1752 THREADED_TEST(Boolean) {
1753   LocalContext env;
1754   v8::Isolate* isolate = env->GetIsolate();
1755   v8::HandleScope scope(isolate);
1756   v8::Handle<v8::Boolean> t = v8::True(isolate);
1757   CHECK(t->Value());
1758   v8::Handle<v8::Boolean> f = v8::False(isolate);
1759   CHECK(!f->Value());
1760   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1761   CHECK(!u->BooleanValue());
1762   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1763   CHECK(!n->BooleanValue());
1764   v8::Handle<String> str1 = v8_str("");
1765   CHECK(!str1->BooleanValue());
1766   v8::Handle<String> str2 = v8_str("x");
1767   CHECK(str2->BooleanValue());
1768   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1769   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1770   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1771   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1772   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1773 }
1774
1775
1776 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1777   ApiTestFuzzer::Fuzz();
1778   args.GetReturnValue().Set(v8_num(13.4));
1779 }
1780
1781
1782 static void GetM(Local<String> name,
1783                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1784   ApiTestFuzzer::Fuzz();
1785   info.GetReturnValue().Set(v8_num(876));
1786 }
1787
1788
1789 THREADED_TEST(GlobalPrototype) {
1790   v8::Isolate* isolate = CcTest::isolate();
1791   v8::HandleScope scope(isolate);
1792   v8::Handle<v8::FunctionTemplate> func_templ =
1793       v8::FunctionTemplate::New(isolate);
1794   func_templ->PrototypeTemplate()->Set(
1795       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1796   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1797   templ->Set(isolate, "x", v8_num(200));
1798   templ->SetAccessor(v8_str("m"), GetM);
1799   LocalContext env(0, templ);
1800   v8::Handle<Script> script(v8_compile("dummy()"));
1801   v8::Handle<Value> result(script->Run());
1802   CHECK_EQ(13.4, result->NumberValue());
1803   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1804   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1805 }
1806
1807
1808 THREADED_TEST(ObjectTemplate) {
1809   v8::Isolate* isolate = CcTest::isolate();
1810   v8::HandleScope scope(isolate);
1811   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1812   templ1->Set(isolate, "x", v8_num(10));
1813   templ1->Set(isolate, "y", v8_num(13));
1814   LocalContext env;
1815   Local<v8::Object> instance1 = templ1->NewInstance();
1816   env->Global()->Set(v8_str("p"), instance1);
1817   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1818   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1819   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1820   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1821   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1822   templ2->Set(isolate, "a", v8_num(12));
1823   templ2->Set(isolate, "b", templ1);
1824   Local<v8::Object> instance2 = templ2->NewInstance();
1825   env->Global()->Set(v8_str("q"), instance2);
1826   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1827   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1828   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1829   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1830 }
1831
1832
1833 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1834   ApiTestFuzzer::Fuzz();
1835   args.GetReturnValue().Set(v8_num(17.2));
1836 }
1837
1838
1839 static void GetKnurd(Local<String> property,
1840                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1841   ApiTestFuzzer::Fuzz();
1842   info.GetReturnValue().Set(v8_num(15.2));
1843 }
1844
1845
1846 THREADED_TEST(DescriptorInheritance) {
1847   v8::Isolate* isolate = CcTest::isolate();
1848   v8::HandleScope scope(isolate);
1849   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1850   super->PrototypeTemplate()->Set(isolate, "flabby",
1851                                   v8::FunctionTemplate::New(isolate,
1852                                                             GetFlabby));
1853   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1854
1855   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1856
1857   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1858   base1->Inherit(super);
1859   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1860
1861   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1862   base2->Inherit(super);
1863   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1864
1865   LocalContext env;
1866
1867   env->Global()->Set(v8_str("s"), super->GetFunction());
1868   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1869   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1870
1871   // Checks right __proto__ chain.
1872   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1873   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1874
1875   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1876
1877   // Instance accessor should not be visible on function object or its prototype
1878   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1879   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1880   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1881
1882   env->Global()->Set(v8_str("obj"),
1883                      base1->GetFunction()->NewInstance());
1884   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1885   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1886   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1887   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1888   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1889
1890   env->Global()->Set(v8_str("obj2"),
1891                      base2->GetFunction()->NewInstance());
1892   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1893   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1894   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1895   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1896   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1897
1898   // base1 and base2 cannot cross reference to each's prototype
1899   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1900   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1901 }
1902
1903
1904 int echo_named_call_count;
1905
1906
1907 static void EchoNamedProperty(Local<String> name,
1908                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1909   ApiTestFuzzer::Fuzz();
1910   CHECK_EQ(v8_str("data"), info.Data());
1911   echo_named_call_count++;
1912   info.GetReturnValue().Set(name);
1913 }
1914
1915
1916 // Helper functions for Interceptor/Accessor interaction tests
1917
1918 void SimpleAccessorGetter(Local<String> name,
1919                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1920   Handle<Object> self = info.This();
1921   info.GetReturnValue().Set(
1922       self->Get(String::Concat(v8_str("accessor_"), name)));
1923 }
1924
1925 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1926                           const v8::PropertyCallbackInfo<void>& info) {
1927   Handle<Object> self = info.This();
1928   self->Set(String::Concat(v8_str("accessor_"), name), value);
1929 }
1930
1931 void EmptyInterceptorGetter(Local<String> name,
1932                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1933 }
1934
1935 void EmptyInterceptorSetter(Local<String> name,
1936                             Local<Value> value,
1937                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1938 }
1939
1940 void InterceptorGetter(Local<String> name,
1941                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1942   // Intercept names that start with 'interceptor_'.
1943   String::Utf8Value utf8(name);
1944   char* name_str = *utf8;
1945   char prefix[] = "interceptor_";
1946   int i;
1947   for (i = 0; name_str[i] && prefix[i]; ++i) {
1948     if (name_str[i] != prefix[i]) return;
1949   }
1950   Handle<Object> self = info.This();
1951   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1952 }
1953
1954 void InterceptorSetter(Local<String> name,
1955                        Local<Value> value,
1956                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1957   // Intercept accesses that set certain integer values, for which the name does
1958   // not start with 'accessor_'.
1959   String::Utf8Value utf8(name);
1960   char* name_str = *utf8;
1961   char prefix[] = "accessor_";
1962   int i;
1963   for (i = 0; name_str[i] && prefix[i]; ++i) {
1964     if (name_str[i] != prefix[i]) break;
1965   }
1966   if (!prefix[i]) return;
1967
1968   if (value->IsInt32() && value->Int32Value() < 10000) {
1969     Handle<Object> self = info.This();
1970     self->SetHiddenValue(name, value);
1971     info.GetReturnValue().Set(value);
1972   }
1973 }
1974
1975 void AddAccessor(Handle<FunctionTemplate> templ,
1976                  Handle<String> name,
1977                  v8::AccessorGetterCallback getter,
1978                  v8::AccessorSetterCallback setter) {
1979   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1980 }
1981
1982 void AddInterceptor(Handle<FunctionTemplate> templ,
1983                     v8::NamedPropertyGetterCallback getter,
1984                     v8::NamedPropertySetterCallback setter) {
1985   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1986 }
1987
1988
1989 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1990   v8::HandleScope scope(CcTest::isolate());
1991   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1992   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1993   child->Inherit(parent);
1994   AddAccessor(parent, v8_str("age"),
1995               SimpleAccessorGetter, SimpleAccessorSetter);
1996   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1997   LocalContext env;
1998   env->Global()->Set(v8_str("Child"), child->GetFunction());
1999   CompileRun("var child = new Child;"
2000              "child.age = 10;");
2001   ExpectBoolean("child.hasOwnProperty('age')", false);
2002   ExpectInt32("child.age", 10);
2003   ExpectInt32("child.accessor_age", 10);
2004 }
2005
2006
2007 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2008   v8::HandleScope scope(CcTest::isolate());
2009   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2010   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2011   LocalContext env;
2012   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2013   CompileRun("var o1 = new Constructor;"
2014              "o1.a = 1;"  // Ensure a and x share the descriptor array.
2015              "Object.defineProperty(o1, 'x', {value: 10});");
2016   CompileRun("var o2 = new Constructor;"
2017              "o2.a = 1;"
2018              "Object.defineProperty(o2, 'x', {value: 10});");
2019 }
2020
2021
2022 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2023   v8::Isolate* isolate = CcTest::isolate();
2024   v8::HandleScope scope(isolate);
2025   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2026   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2027   child->Inherit(parent);
2028   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2029   LocalContext env;
2030   env->Global()->Set(v8_str("Child"), child->GetFunction());
2031   CompileRun("var child = new Child;"
2032              "var parent = child.__proto__;"
2033              "Object.defineProperty(parent, 'age', "
2034              "  {get: function(){ return this.accessor_age; }, "
2035              "   set: function(v){ this.accessor_age = v; }, "
2036              "   enumerable: true, configurable: true});"
2037              "child.age = 10;");
2038   ExpectBoolean("child.hasOwnProperty('age')", false);
2039   ExpectInt32("child.age", 10);
2040   ExpectInt32("child.accessor_age", 10);
2041 }
2042
2043
2044 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2045   v8::Isolate* isolate = CcTest::isolate();
2046   v8::HandleScope scope(isolate);
2047   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2048   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2049   child->Inherit(parent);
2050   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2051   LocalContext env;
2052   env->Global()->Set(v8_str("Child"), child->GetFunction());
2053   CompileRun("var child = new Child;"
2054              "var parent = child.__proto__;"
2055              "parent.name = 'Alice';");
2056   ExpectBoolean("child.hasOwnProperty('name')", false);
2057   ExpectString("child.name", "Alice");
2058   CompileRun("child.name = 'Bob';");
2059   ExpectString("child.name", "Bob");
2060   ExpectBoolean("child.hasOwnProperty('name')", true);
2061   ExpectString("parent.name", "Alice");
2062 }
2063
2064
2065 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2066   v8::HandleScope scope(CcTest::isolate());
2067   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2068   AddAccessor(templ, v8_str("age"),
2069               SimpleAccessorGetter, SimpleAccessorSetter);
2070   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2071   LocalContext env;
2072   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2073   CompileRun("var obj = new Obj;"
2074              "function setAge(i){ obj.age = i; };"
2075              "for(var i = 0; i <= 10000; i++) setAge(i);");
2076   // All i < 10000 go to the interceptor.
2077   ExpectInt32("obj.interceptor_age", 9999);
2078   // The last i goes to the accessor.
2079   ExpectInt32("obj.accessor_age", 10000);
2080 }
2081
2082
2083 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2084   v8::HandleScope scope(CcTest::isolate());
2085   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2086   AddAccessor(templ, v8_str("age"),
2087               SimpleAccessorGetter, SimpleAccessorSetter);
2088   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2089   LocalContext env;
2090   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2091   CompileRun("var obj = new Obj;"
2092              "function setAge(i){ obj.age = i; };"
2093              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2094   // All i >= 10000 go to the accessor.
2095   ExpectInt32("obj.accessor_age", 10000);
2096   // The last i goes to the interceptor.
2097   ExpectInt32("obj.interceptor_age", 9999);
2098 }
2099
2100
2101 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2102   v8::HandleScope scope(CcTest::isolate());
2103   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2104   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2105   child->Inherit(parent);
2106   AddAccessor(parent, v8_str("age"),
2107               SimpleAccessorGetter, SimpleAccessorSetter);
2108   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2109   LocalContext env;
2110   env->Global()->Set(v8_str("Child"), child->GetFunction());
2111   CompileRun("var child = new Child;"
2112              "function setAge(i){ child.age = i; };"
2113              "for(var i = 0; i <= 10000; i++) setAge(i);");
2114   // All i < 10000 go to the interceptor.
2115   ExpectInt32("child.interceptor_age", 9999);
2116   // The last i goes to the accessor.
2117   ExpectInt32("child.accessor_age", 10000);
2118 }
2119
2120
2121 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2122   v8::HandleScope scope(CcTest::isolate());
2123   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2124   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2125   child->Inherit(parent);
2126   AddAccessor(parent, v8_str("age"),
2127               SimpleAccessorGetter, SimpleAccessorSetter);
2128   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2129   LocalContext env;
2130   env->Global()->Set(v8_str("Child"), child->GetFunction());
2131   CompileRun("var child = new Child;"
2132              "function setAge(i){ child.age = i; };"
2133              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2134   // All i >= 10000 go to the accessor.
2135   ExpectInt32("child.accessor_age", 10000);
2136   // The last i goes to the interceptor.
2137   ExpectInt32("child.interceptor_age", 9999);
2138 }
2139
2140
2141 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2142   v8::HandleScope scope(CcTest::isolate());
2143   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2144   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2145   LocalContext env;
2146   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2147   CompileRun("var obj = new Obj;"
2148              "function setter(i) { this.accessor_age = i; };"
2149              "function getter() { return this.accessor_age; };"
2150              "function setAge(i) { obj.age = i; };"
2151              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2152              "for(var i = 0; i <= 10000; i++) setAge(i);");
2153   // All i < 10000 go to the interceptor.
2154   ExpectInt32("obj.interceptor_age", 9999);
2155   // The last i goes to the JavaScript accessor.
2156   ExpectInt32("obj.accessor_age", 10000);
2157   // The installed JavaScript getter is still intact.
2158   // This last part is a regression test for issue 1651 and relies on the fact
2159   // that both interceptor and accessor are being installed on the same object.
2160   ExpectInt32("obj.age", 10000);
2161   ExpectBoolean("obj.hasOwnProperty('age')", true);
2162   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2163 }
2164
2165
2166 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2167   v8::HandleScope scope(CcTest::isolate());
2168   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2169   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2170   LocalContext env;
2171   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2172   CompileRun("var obj = new Obj;"
2173              "function setter(i) { this.accessor_age = i; };"
2174              "function getter() { return this.accessor_age; };"
2175              "function setAge(i) { obj.age = i; };"
2176              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2177              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2178   // All i >= 10000 go to the accessor.
2179   ExpectInt32("obj.accessor_age", 10000);
2180   // The last i goes to the interceptor.
2181   ExpectInt32("obj.interceptor_age", 9999);
2182   // The installed JavaScript getter is still intact.
2183   // This last part is a regression test for issue 1651 and relies on the fact
2184   // that both interceptor and accessor are being installed on the same object.
2185   ExpectInt32("obj.age", 10000);
2186   ExpectBoolean("obj.hasOwnProperty('age')", true);
2187   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2188 }
2189
2190
2191 THREADED_TEST(SwitchFromInterceptorToProperty) {
2192   v8::HandleScope scope(CcTest::isolate());
2193   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2194   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2195   child->Inherit(parent);
2196   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2197   LocalContext env;
2198   env->Global()->Set(v8_str("Child"), child->GetFunction());
2199   CompileRun("var child = new Child;"
2200              "function setAge(i){ child.age = i; };"
2201              "for(var i = 0; i <= 10000; i++) setAge(i);");
2202   // All i < 10000 go to the interceptor.
2203   ExpectInt32("child.interceptor_age", 9999);
2204   // The last i goes to child's own property.
2205   ExpectInt32("child.age", 10000);
2206 }
2207
2208
2209 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2210   v8::HandleScope scope(CcTest::isolate());
2211   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2212   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2213   child->Inherit(parent);
2214   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2215   LocalContext env;
2216   env->Global()->Set(v8_str("Child"), child->GetFunction());
2217   CompileRun("var child = new Child;"
2218              "function setAge(i){ child.age = i; };"
2219              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2220   // All i >= 10000 go to child's own property.
2221   ExpectInt32("child.age", 10000);
2222   // The last i goes to the interceptor.
2223   ExpectInt32("child.interceptor_age", 9999);
2224 }
2225
2226
2227 THREADED_TEST(NamedPropertyHandlerGetter) {
2228   echo_named_call_count = 0;
2229   v8::HandleScope scope(CcTest::isolate());
2230   v8::Handle<v8::FunctionTemplate> templ =
2231       v8::FunctionTemplate::New(CcTest::isolate());
2232   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2233                                                      0, 0, 0, 0,
2234                                                      v8_str("data"));
2235   LocalContext env;
2236   env->Global()->Set(v8_str("obj"),
2237                      templ->GetFunction()->NewInstance());
2238   CHECK_EQ(echo_named_call_count, 0);
2239   v8_compile("obj.x")->Run();
2240   CHECK_EQ(echo_named_call_count, 1);
2241   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2242   v8::Handle<Value> str = CompileRun(code);
2243   String::Utf8Value value(str);
2244   CHECK_EQ(*value, "oddlepoddle");
2245   // Check default behavior
2246   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2247   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2248   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2249 }
2250
2251
2252 int echo_indexed_call_count = 0;
2253
2254
2255 static void EchoIndexedProperty(
2256     uint32_t index,
2257     const v8::PropertyCallbackInfo<v8::Value>& info) {
2258   ApiTestFuzzer::Fuzz();
2259   CHECK_EQ(v8_num(637), info.Data());
2260   echo_indexed_call_count++;
2261   info.GetReturnValue().Set(v8_num(index));
2262 }
2263
2264
2265 THREADED_TEST(IndexedPropertyHandlerGetter) {
2266   v8::Isolate* isolate = CcTest::isolate();
2267   v8::HandleScope scope(isolate);
2268   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2269   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2270                                                        0, 0, 0, 0,
2271                                                        v8_num(637));
2272   LocalContext env;
2273   env->Global()->Set(v8_str("obj"),
2274                      templ->GetFunction()->NewInstance());
2275   Local<Script> script = v8_compile("obj[900]");
2276   CHECK_EQ(script->Run()->Int32Value(), 900);
2277 }
2278
2279
2280 v8::Handle<v8::Object> bottom;
2281
2282 static void CheckThisIndexedPropertyHandler(
2283     uint32_t index,
2284     const v8::PropertyCallbackInfo<v8::Value>& info) {
2285   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2286   ApiTestFuzzer::Fuzz();
2287   CHECK(info.This()->Equals(bottom));
2288 }
2289
2290 static void CheckThisNamedPropertyHandler(
2291     Local<String> name,
2292     const v8::PropertyCallbackInfo<v8::Value>& info) {
2293   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2294   ApiTestFuzzer::Fuzz();
2295   CHECK(info.This()->Equals(bottom));
2296 }
2297
2298 void CheckThisIndexedPropertySetter(
2299     uint32_t index,
2300     Local<Value> value,
2301     const v8::PropertyCallbackInfo<v8::Value>& info) {
2302   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2303   ApiTestFuzzer::Fuzz();
2304   CHECK(info.This()->Equals(bottom));
2305 }
2306
2307
2308 void CheckThisNamedPropertySetter(
2309     Local<String> property,
2310     Local<Value> value,
2311     const v8::PropertyCallbackInfo<v8::Value>& info) {
2312   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2313   ApiTestFuzzer::Fuzz();
2314   CHECK(info.This()->Equals(bottom));
2315 }
2316
2317 void CheckThisIndexedPropertyQuery(
2318     uint32_t index,
2319     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2320   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2321   ApiTestFuzzer::Fuzz();
2322   CHECK(info.This()->Equals(bottom));
2323 }
2324
2325
2326 void CheckThisNamedPropertyQuery(
2327     Local<String> property,
2328     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2329   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2330   ApiTestFuzzer::Fuzz();
2331   CHECK(info.This()->Equals(bottom));
2332 }
2333
2334
2335 void CheckThisIndexedPropertyDeleter(
2336     uint32_t index,
2337     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2338   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2339   ApiTestFuzzer::Fuzz();
2340   CHECK(info.This()->Equals(bottom));
2341 }
2342
2343
2344 void CheckThisNamedPropertyDeleter(
2345     Local<String> property,
2346     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2347   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2348   ApiTestFuzzer::Fuzz();
2349   CHECK(info.This()->Equals(bottom));
2350 }
2351
2352
2353 void CheckThisIndexedPropertyEnumerator(
2354     const v8::PropertyCallbackInfo<v8::Array>& info) {
2355   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2356   ApiTestFuzzer::Fuzz();
2357   CHECK(info.This()->Equals(bottom));
2358 }
2359
2360
2361 void CheckThisNamedPropertyEnumerator(
2362     const v8::PropertyCallbackInfo<v8::Array>& info) {
2363   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2364   ApiTestFuzzer::Fuzz();
2365   CHECK(info.This()->Equals(bottom));
2366 }
2367
2368
2369 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2370   LocalContext env;
2371   v8::Isolate* isolate = env->GetIsolate();
2372   v8::HandleScope scope(isolate);
2373
2374   // Set up a prototype chain with three interceptors.
2375   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2376   templ->InstanceTemplate()->SetIndexedPropertyHandler(
2377       CheckThisIndexedPropertyHandler,
2378       CheckThisIndexedPropertySetter,
2379       CheckThisIndexedPropertyQuery,
2380       CheckThisIndexedPropertyDeleter,
2381       CheckThisIndexedPropertyEnumerator);
2382
2383   templ->InstanceTemplate()->SetNamedPropertyHandler(
2384       CheckThisNamedPropertyHandler,
2385       CheckThisNamedPropertySetter,
2386       CheckThisNamedPropertyQuery,
2387       CheckThisNamedPropertyDeleter,
2388       CheckThisNamedPropertyEnumerator);
2389
2390   bottom = templ->GetFunction()->NewInstance();
2391   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2392   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2393
2394   bottom->SetPrototype(middle);
2395   middle->SetPrototype(top);
2396   env->Global()->Set(v8_str("obj"), bottom);
2397
2398   // Indexed and named get.
2399   CompileRun("obj[0]");
2400   CompileRun("obj.x");
2401
2402   // Indexed and named set.
2403   CompileRun("obj[1] = 42");
2404   CompileRun("obj.y = 42");
2405
2406   // Indexed and named query.
2407   CompileRun("0 in obj");
2408   CompileRun("'x' in obj");
2409
2410   // Indexed and named deleter.
2411   CompileRun("delete obj[0]");
2412   CompileRun("delete obj.x");
2413
2414   // Enumerators.
2415   CompileRun("for (var p in obj) ;");
2416 }
2417
2418
2419 static void PrePropertyHandlerGet(
2420     Local<String> key,
2421     const v8::PropertyCallbackInfo<v8::Value>& info) {
2422   ApiTestFuzzer::Fuzz();
2423   if (v8_str("pre")->Equals(key)) {
2424     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2425   }
2426 }
2427
2428
2429 static void PrePropertyHandlerQuery(
2430     Local<String> key,
2431     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2432   if (v8_str("pre")->Equals(key)) {
2433     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2434   }
2435 }
2436
2437
2438 THREADED_TEST(PrePropertyHandler) {
2439   v8::Isolate* isolate = CcTest::isolate();
2440   v8::HandleScope scope(isolate);
2441   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2442   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2443                                                     0,
2444                                                     PrePropertyHandlerQuery);
2445   LocalContext env(NULL, desc->InstanceTemplate());
2446   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2447   v8::Handle<Value> result_pre = CompileRun("pre");
2448   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2449   v8::Handle<Value> result_on = CompileRun("on");
2450   CHECK_EQ(v8_str("Object: on"), result_on);
2451   v8::Handle<Value> result_post = CompileRun("post");
2452   CHECK(result_post.IsEmpty());
2453 }
2454
2455
2456 THREADED_TEST(UndefinedIsNotEnumerable) {
2457   LocalContext env;
2458   v8::HandleScope scope(env->GetIsolate());
2459   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2460   CHECK(result->IsFalse());
2461 }
2462
2463
2464 v8::Handle<Script> call_recursively_script;
2465 static const int kTargetRecursionDepth = 200;  // near maximum
2466
2467
2468 static void CallScriptRecursivelyCall(
2469     const v8::FunctionCallbackInfo<v8::Value>& args) {
2470   ApiTestFuzzer::Fuzz();
2471   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2472   if (depth == kTargetRecursionDepth) return;
2473   args.This()->Set(v8_str("depth"),
2474                    v8::Integer::New(args.GetIsolate(), depth + 1));
2475   args.GetReturnValue().Set(call_recursively_script->Run());
2476 }
2477
2478
2479 static void CallFunctionRecursivelyCall(
2480     const v8::FunctionCallbackInfo<v8::Value>& args) {
2481   ApiTestFuzzer::Fuzz();
2482   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2483   if (depth == kTargetRecursionDepth) {
2484     printf("[depth = %d]\n", depth);
2485     return;
2486   }
2487   args.This()->Set(v8_str("depth"),
2488                    v8::Integer::New(args.GetIsolate(), depth + 1));
2489   v8::Handle<Value> function =
2490       args.This()->Get(v8_str("callFunctionRecursively"));
2491   args.GetReturnValue().Set(
2492       function.As<Function>()->Call(args.This(), 0, NULL));
2493 }
2494
2495
2496 THREADED_TEST(DeepCrossLanguageRecursion) {
2497   v8::Isolate* isolate = CcTest::isolate();
2498   v8::HandleScope scope(isolate);
2499   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2500   global->Set(v8_str("callScriptRecursively"),
2501               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2502   global->Set(v8_str("callFunctionRecursively"),
2503               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2504   LocalContext env(NULL, global);
2505
2506   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2507   call_recursively_script = v8_compile("callScriptRecursively()");
2508   call_recursively_script->Run();
2509   call_recursively_script = v8::Handle<Script>();
2510
2511   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2512   CompileRun("callFunctionRecursively()");
2513 }
2514
2515
2516 static void ThrowingPropertyHandlerGet(
2517     Local<String> key,
2518     const v8::PropertyCallbackInfo<v8::Value>& info) {
2519   ApiTestFuzzer::Fuzz();
2520   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2521 }
2522
2523
2524 static void ThrowingPropertyHandlerSet(
2525     Local<String> key,
2526     Local<Value>,
2527     const v8::PropertyCallbackInfo<v8::Value>& info) {
2528   info.GetIsolate()->ThrowException(key);
2529   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2530 }
2531
2532
2533 THREADED_TEST(CallbackExceptionRegression) {
2534   v8::Isolate* isolate = CcTest::isolate();
2535   v8::HandleScope scope(isolate);
2536   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2537   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2538                                ThrowingPropertyHandlerSet);
2539   LocalContext env;
2540   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2541   v8::Handle<Value> otto = CompileRun(
2542       "try { with (obj) { otto; } } catch (e) { e; }");
2543   CHECK_EQ(v8_str("otto"), otto);
2544   v8::Handle<Value> netto = CompileRun(
2545       "try { with (obj) { netto = 4; } } catch (e) { e; }");
2546   CHECK_EQ(v8_str("netto"), netto);
2547 }
2548
2549
2550 THREADED_TEST(FunctionPrototype) {
2551   v8::Isolate* isolate = CcTest::isolate();
2552   v8::HandleScope scope(isolate);
2553   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2554   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2555   LocalContext env;
2556   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2557   Local<Script> script = v8_compile("Foo.prototype.plak");
2558   CHECK_EQ(script->Run()->Int32Value(), 321);
2559 }
2560
2561
2562 THREADED_TEST(InternalFields) {
2563   LocalContext env;
2564   v8::Isolate* isolate = env->GetIsolate();
2565   v8::HandleScope scope(isolate);
2566
2567   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2568   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2569   instance_templ->SetInternalFieldCount(1);
2570   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2571   CHECK_EQ(1, obj->InternalFieldCount());
2572   CHECK(obj->GetInternalField(0)->IsUndefined());
2573   obj->SetInternalField(0, v8_num(17));
2574   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2575 }
2576
2577
2578 THREADED_TEST(GlobalObjectInternalFields) {
2579   v8::Isolate* isolate = CcTest::isolate();
2580   v8::HandleScope scope(isolate);
2581   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2582   global_template->SetInternalFieldCount(1);
2583   LocalContext env(NULL, global_template);
2584   v8::Handle<v8::Object> global_proxy = env->Global();
2585   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2586   CHECK_EQ(1, global->InternalFieldCount());
2587   CHECK(global->GetInternalField(0)->IsUndefined());
2588   global->SetInternalField(0, v8_num(17));
2589   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2590 }
2591
2592
2593 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2594   LocalContext env;
2595   v8::HandleScope scope(CcTest::isolate());
2596
2597   v8::Local<v8::Object> global = env->Global();
2598   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2599   CHECK(global->HasRealIndexedProperty(0));
2600 }
2601
2602
2603 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2604                                                void* value) {
2605   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2606   obj->SetAlignedPointerInInternalField(0, value);
2607   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2608   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2609 }
2610
2611
2612 THREADED_TEST(InternalFieldsAlignedPointers) {
2613   LocalContext env;
2614   v8::Isolate* isolate = env->GetIsolate();
2615   v8::HandleScope scope(isolate);
2616
2617   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2618   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2619   instance_templ->SetInternalFieldCount(1);
2620   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2621   CHECK_EQ(1, obj->InternalFieldCount());
2622
2623   CheckAlignedPointerInInternalField(obj, NULL);
2624
2625   int* heap_allocated = new int[100];
2626   CheckAlignedPointerInInternalField(obj, heap_allocated);
2627   delete[] heap_allocated;
2628
2629   int stack_allocated[100];
2630   CheckAlignedPointerInInternalField(obj, stack_allocated);
2631
2632   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2633   CheckAlignedPointerInInternalField(obj, huge);
2634
2635   v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2636   CHECK_EQ(1, Object::InternalFieldCount(persistent));
2637   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2638 }
2639
2640
2641 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2642                                               int index,
2643                                               void* value) {
2644   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2645   (*env)->SetAlignedPointerInEmbedderData(index, value);
2646   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2647   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2648 }
2649
2650
2651 static void* AlignedTestPointer(int i) {
2652   return reinterpret_cast<void*>(i * 1234);
2653 }
2654
2655
2656 THREADED_TEST(EmbedderDataAlignedPointers) {
2657   LocalContext env;
2658   v8::HandleScope scope(env->GetIsolate());
2659
2660   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2661
2662   int* heap_allocated = new int[100];
2663   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2664   delete[] heap_allocated;
2665
2666   int stack_allocated[100];
2667   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2668
2669   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2670   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2671
2672   // Test growing of the embedder data's backing store.
2673   for (int i = 0; i < 100; i++) {
2674     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2675   }
2676   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2677   for (int i = 0; i < 100; i++) {
2678     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2679   }
2680 }
2681
2682
2683 static void CheckEmbedderData(LocalContext* env,
2684                               int index,
2685                               v8::Handle<Value> data) {
2686   (*env)->SetEmbedderData(index, data);
2687   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2688 }
2689
2690
2691 THREADED_TEST(EmbedderData) {
2692   LocalContext env;
2693   v8::Isolate* isolate = env->GetIsolate();
2694   v8::HandleScope scope(isolate);
2695
2696   CheckEmbedderData(
2697       &env, 3,
2698       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2699   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2700                                                      "over the lazy dog."));
2701   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2702   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2703 }
2704
2705
2706 THREADED_TEST(IdentityHash) {
2707   LocalContext env;
2708   v8::Isolate* isolate = env->GetIsolate();
2709   v8::HandleScope scope(isolate);
2710
2711   // Ensure that the test starts with an fresh heap to test whether the hash
2712   // code is based on the address.
2713   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2714   Local<v8::Object> obj = v8::Object::New(isolate);
2715   int hash = obj->GetIdentityHash();
2716   int hash1 = obj->GetIdentityHash();
2717   CHECK_EQ(hash, hash1);
2718   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2719   // Since the identity hash is essentially a random number two consecutive
2720   // objects should not be assigned the same hash code. If the test below fails
2721   // the random number generator should be evaluated.
2722   CHECK_NE(hash, hash2);
2723   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2724   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2725   // Make sure that the identity hash is not based on the initial address of
2726   // the object alone. If the test below fails the random number generator
2727   // should be evaluated.
2728   CHECK_NE(hash, hash3);
2729   int hash4 = obj->GetIdentityHash();
2730   CHECK_EQ(hash, hash4);
2731
2732   // Check identity hashes behaviour in the presence of JS accessors.
2733   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2734   {
2735     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2736     Local<v8::Object> o1 = v8::Object::New(isolate);
2737     Local<v8::Object> o2 = v8::Object::New(isolate);
2738     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2739   }
2740   {
2741     CompileRun(
2742         "function cnst() { return 42; };\n"
2743         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2744     Local<v8::Object> o1 = v8::Object::New(isolate);
2745     Local<v8::Object> o2 = v8::Object::New(isolate);
2746     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2747   }
2748 }
2749
2750
2751 THREADED_TEST(SymbolProperties) {
2752   i::FLAG_harmony_symbols = true;
2753
2754   LocalContext env;
2755   v8::Isolate* isolate = env->GetIsolate();
2756   v8::HandleScope scope(isolate);
2757
2758   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2759   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2760   v8::Local<v8::Symbol> sym2 =
2761       v8::Symbol::New(isolate, v8_str("my-symbol"));
2762
2763   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2764
2765   // Check basic symbol functionality.
2766   CHECK(sym1->IsSymbol());
2767   CHECK(sym2->IsSymbol());
2768   CHECK(!obj->IsSymbol());
2769
2770   CHECK(sym1->Equals(sym1));
2771   CHECK(sym2->Equals(sym2));
2772   CHECK(!sym1->Equals(sym2));
2773   CHECK(!sym2->Equals(sym1));
2774   CHECK(sym1->StrictEquals(sym1));
2775   CHECK(sym2->StrictEquals(sym2));
2776   CHECK(!sym1->StrictEquals(sym2));
2777   CHECK(!sym2->StrictEquals(sym1));
2778
2779   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2780
2781   v8::Local<v8::Value> sym_val = sym2;
2782   CHECK(sym_val->IsSymbol());
2783   CHECK(sym_val->Equals(sym2));
2784   CHECK(sym_val->StrictEquals(sym2));
2785   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2786
2787   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2788   CHECK(sym_obj->IsSymbolObject());
2789   CHECK(!sym2->IsSymbolObject());
2790   CHECK(!obj->IsSymbolObject());
2791   CHECK(!sym_obj->Equals(sym2));
2792   CHECK(!sym_obj->StrictEquals(sym2));
2793   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2794   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2795
2796   // Make sure delete of a non-existent symbol property works.
2797   CHECK(obj->Delete(sym1));
2798   CHECK(!obj->Has(sym1));
2799
2800   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2801   CHECK(obj->Has(sym1));
2802   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2803   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2804   CHECK(obj->Has(sym1));
2805   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2806   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2807
2808   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2809   int num_props = obj->GetPropertyNames()->Length();
2810   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2811                  v8::Integer::New(isolate, 20)));
2812   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2813   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2814
2815   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2816
2817   // Add another property and delete it afterwards to force the object in
2818   // slow case.
2819   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2820   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2821   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2822   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2823   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2824
2825   CHECK(obj->Has(sym1));
2826   CHECK(obj->Has(sym2));
2827   CHECK(obj->Delete(sym2));
2828   CHECK(obj->Has(sym1));
2829   CHECK(!obj->Has(sym2));
2830   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2831   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2832
2833   // Symbol properties are inherited.
2834   v8::Local<v8::Object> child = v8::Object::New(isolate);
2835   child->SetPrototype(obj);
2836   CHECK(child->Has(sym1));
2837   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2838   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2839 }
2840
2841
2842 THREADED_TEST(PrivateProperties) {
2843   LocalContext env;
2844   v8::Isolate* isolate = env->GetIsolate();
2845   v8::HandleScope scope(isolate);
2846
2847   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2848   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2849   v8::Local<v8::Private> priv2 =
2850       v8::Private::New(isolate, v8_str("my-private"));
2851
2852   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2853
2854   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2855
2856   // Make sure delete of a non-existent private symbol property works.
2857   CHECK(obj->DeletePrivate(priv1));
2858   CHECK(!obj->HasPrivate(priv1));
2859
2860   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2861   CHECK(obj->HasPrivate(priv1));
2862   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2863   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2864   CHECK(obj->HasPrivate(priv1));
2865   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2866
2867   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2868   int num_props = obj->GetPropertyNames()->Length();
2869   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2870                  v8::Integer::New(isolate, 20)));
2871   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2872   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2873
2874   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2875
2876   // Add another property and delete it afterwards to force the object in
2877   // slow case.
2878   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2879   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2880   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2881   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2882   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2883
2884   CHECK(obj->HasPrivate(priv1));
2885   CHECK(obj->HasPrivate(priv2));
2886   CHECK(obj->DeletePrivate(priv2));
2887   CHECK(obj->HasPrivate(priv1));
2888   CHECK(!obj->HasPrivate(priv2));
2889   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2890   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2891
2892   // Private properties are inherited (for the time being).
2893   v8::Local<v8::Object> child = v8::Object::New(isolate);
2894   child->SetPrototype(obj);
2895   CHECK(child->HasPrivate(priv1));
2896   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2897   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2898 }
2899
2900
2901 THREADED_TEST(GlobalSymbols) {
2902   i::FLAG_harmony_symbols = true;
2903
2904   LocalContext env;
2905   v8::Isolate* isolate = env->GetIsolate();
2906   v8::HandleScope scope(isolate);
2907
2908   v8::Local<String> name = v8_str("my-symbol");
2909   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2910   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2911   CHECK(glob2->SameValue(glob));
2912
2913   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2914   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2915   CHECK(glob_api2->SameValue(glob_api));
2916   CHECK(!glob_api->SameValue(glob));
2917
2918   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2919   CHECK(!sym->SameValue(glob));
2920
2921   CompileRun("var sym2 = Symbol.for('my-symbol')");
2922   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2923   CHECK(sym2->SameValue(glob));
2924   CHECK(!sym2->SameValue(glob_api));
2925 }
2926
2927
2928 THREADED_TEST(GlobalPrivates) {
2929   LocalContext env;
2930   v8::Isolate* isolate = env->GetIsolate();
2931   v8::HandleScope scope(isolate);
2932
2933   v8::Local<String> name = v8_str("my-private");
2934   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2935   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2936   CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2937
2938   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2939   CHECK(obj->HasPrivate(glob2));
2940
2941   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2942   CHECK(!obj->HasPrivate(priv));
2943
2944   CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2945   v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2946   CHECK(!obj->Has(intern));
2947 }
2948
2949
2950 class ScopedArrayBufferContents {
2951  public:
2952   explicit ScopedArrayBufferContents(
2953       const v8::ArrayBuffer::Contents& contents)
2954     : contents_(contents) {}
2955   ~ScopedArrayBufferContents() { free(contents_.Data()); }
2956   void* Data() const { return contents_.Data(); }
2957   size_t ByteLength() const { return contents_.ByteLength(); }
2958  private:
2959   const v8::ArrayBuffer::Contents contents_;
2960 };
2961
2962 template <typename T>
2963 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2964   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2965   for (int i = 0; i < value->InternalFieldCount(); i++) {
2966     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2967   }
2968 }
2969
2970
2971 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2972   LocalContext env;
2973   v8::Isolate* isolate = env->GetIsolate();
2974   v8::HandleScope handle_scope(isolate);
2975
2976   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2977   CheckInternalFieldsAreZero(ab);
2978   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2979   CHECK(!ab->IsExternal());
2980   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2981
2982   ScopedArrayBufferContents ab_contents(ab->Externalize());
2983   CHECK(ab->IsExternal());
2984
2985   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2986   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2987   ASSERT(data != NULL);
2988   env->Global()->Set(v8_str("ab"), ab);
2989
2990   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2991   CHECK_EQ(1024, result->Int32Value());
2992
2993   result = CompileRun("var u8 = new Uint8Array(ab);"
2994                       "u8[0] = 0xFF;"
2995                       "u8[1] = 0xAA;"
2996                       "u8.length");
2997   CHECK_EQ(1024, result->Int32Value());
2998   CHECK_EQ(0xFF, data[0]);
2999   CHECK_EQ(0xAA, data[1]);
3000   data[0] = 0xCC;
3001   data[1] = 0x11;
3002   result = CompileRun("u8[0] + u8[1]");
3003   CHECK_EQ(0xDD, result->Int32Value());
3004 }
3005
3006
3007 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3008   LocalContext env;
3009   v8::Isolate* isolate = env->GetIsolate();
3010   v8::HandleScope handle_scope(isolate);
3011
3012
3013   v8::Local<v8::Value> result =
3014       CompileRun("var ab1 = new ArrayBuffer(2);"
3015                  "var u8_a = new Uint8Array(ab1);"
3016                  "u8_a[0] = 0xAA;"
3017                  "u8_a[1] = 0xFF; u8_a.buffer");
3018   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3019   CheckInternalFieldsAreZero(ab1);
3020   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3021   CHECK(!ab1->IsExternal());
3022   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3023   CHECK(ab1->IsExternal());
3024
3025   result = CompileRun("ab1.byteLength");
3026   CHECK_EQ(2, result->Int32Value());
3027   result = CompileRun("u8_a[0]");
3028   CHECK_EQ(0xAA, result->Int32Value());
3029   result = CompileRun("u8_a[1]");
3030   CHECK_EQ(0xFF, result->Int32Value());
3031   result = CompileRun("var u8_b = new Uint8Array(ab1);"
3032                       "u8_b[0] = 0xBB;"
3033                       "u8_a[0]");
3034   CHECK_EQ(0xBB, result->Int32Value());
3035   result = CompileRun("u8_b[1]");
3036   CHECK_EQ(0xFF, result->Int32Value());
3037
3038   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3039   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3040   CHECK_EQ(0xBB, ab1_data[0]);
3041   CHECK_EQ(0xFF, ab1_data[1]);
3042   ab1_data[0] = 0xCC;
3043   ab1_data[1] = 0x11;
3044   result = CompileRun("u8_a[0] + u8_a[1]");
3045   CHECK_EQ(0xDD, result->Int32Value());
3046 }
3047
3048
3049 THREADED_TEST(ArrayBuffer_External) {
3050   LocalContext env;
3051   v8::Isolate* isolate = env->GetIsolate();
3052   v8::HandleScope handle_scope(isolate);
3053
3054   i::ScopedVector<uint8_t> my_data(100);
3055   memset(my_data.start(), 0, 100);
3056   Local<v8::ArrayBuffer> ab3 =
3057       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3058   CheckInternalFieldsAreZero(ab3);
3059   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3060   CHECK(ab3->IsExternal());
3061
3062   env->Global()->Set(v8_str("ab3"), ab3);
3063
3064   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3065   CHECK_EQ(100, result->Int32Value());
3066
3067   result = CompileRun("var u8_b = new Uint8Array(ab3);"
3068                       "u8_b[0] = 0xBB;"
3069                       "u8_b[1] = 0xCC;"
3070                       "u8_b.length");
3071   CHECK_EQ(100, result->Int32Value());
3072   CHECK_EQ(0xBB, my_data[0]);
3073   CHECK_EQ(0xCC, my_data[1]);
3074   my_data[0] = 0xCC;
3075   my_data[1] = 0x11;
3076   result = CompileRun("u8_b[0] + u8_b[1]");
3077   CHECK_EQ(0xDD, result->Int32Value());
3078 }
3079
3080
3081 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3082   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3083   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3084 }
3085
3086
3087 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3088   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3089   CHECK_EQ(0, static_cast<int>(ta->Length()));
3090   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3091 }
3092
3093
3094 static void CheckIsTypedArrayVarNeutered(const char* name) {
3095   i::ScopedVector<char> source(1024);
3096   i::OS::SNPrintF(source,
3097       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3098       name, name, name);
3099   CHECK(CompileRun(source.start())->IsTrue());
3100   v8::Handle<v8::TypedArray> ta =
3101     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3102   CheckIsNeutered(ta);
3103 }
3104
3105
3106 template <typename TypedArray, int kElementSize>
3107 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3108                                          int byteOffset,
3109                                          int length) {
3110   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3111   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3112   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3113   CHECK_EQ(length, static_cast<int>(ta->Length()));
3114   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3115   return ta;
3116 }
3117
3118
3119 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3120   LocalContext env;
3121   v8::Isolate* isolate = env->GetIsolate();
3122   v8::HandleScope handle_scope(isolate);
3123
3124   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3125
3126   v8::Handle<v8::Uint8Array> u8a =
3127     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3128   v8::Handle<v8::Uint8ClampedArray> u8c =
3129     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3130   v8::Handle<v8::Int8Array> i8a =
3131     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3132
3133   v8::Handle<v8::Uint16Array> u16a =
3134     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3135   v8::Handle<v8::Int16Array> i16a =
3136     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3137
3138   v8::Handle<v8::Uint32Array> u32a =
3139     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3140   v8::Handle<v8::Int32Array> i32a =
3141     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3142
3143   v8::Handle<v8::Float32Array> f32a =
3144     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3145   v8::Handle<v8::Float64Array> f64a =
3146     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3147
3148   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3149   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3150   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3151   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3152
3153   ScopedArrayBufferContents contents(buffer->Externalize());
3154   buffer->Neuter();
3155   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3156   CheckIsNeutered(u8a);
3157   CheckIsNeutered(u8c);
3158   CheckIsNeutered(i8a);
3159   CheckIsNeutered(u16a);
3160   CheckIsNeutered(i16a);
3161   CheckIsNeutered(u32a);
3162   CheckIsNeutered(i32a);
3163   CheckIsNeutered(f32a);
3164   CheckIsNeutered(f64a);
3165   CheckDataViewIsNeutered(dv);
3166 }
3167
3168
3169 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3170   LocalContext env;
3171   v8::Isolate* isolate = env->GetIsolate();
3172   v8::HandleScope handle_scope(isolate);
3173
3174   CompileRun(
3175       "var ab = new ArrayBuffer(1024);"
3176       "var u8a = new Uint8Array(ab, 1, 1023);"
3177       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3178       "var i8a = new Int8Array(ab, 1, 1023);"
3179       "var u16a = new Uint16Array(ab, 2, 511);"
3180       "var i16a = new Int16Array(ab, 2, 511);"
3181       "var u32a = new Uint32Array(ab, 4, 255);"
3182       "var i32a = new Int32Array(ab, 4, 255);"
3183       "var f32a = new Float32Array(ab, 4, 255);"
3184       "var f64a = new Float64Array(ab, 8, 127);"
3185       "var dv = new DataView(ab, 1, 1023);");
3186
3187   v8::Handle<v8::ArrayBuffer> ab =
3188       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3189
3190   v8::Handle<v8::DataView> dv =
3191     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3192
3193   ScopedArrayBufferContents contents(ab->Externalize());
3194   ab->Neuter();
3195   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3196   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3197
3198   CheckIsTypedArrayVarNeutered("u8a");
3199   CheckIsTypedArrayVarNeutered("u8c");
3200   CheckIsTypedArrayVarNeutered("i8a");
3201   CheckIsTypedArrayVarNeutered("u16a");
3202   CheckIsTypedArrayVarNeutered("i16a");
3203   CheckIsTypedArrayVarNeutered("u32a");
3204   CheckIsTypedArrayVarNeutered("i32a");
3205   CheckIsTypedArrayVarNeutered("f32a");
3206   CheckIsTypedArrayVarNeutered("f64a");
3207
3208   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3209   CheckDataViewIsNeutered(dv);
3210 }
3211
3212
3213
3214 THREADED_TEST(HiddenProperties) {
3215   LocalContext env;
3216   v8::Isolate* isolate = env->GetIsolate();
3217   v8::HandleScope scope(isolate);
3218
3219   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3220   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3221   v8::Local<v8::String> empty = v8_str("");
3222   v8::Local<v8::String> prop_name = v8_str("prop_name");
3223
3224   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3225
3226   // Make sure delete of a non-existent hidden value works
3227   CHECK(obj->DeleteHiddenValue(key));
3228
3229   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3230   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3231   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3232   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3233
3234   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3235
3236   // Make sure we do not find the hidden property.
3237   CHECK(!obj->Has(empty));
3238   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3239   CHECK(obj->Get(empty)->IsUndefined());
3240   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3241   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3242   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3243   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3244
3245   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3246
3247   // Add another property and delete it afterwards to force the object in
3248   // slow case.
3249   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3250   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3251   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3252   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3253   CHECK(obj->Delete(prop_name));
3254   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3255
3256   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3257
3258   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3259   CHECK(obj->GetHiddenValue(key).IsEmpty());
3260
3261   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3262   CHECK(obj->DeleteHiddenValue(key));
3263   CHECK(obj->GetHiddenValue(key).IsEmpty());
3264 }
3265
3266
3267 THREADED_TEST(Regress97784) {
3268   // Regression test for crbug.com/97784
3269   // Messing with the Object.prototype should not have effect on
3270   // hidden properties.
3271   LocalContext env;
3272   v8::HandleScope scope(env->GetIsolate());
3273
3274   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3275   v8::Local<v8::String> key = v8_str("hidden");
3276
3277   CompileRun(
3278       "set_called = false;"
3279       "Object.defineProperty("
3280       "    Object.prototype,"
3281       "    'hidden',"
3282       "    {get: function() { return 45; },"
3283       "     set: function() { set_called = true; }})");
3284
3285   CHECK(obj->GetHiddenValue(key).IsEmpty());
3286   // Make sure that the getter and setter from Object.prototype is not invoked.
3287   // If it did we would have full access to the hidden properties in
3288   // the accessor.
3289   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3290   ExpectFalse("set_called");
3291   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3292 }
3293
3294
3295 static bool interceptor_for_hidden_properties_called;
3296 static void InterceptorForHiddenProperties(
3297     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3298   interceptor_for_hidden_properties_called = true;
3299 }
3300
3301
3302 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3303   LocalContext context;
3304   v8::Isolate* isolate = context->GetIsolate();
3305   v8::HandleScope scope(isolate);
3306
3307   interceptor_for_hidden_properties_called = false;
3308
3309   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3310
3311   // Associate an interceptor with an object and start setting hidden values.
3312   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3313   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3314   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3315   Local<v8::Function> function = fun_templ->GetFunction();
3316   Local<v8::Object> obj = function->NewInstance();
3317   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3318   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3319   CHECK(!interceptor_for_hidden_properties_called);
3320 }
3321
3322
3323 THREADED_TEST(External) {
3324   v8::HandleScope scope(CcTest::isolate());
3325   int x = 3;
3326   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3327   LocalContext env;
3328   env->Global()->Set(v8_str("ext"), ext);
3329   Local<Value> reext_obj = CompileRun("this.ext");
3330   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3331   int* ptr = static_cast<int*>(reext->Value());
3332   CHECK_EQ(x, 3);
3333   *ptr = 10;
3334   CHECK_EQ(x, 10);
3335
3336   // Make sure unaligned pointers are wrapped properly.
3337   char* data = i::StrDup("0123456789");
3338   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3339   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3340   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3341   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3342
3343   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3344   CHECK_EQ('0', *char_ptr);
3345   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3346   CHECK_EQ('1', *char_ptr);
3347   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3348   CHECK_EQ('2', *char_ptr);
3349   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3350   CHECK_EQ('3', *char_ptr);
3351   i::DeleteArray(data);
3352 }
3353
3354
3355 THREADED_TEST(GlobalHandle) {
3356   v8::Isolate* isolate = CcTest::isolate();
3357   v8::Persistent<String> global;
3358   {
3359     v8::HandleScope scope(isolate);
3360     global.Reset(isolate, v8_str("str"));
3361   }
3362   {
3363     v8::HandleScope scope(isolate);
3364     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3365   }
3366   global.Reset();
3367   {
3368     v8::HandleScope scope(isolate);
3369     global.Reset(isolate, v8_str("str"));
3370   }
3371   {
3372     v8::HandleScope scope(isolate);
3373     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3374   }
3375   global.Reset();
3376 }
3377
3378
3379 THREADED_TEST(ResettingGlobalHandle) {
3380   v8::Isolate* isolate = CcTest::isolate();
3381   v8::Persistent<String> global;
3382   {
3383     v8::HandleScope scope(isolate);
3384     global.Reset(isolate, v8_str("str"));
3385   }
3386   v8::internal::GlobalHandles* global_handles =
3387       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3388   int initial_handle_count = global_handles->global_handles_count();
3389   {
3390     v8::HandleScope scope(isolate);
3391     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3392   }
3393   {
3394     v8::HandleScope scope(isolate);
3395     global.Reset(isolate, v8_str("longer"));
3396   }
3397   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3398   {
3399     v8::HandleScope scope(isolate);
3400     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3401   }
3402   global.Reset();
3403   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3404 }
3405
3406
3407 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3408   v8::Isolate* isolate = CcTest::isolate();
3409   v8::Persistent<String> global;
3410   {
3411     v8::HandleScope scope(isolate);
3412     global.Reset(isolate, v8_str("str"));
3413   }
3414   v8::internal::GlobalHandles* global_handles =
3415       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3416   int initial_handle_count = global_handles->global_handles_count();
3417   {
3418     v8::HandleScope scope(isolate);
3419     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3420   }
3421   {
3422     v8::HandleScope scope(isolate);
3423     Local<String> empty;
3424     global.Reset(isolate, empty);
3425   }
3426   CHECK(global.IsEmpty());
3427   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3428 }
3429
3430
3431 template<class T>
3432 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3433   return unique.Pass();
3434 }
3435
3436
3437 template<class T>
3438 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3439                                             const v8::Persistent<T> & global) {
3440   v8::UniquePersistent<String> unique(isolate, global);
3441   return unique.Pass();
3442 }
3443
3444
3445 THREADED_TEST(UniquePersistent) {
3446   v8::Isolate* isolate = CcTest::isolate();
3447   v8::Persistent<String> global;
3448   {
3449     v8::HandleScope scope(isolate);
3450     global.Reset(isolate, v8_str("str"));
3451   }
3452   v8::internal::GlobalHandles* global_handles =
3453       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3454   int initial_handle_count = global_handles->global_handles_count();
3455   {
3456     v8::UniquePersistent<String> unique(isolate, global);
3457     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3458     // Test assignment via Pass
3459     {
3460       v8::UniquePersistent<String> copy = unique.Pass();
3461       CHECK(unique.IsEmpty());
3462       CHECK(copy == global);
3463       CHECK_EQ(initial_handle_count + 1,
3464                global_handles->global_handles_count());
3465       unique = copy.Pass();
3466     }
3467     // Test ctor via Pass
3468     {
3469       v8::UniquePersistent<String> copy(unique.Pass());
3470       CHECK(unique.IsEmpty());
3471       CHECK(copy == global);
3472       CHECK_EQ(initial_handle_count + 1,
3473                global_handles->global_handles_count());
3474       unique = copy.Pass();
3475     }
3476     // Test pass through function call
3477     {
3478       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3479       CHECK(unique.IsEmpty());
3480       CHECK(copy == global);
3481       CHECK_EQ(initial_handle_count + 1,
3482                global_handles->global_handles_count());
3483       unique = copy.Pass();
3484     }
3485     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3486   }
3487   // Test pass from function call
3488   {
3489     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3490     CHECK(unique == global);
3491     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3492   }
3493   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3494   global.Reset();
3495 }
3496
3497
3498 template<typename K, typename V>
3499 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3500  public:
3501   typedef typename v8::DefaultPersistentValueMapTraits<K, V>::Impl Impl;
3502   static const bool kIsWeak = true;
3503   struct WeakCallbackDataType {
3504     Impl* impl;
3505     K key;
3506   };
3507   static WeakCallbackDataType* WeakCallbackParameter(
3508       Impl* impl, const K& key, Local<V> value) {
3509     WeakCallbackDataType* data = new WeakCallbackDataType;
3510     data->impl = impl;
3511     data->key = key;
3512     return data;
3513   }
3514   static Impl* ImplFromWeakCallbackData(
3515       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3516     return data.GetParameter()->impl;
3517   }
3518   static K KeyFromWeakCallbackData(
3519       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3520     return data.GetParameter()->key;
3521   }
3522   static void DisposeCallbackData(WeakCallbackDataType* data) {
3523     delete data;
3524   }
3525   static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3526       Impl* impl, K key) { }
3527 };
3528
3529
3530 template<typename Map>
3531 static void TestPersistentValueMap() {
3532   LocalContext env;
3533   v8::Isolate* isolate = env->GetIsolate();
3534   Map map(isolate);
3535   v8::internal::GlobalHandles* global_handles =
3536       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3537   int initial_handle_count = global_handles->global_handles_count();
3538   CHECK_EQ(0, static_cast<int>(map.Size()));
3539   {
3540     HandleScope scope(isolate);
3541     Local<v8::Object> obj = map.Get(7);
3542     CHECK(obj.IsEmpty());
3543     Local<v8::Object> expected = v8::Object::New(isolate);
3544     map.Set(7, expected);
3545     CHECK_EQ(1, static_cast<int>(map.Size()));
3546     obj = map.Get(7);
3547     CHECK_EQ(expected, obj);
3548     v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3549     CHECK_EQ(0, static_cast<int>(map.Size()));
3550     CHECK(expected == removed);
3551     removed = map.Remove(7);
3552     CHECK(removed.IsEmpty());
3553     map.Set(8, expected);
3554     CHECK_EQ(1, static_cast<int>(map.Size()));
3555     map.Set(8, expected);
3556     CHECK_EQ(1, static_cast<int>(map.Size()));
3557   }
3558   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3559   if (map.IsWeak()) {
3560     reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3561         CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3562   } else {
3563     map.Clear();
3564   }
3565   CHECK_EQ(0, static_cast<int>(map.Size()));
3566   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3567 }
3568
3569
3570 TEST(PersistentValueMap) {
3571   // Default case, w/o weak callbacks:
3572   TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3573
3574   // Custom traits with weak callbacks:
3575   typedef v8::StdPersistentValueMap<int, v8::Object,
3576       WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3577   TestPersistentValueMap<WeakPersistentValueMap>();
3578 }
3579
3580
3581 THREADED_TEST(GlobalHandleUpcast) {
3582   v8::Isolate* isolate = CcTest::isolate();
3583   v8::HandleScope scope(isolate);
3584   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3585   v8::Persistent<String> global_string(isolate, local);
3586   v8::Persistent<Value>& global_value =
3587       v8::Persistent<Value>::Cast(global_string);
3588   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3589   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3590   global_string.Reset();
3591 }
3592
3593
3594 THREADED_TEST(HandleEquality) {
3595   v8::Isolate* isolate = CcTest::isolate();
3596   v8::Persistent<String> global1;
3597   v8::Persistent<String> global2;
3598   {
3599     v8::HandleScope scope(isolate);
3600     global1.Reset(isolate, v8_str("str"));
3601     global2.Reset(isolate, v8_str("str2"));
3602   }
3603   CHECK_EQ(global1 == global1, true);
3604   CHECK_EQ(global1 != global1, false);
3605   {
3606     v8::HandleScope scope(isolate);
3607     Local<String> local1 = Local<String>::New(isolate, global1);
3608     Local<String> local2 = Local<String>::New(isolate, global2);
3609
3610     CHECK_EQ(global1 == local1, true);
3611     CHECK_EQ(global1 != local1, false);
3612     CHECK_EQ(local1 == global1, true);
3613     CHECK_EQ(local1 != global1, false);
3614
3615     CHECK_EQ(global1 == local2, false);
3616     CHECK_EQ(global1 != local2, true);
3617     CHECK_EQ(local2 == global1, false);
3618     CHECK_EQ(local2 != global1, true);
3619
3620     CHECK_EQ(local1 == local2, false);
3621     CHECK_EQ(local1 != local2, true);
3622
3623     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3624     CHECK_EQ(local1 == anotherLocal1, true);
3625     CHECK_EQ(local1 != anotherLocal1, false);
3626   }
3627   global1.Reset();
3628   global2.Reset();
3629 }
3630
3631
3632 THREADED_TEST(LocalHandle) {
3633   v8::HandleScope scope(CcTest::isolate());
3634   v8::Local<String> local =
3635       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3636   CHECK_EQ(local->Length(), 3);
3637 }
3638
3639
3640 class WeakCallCounter {
3641  public:
3642   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3643   int id() { return id_; }
3644   void increment() { number_of_weak_calls_++; }
3645   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3646  private:
3647   int id_;
3648   int number_of_weak_calls_;
3649 };
3650
3651
3652 template<typename T>
3653 struct WeakCallCounterAndPersistent {
3654   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3655       : counter(counter) {}
3656   WeakCallCounter* counter;
3657   v8::Persistent<T> handle;
3658 };
3659
3660
3661 template <typename T>
3662 static void WeakPointerCallback(
3663     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3664   CHECK_EQ(1234, data.GetParameter()->counter->id());
3665   data.GetParameter()->counter->increment();
3666   data.GetParameter()->handle.Reset();
3667 }
3668
3669
3670 template<typename T>
3671 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3672   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3673 }
3674
3675
3676 THREADED_TEST(ApiObjectGroups) {
3677   LocalContext env;
3678   v8::Isolate* iso = env->GetIsolate();
3679   HandleScope scope(iso);
3680
3681   WeakCallCounter counter(1234);
3682
3683   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3684   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3685   WeakCallCounterAndPersistent<Value> g1c1(&counter);
3686   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3687   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3688   WeakCallCounterAndPersistent<Value> g2c1(&counter);
3689
3690   {
3691     HandleScope scope(iso);
3692     g1s1.handle.Reset(iso, Object::New(iso));
3693     g1s2.handle.Reset(iso, Object::New(iso));
3694     g1c1.handle.Reset(iso, Object::New(iso));
3695     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3696     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3697     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3698
3699     g2s1.handle.Reset(iso, Object::New(iso));
3700     g2s2.handle.Reset(iso, Object::New(iso));
3701     g2c1.handle.Reset(iso, Object::New(iso));
3702     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3703     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3704     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3705   }
3706
3707   WeakCallCounterAndPersistent<Value> root(&counter);
3708   root.handle.Reset(iso, g1s1.handle);  // make a root.
3709
3710   // Connect group 1 and 2, make a cycle.
3711   {
3712     HandleScope scope(iso);
3713     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3714             Set(0, Local<Value>::New(iso, g2s2.handle)));
3715     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3716             Set(0, Local<Value>::New(iso, g1s1.handle)));
3717   }
3718
3719   {
3720     UniqueId id1 = MakeUniqueId(g1s1.handle);
3721     UniqueId id2 = MakeUniqueId(g2s2.handle);
3722     iso->SetObjectGroupId(g1s1.handle, id1);
3723     iso->SetObjectGroupId(g1s2.handle, id1);
3724     iso->SetReferenceFromGroup(id1, g1c1.handle);
3725     iso->SetObjectGroupId(g2s1.handle, id2);
3726     iso->SetObjectGroupId(g2s2.handle, id2);
3727     iso->SetReferenceFromGroup(id2, g2c1.handle);
3728   }
3729   // Do a single full GC, ensure incremental marking is stopped.
3730   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3731       iso)->heap();
3732   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3733
3734   // All object should be alive.
3735   CHECK_EQ(0, counter.NumberOfWeakCalls());
3736
3737   // Weaken the root.
3738   root.handle.SetWeak(&root, &WeakPointerCallback);
3739   // But make children strong roots---all the objects (except for children)
3740   // should be collectable now.
3741   g1c1.handle.ClearWeak();
3742   g2c1.handle.ClearWeak();
3743
3744   // Groups are deleted, rebuild groups.
3745   {
3746     UniqueId id1 = MakeUniqueId(g1s1.handle);
3747     UniqueId id2 = MakeUniqueId(g2s2.handle);
3748     iso->SetObjectGroupId(g1s1.handle, id1);
3749     iso->SetObjectGroupId(g1s2.handle, id1);
3750     iso->SetReferenceFromGroup(id1, g1c1.handle);
3751     iso->SetObjectGroupId(g2s1.handle, id2);
3752     iso->SetObjectGroupId(g2s2.handle, id2);
3753     iso->SetReferenceFromGroup(id2, g2c1.handle);
3754   }
3755
3756   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3757
3758   // All objects should be gone. 5 global handles in total.
3759   CHECK_EQ(5, counter.NumberOfWeakCalls());
3760
3761   // And now make children weak again and collect them.
3762   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3763   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3764
3765   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3766   CHECK_EQ(7, counter.NumberOfWeakCalls());
3767 }
3768
3769
3770 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3771   LocalContext env;
3772   v8::Isolate* iso = env->GetIsolate();
3773   HandleScope scope(iso);
3774
3775   WeakCallCounter counter(1234);
3776
3777   WeakCallCounterAndPersistent<Object> g1s1(&counter);
3778   WeakCallCounterAndPersistent<String> g1s2(&counter);
3779   WeakCallCounterAndPersistent<String> g1c1(&counter);
3780   WeakCallCounterAndPersistent<Object> g2s1(&counter);
3781   WeakCallCounterAndPersistent<String> g2s2(&counter);
3782   WeakCallCounterAndPersistent<String> g2c1(&counter);
3783
3784   {
3785     HandleScope scope(iso);
3786     g1s1.handle.Reset(iso, Object::New(iso));
3787     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3788     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3789     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3790     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3791     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3792
3793     g2s1.handle.Reset(iso, Object::New(iso));
3794     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3795     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3796     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3797     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3798     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3799   }
3800
3801   WeakCallCounterAndPersistent<Value> root(&counter);
3802   root.handle.Reset(iso, g1s1.handle);  // make a root.
3803
3804   // Connect group 1 and 2, make a cycle.
3805   {
3806     HandleScope scope(iso);
3807     CHECK(Local<Object>::New(iso, g1s1.handle)
3808               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3809     CHECK(Local<Object>::New(iso, g2s1.handle)
3810               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3811   }
3812
3813   {
3814     UniqueId id1 = MakeUniqueId(g1s1.handle);
3815     UniqueId id2 = MakeUniqueId(g2s2.handle);
3816     iso->SetObjectGroupId(g1s1.handle, id1);
3817     iso->SetObjectGroupId(g1s2.handle, id1);
3818     iso->SetReference(g1s1.handle, g1c1.handle);
3819     iso->SetObjectGroupId(g2s1.handle, id2);
3820     iso->SetObjectGroupId(g2s2.handle, id2);
3821     iso->SetReferenceFromGroup(id2, g2c1.handle);
3822   }
3823   // Do a single full GC, ensure incremental marking is stopped.
3824   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3825       iso)->heap();
3826   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3827
3828   // All object should be alive.
3829   CHECK_EQ(0, counter.NumberOfWeakCalls());
3830
3831   // Weaken the root.
3832   root.handle.SetWeak(&root, &WeakPointerCallback);
3833   // But make children strong roots---all the objects (except for children)
3834   // should be collectable now.
3835   g1c1.handle.ClearWeak();
3836   g2c1.handle.ClearWeak();
3837
3838   // Groups are deleted, rebuild groups.
3839   {
3840     UniqueId id1 = MakeUniqueId(g1s1.handle);
3841     UniqueId id2 = MakeUniqueId(g2s2.handle);
3842     iso->SetObjectGroupId(g1s1.handle, id1);
3843     iso->SetObjectGroupId(g1s2.handle, id1);
3844     iso->SetReference(g1s1.handle, g1c1.handle);
3845     iso->SetObjectGroupId(g2s1.handle, id2);
3846     iso->SetObjectGroupId(g2s2.handle, id2);
3847     iso->SetReferenceFromGroup(id2, g2c1.handle);
3848   }
3849
3850   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3851
3852   // All objects should be gone. 5 global handles in total.
3853   CHECK_EQ(5, counter.NumberOfWeakCalls());
3854
3855   // And now make children weak again and collect them.
3856   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3857   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3858
3859   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3860   CHECK_EQ(7, counter.NumberOfWeakCalls());
3861 }
3862
3863
3864 THREADED_TEST(ApiObjectGroupsCycle) {
3865   LocalContext env;
3866   v8::Isolate* iso = env->GetIsolate();
3867   HandleScope scope(iso);
3868
3869   WeakCallCounter counter(1234);
3870
3871   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3872   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3873   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3874   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3875   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3876   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3877   WeakCallCounterAndPersistent<Value> g4s1(&counter);
3878   WeakCallCounterAndPersistent<Value> g4s2(&counter);
3879
3880   {
3881     HandleScope scope(iso);
3882     g1s1.handle.Reset(iso, Object::New(iso));
3883     g1s2.handle.Reset(iso, Object::New(iso));
3884     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3885     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3886     CHECK(g1s1.handle.IsWeak());
3887     CHECK(g1s2.handle.IsWeak());
3888
3889     g2s1.handle.Reset(iso, Object::New(iso));
3890     g2s2.handle.Reset(iso, Object::New(iso));
3891     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3892     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3893     CHECK(g2s1.handle.IsWeak());
3894     CHECK(g2s2.handle.IsWeak());
3895
3896     g3s1.handle.Reset(iso, Object::New(iso));
3897     g3s2.handle.Reset(iso, Object::New(iso));
3898     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3899     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3900     CHECK(g3s1.handle.IsWeak());
3901     CHECK(g3s2.handle.IsWeak());
3902
3903     g4s1.handle.Reset(iso, Object::New(iso));
3904     g4s2.handle.Reset(iso, Object::New(iso));
3905     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3906     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3907     CHECK(g4s1.handle.IsWeak());
3908     CHECK(g4s2.handle.IsWeak());
3909   }
3910
3911   WeakCallCounterAndPersistent<Value> root(&counter);
3912   root.handle.Reset(iso, g1s1.handle);  // make a root.
3913
3914   // Connect groups.  We're building the following cycle:
3915   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3916   // groups.
3917   {
3918     UniqueId id1 = MakeUniqueId(g1s1.handle);
3919     UniqueId id2 = MakeUniqueId(g2s1.handle);
3920     UniqueId id3 = MakeUniqueId(g3s1.handle);
3921     UniqueId id4 = MakeUniqueId(g4s1.handle);
3922     iso->SetObjectGroupId(g1s1.handle, id1);
3923     iso->SetObjectGroupId(g1s2.handle, id1);
3924     iso->SetReferenceFromGroup(id1, g2s1.handle);
3925     iso->SetObjectGroupId(g2s1.handle, id2);
3926     iso->SetObjectGroupId(g2s2.handle, id2);
3927     iso->SetReferenceFromGroup(id2, g3s1.handle);
3928     iso->SetObjectGroupId(g3s1.handle, id3);
3929     iso->SetObjectGroupId(g3s2.handle, id3);
3930     iso->SetReferenceFromGroup(id3, g4s1.handle);
3931     iso->SetObjectGroupId(g4s1.handle, id4);
3932     iso->SetObjectGroupId(g4s2.handle, id4);
3933     iso->SetReferenceFromGroup(id4, g1s1.handle);
3934   }
3935   // Do a single full GC
3936   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3937       iso)->heap();
3938   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3939
3940   // All object should be alive.
3941   CHECK_EQ(0, counter.NumberOfWeakCalls());
3942
3943   // Weaken the root.
3944   root.handle.SetWeak(&root, &WeakPointerCallback);
3945
3946   // Groups are deleted, rebuild groups.
3947   {
3948     UniqueId id1 = MakeUniqueId(g1s1.handle);
3949     UniqueId id2 = MakeUniqueId(g2s1.handle);
3950     UniqueId id3 = MakeUniqueId(g3s1.handle);
3951     UniqueId id4 = MakeUniqueId(g4s1.handle);
3952     iso->SetObjectGroupId(g1s1.handle, id1);
3953     iso->SetObjectGroupId(g1s2.handle, id1);
3954     iso->SetReferenceFromGroup(id1, g2s1.handle);
3955     iso->SetObjectGroupId(g2s1.handle, id2);
3956     iso->SetObjectGroupId(g2s2.handle, id2);
3957     iso->SetReferenceFromGroup(id2, g3s1.handle);
3958     iso->SetObjectGroupId(g3s1.handle, id3);
3959     iso->SetObjectGroupId(g3s2.handle, id3);
3960     iso->SetReferenceFromGroup(id3, g4s1.handle);
3961     iso->SetObjectGroupId(g4s1.handle, id4);
3962     iso->SetObjectGroupId(g4s2.handle, id4);
3963     iso->SetReferenceFromGroup(id4, g1s1.handle);
3964   }
3965
3966   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3967
3968   // All objects should be gone. 9 global handles in total.
3969   CHECK_EQ(9, counter.NumberOfWeakCalls());
3970 }
3971
3972
3973 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3974 // on the buildbots, so was made non-threaded for the time being.
3975 TEST(ApiObjectGroupsCycleForScavenger) {
3976   i::FLAG_stress_compaction = false;
3977   i::FLAG_gc_global = false;
3978   LocalContext env;
3979   v8::Isolate* iso = env->GetIsolate();
3980   HandleScope scope(iso);
3981
3982   WeakCallCounter counter(1234);
3983
3984   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3985   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3986   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3987   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3988   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3989   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3990
3991   {
3992     HandleScope scope(iso);
3993     g1s1.handle.Reset(iso, Object::New(iso));
3994     g1s2.handle.Reset(iso, Object::New(iso));
3995     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3996     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3997
3998     g2s1.handle.Reset(iso, Object::New(iso));
3999     g2s2.handle.Reset(iso, Object::New(iso));
4000     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4001     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4002
4003     g3s1.handle.Reset(iso, Object::New(iso));
4004     g3s2.handle.Reset(iso, Object::New(iso));
4005     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4006     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4007   }
4008
4009   // Make a root.
4010   WeakCallCounterAndPersistent<Value> root(&counter);
4011   root.handle.Reset(iso, g1s1.handle);
4012   root.handle.MarkPartiallyDependent();
4013
4014   // Connect groups.  We're building the following cycle:
4015   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4016   // groups.
4017   {
4018     HandleScope handle_scope(iso);
4019     g1s1.handle.MarkPartiallyDependent();
4020     g1s2.handle.MarkPartiallyDependent();
4021     g2s1.handle.MarkPartiallyDependent();
4022     g2s2.handle.MarkPartiallyDependent();
4023     g3s1.handle.MarkPartiallyDependent();
4024     g3s2.handle.MarkPartiallyDependent();
4025     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4026     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4027     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4028         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4029     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4030     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4031     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4032         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4033     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4034     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4035     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4036         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4037   }
4038
4039   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4040       iso)->heap();
4041   heap->CollectGarbage(i::NEW_SPACE);
4042
4043   // All objects should be alive.
4044   CHECK_EQ(0, counter.NumberOfWeakCalls());
4045
4046   // Weaken the root.
4047   root.handle.SetWeak(&root, &WeakPointerCallback);
4048   root.handle.MarkPartiallyDependent();
4049
4050   // Groups are deleted, rebuild groups.
4051   {
4052     HandleScope handle_scope(iso);
4053     g1s1.handle.MarkPartiallyDependent();
4054     g1s2.handle.MarkPartiallyDependent();
4055     g2s1.handle.MarkPartiallyDependent();
4056     g2s2.handle.MarkPartiallyDependent();
4057     g3s1.handle.MarkPartiallyDependent();
4058     g3s2.handle.MarkPartiallyDependent();
4059     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4060     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4061     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4062         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4063     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4064     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4065     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4066         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4067     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4068     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4069     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4070         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4071   }
4072
4073   heap->CollectGarbage(i::NEW_SPACE);
4074
4075   // All objects should be gone. 7 global handles in total.
4076   CHECK_EQ(7, counter.NumberOfWeakCalls());
4077 }
4078
4079
4080 THREADED_TEST(ScriptException) {
4081   LocalContext env;
4082   v8::HandleScope scope(env->GetIsolate());
4083   Local<Script> script = v8_compile("throw 'panama!';");
4084   v8::TryCatch try_catch;
4085   Local<Value> result = script->Run();
4086   CHECK(result.IsEmpty());
4087   CHECK(try_catch.HasCaught());
4088   String::Utf8Value exception_value(try_catch.Exception());
4089   CHECK_EQ(*exception_value, "panama!");
4090 }
4091
4092
4093 TEST(TryCatchCustomException) {
4094   LocalContext env;
4095   v8::HandleScope scope(env->GetIsolate());
4096   v8::TryCatch try_catch;
4097   CompileRun("function CustomError() { this.a = 'b'; }"
4098              "(function f() { throw new CustomError(); })();");
4099   CHECK(try_catch.HasCaught());
4100   CHECK(try_catch.Exception()->ToObject()->
4101             Get(v8_str("a"))->Equals(v8_str("b")));
4102 }
4103
4104
4105 bool message_received;
4106
4107
4108 static void check_message_0(v8::Handle<v8::Message> message,
4109                             v8::Handle<Value> data) {
4110   CHECK_EQ(5.76, data->NumberValue());
4111   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4112   CHECK(!message->IsSharedCrossOrigin());
4113   message_received = true;
4114 }
4115
4116
4117 THREADED_TEST(MessageHandler0) {
4118   message_received = false;
4119   v8::HandleScope scope(CcTest::isolate());
4120   CHECK(!message_received);
4121   LocalContext context;
4122   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4123   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4124   script->Run();
4125   CHECK(message_received);
4126   // clear out the message listener
4127   v8::V8::RemoveMessageListeners(check_message_0);
4128 }
4129
4130
4131 static void check_message_1(v8::Handle<v8::Message> message,
4132                             v8::Handle<Value> data) {
4133   CHECK(data->IsNumber());
4134   CHECK_EQ(1337, data->Int32Value());
4135   CHECK(!message->IsSharedCrossOrigin());
4136   message_received = true;
4137 }
4138
4139
4140 TEST(MessageHandler1) {
4141   message_received = false;
4142   v8::HandleScope scope(CcTest::isolate());
4143   CHECK(!message_received);
4144   v8::V8::AddMessageListener(check_message_1);
4145   LocalContext context;
4146   CompileRun("throw 1337;");
4147   CHECK(message_received);
4148   // clear out the message listener
4149   v8::V8::RemoveMessageListeners(check_message_1);
4150 }
4151
4152
4153 static void check_message_2(v8::Handle<v8::Message> message,
4154                             v8::Handle<Value> data) {
4155   LocalContext context;
4156   CHECK(data->IsObject());
4157   v8::Local<v8::Value> hidden_property =
4158       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4159   CHECK(v8_str("hidden value")->Equals(hidden_property));
4160   CHECK(!message->IsSharedCrossOrigin());
4161   message_received = true;
4162 }
4163
4164
4165 TEST(MessageHandler2) {
4166   message_received = false;
4167   v8::HandleScope scope(CcTest::isolate());
4168   CHECK(!message_received);
4169   v8::V8::AddMessageListener(check_message_2);
4170   LocalContext context;
4171   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4172   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4173                                            v8_str("hidden value"));
4174   context->Global()->Set(v8_str("error"), error);
4175   CompileRun("throw error;");
4176   CHECK(message_received);
4177   // clear out the message listener
4178   v8::V8::RemoveMessageListeners(check_message_2);
4179 }
4180
4181
4182 static void check_message_3(v8::Handle<v8::Message> message,
4183                             v8::Handle<Value> data) {
4184   CHECK(message->IsSharedCrossOrigin());
4185   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4186   message_received = true;
4187 }
4188
4189
4190 TEST(MessageHandler3) {
4191   message_received = false;
4192   v8::Isolate* isolate = CcTest::isolate();
4193   v8::HandleScope scope(isolate);
4194   CHECK(!message_received);
4195   v8::V8::AddMessageListener(check_message_3);
4196   LocalContext context;
4197   v8::ScriptOrigin origin =
4198       v8::ScriptOrigin(v8_str("6.75"),
4199                        v8::Integer::New(isolate, 1),
4200                        v8::Integer::New(isolate, 2),
4201                        v8::True(isolate));
4202   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4203                                                   &origin);
4204   script->Run();
4205   CHECK(message_received);
4206   // clear out the message listener
4207   v8::V8::RemoveMessageListeners(check_message_3);
4208 }
4209
4210
4211 static void check_message_4(v8::Handle<v8::Message> message,
4212                             v8::Handle<Value> data) {
4213   CHECK(!message->IsSharedCrossOrigin());
4214   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4215   message_received = true;
4216 }
4217
4218
4219 TEST(MessageHandler4) {
4220   message_received = false;
4221   v8::Isolate* isolate = CcTest::isolate();
4222   v8::HandleScope scope(isolate);
4223   CHECK(!message_received);
4224   v8::V8::AddMessageListener(check_message_4);
4225   LocalContext context;
4226   v8::ScriptOrigin origin =
4227       v8::ScriptOrigin(v8_str("6.75"),
4228                        v8::Integer::New(isolate, 1),
4229                        v8::Integer::New(isolate, 2),
4230                        v8::False(isolate));
4231   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4232                                                   &origin);
4233   script->Run();
4234   CHECK(message_received);
4235   // clear out the message listener
4236   v8::V8::RemoveMessageListeners(check_message_4);
4237 }
4238
4239
4240 static void check_message_5a(v8::Handle<v8::Message> message,
4241                             v8::Handle<Value> data) {
4242   CHECK(message->IsSharedCrossOrigin());
4243   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4244   message_received = true;
4245 }
4246
4247
4248 static void check_message_5b(v8::Handle<v8::Message> message,
4249                             v8::Handle<Value> data) {
4250   CHECK(!message->IsSharedCrossOrigin());
4251   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4252   message_received = true;
4253 }
4254
4255
4256 TEST(MessageHandler5) {
4257   message_received = false;
4258   v8::Isolate* isolate = CcTest::isolate();
4259   v8::HandleScope scope(isolate);
4260   CHECK(!message_received);
4261   v8::V8::AddMessageListener(check_message_5a);
4262   LocalContext context;
4263   v8::ScriptOrigin origin =
4264       v8::ScriptOrigin(v8_str("6.75"),
4265                        v8::Integer::New(isolate, 1),
4266                        v8::Integer::New(isolate, 2),
4267                        v8::True(isolate));
4268   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4269                                                   &origin);
4270   script->Run();
4271   CHECK(message_received);
4272   // clear out the message listener
4273   v8::V8::RemoveMessageListeners(check_message_5a);
4274
4275   message_received = false;
4276   v8::V8::AddMessageListener(check_message_5b);
4277   origin =
4278       v8::ScriptOrigin(v8_str("6.75"),
4279                        v8::Integer::New(isolate, 1),
4280                        v8::Integer::New(isolate, 2),
4281                        v8::False(isolate));
4282   script = Script::Compile(v8_str("throw 'error'"),
4283                            &origin);
4284   script->Run();
4285   CHECK(message_received);
4286   // clear out the message listener
4287   v8::V8::RemoveMessageListeners(check_message_5b);
4288 }
4289
4290
4291 THREADED_TEST(GetSetProperty) {
4292   LocalContext context;
4293   v8::Isolate* isolate = context->GetIsolate();
4294   v8::HandleScope scope(isolate);
4295   context->Global()->Set(v8_str("foo"), v8_num(14));
4296   context->Global()->Set(v8_str("12"), v8_num(92));
4297   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4298   context->Global()->Set(v8_num(13), v8_num(56));
4299   Local<Value> foo = CompileRun("this.foo");
4300   CHECK_EQ(14, foo->Int32Value());
4301   Local<Value> twelve = CompileRun("this[12]");
4302   CHECK_EQ(92, twelve->Int32Value());
4303   Local<Value> sixteen = CompileRun("this[16]");
4304   CHECK_EQ(32, sixteen->Int32Value());
4305   Local<Value> thirteen = CompileRun("this[13]");
4306   CHECK_EQ(56, thirteen->Int32Value());
4307   CHECK_EQ(92,
4308            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4309   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4310   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4311   CHECK_EQ(32,
4312            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4313   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4314   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4315   CHECK_EQ(56,
4316            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4317   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4318   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4319 }
4320
4321
4322 THREADED_TEST(PropertyAttributes) {
4323   LocalContext context;
4324   v8::HandleScope scope(context->GetIsolate());
4325   // none
4326   Local<String> prop = v8_str("none");
4327   context->Global()->Set(prop, v8_num(7));
4328   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4329   // read-only
4330   prop = v8_str("read_only");
4331   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4332   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4333   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4334   CompileRun("read_only = 9");
4335   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4336   context->Global()->Set(prop, v8_num(10));
4337   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4338   // dont-delete
4339   prop = v8_str("dont_delete");
4340   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4341   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4342   CompileRun("delete dont_delete");
4343   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4344   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4345   // dont-enum
4346   prop = v8_str("dont_enum");
4347   context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4348   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4349   // absent
4350   prop = v8_str("absent");
4351   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4352   Local<Value> fake_prop = v8_num(1);
4353   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4354   // exception
4355   TryCatch try_catch;
4356   Local<Value> exception =
4357       CompileRun("({ toString: function() { throw 'exception';} })");
4358   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4359   CHECK(try_catch.HasCaught());
4360   String::Utf8Value exception_value(try_catch.Exception());
4361   CHECK_EQ("exception", *exception_value);
4362   try_catch.Reset();
4363 }
4364
4365
4366 THREADED_TEST(Array) {
4367   LocalContext context;
4368   v8::HandleScope scope(context->GetIsolate());
4369   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4370   CHECK_EQ(0, array->Length());
4371   CHECK(array->Get(0)->IsUndefined());
4372   CHECK(!array->Has(0));
4373   CHECK(array->Get(100)->IsUndefined());
4374   CHECK(!array->Has(100));
4375   array->Set(2, v8_num(7));
4376   CHECK_EQ(3, array->Length());
4377   CHECK(!array->Has(0));
4378   CHECK(!array->Has(1));
4379   CHECK(array->Has(2));
4380   CHECK_EQ(7, array->Get(2)->Int32Value());
4381   Local<Value> obj = CompileRun("[1, 2, 3]");
4382   Local<v8::Array> arr = obj.As<v8::Array>();
4383   CHECK_EQ(3, arr->Length());
4384   CHECK_EQ(1, arr->Get(0)->Int32Value());
4385   CHECK_EQ(2, arr->Get(1)->Int32Value());
4386   CHECK_EQ(3, arr->Get(2)->Int32Value());
4387   array = v8::Array::New(context->GetIsolate(), 27);
4388   CHECK_EQ(27, array->Length());
4389   array = v8::Array::New(context->GetIsolate(), -27);
4390   CHECK_EQ(0, array->Length());
4391 }
4392
4393
4394 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4395   v8::EscapableHandleScope scope(args.GetIsolate());
4396   ApiTestFuzzer::Fuzz();
4397   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4398   for (int i = 0; i < args.Length(); i++)
4399     result->Set(i, args[i]);
4400   args.GetReturnValue().Set(scope.Escape(result));
4401 }
4402
4403
4404 THREADED_TEST(Vector) {
4405   v8::Isolate* isolate = CcTest::isolate();
4406   v8::HandleScope scope(isolate);
4407   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4408   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4409   LocalContext context(0, global);
4410
4411   const char* fun = "f()";
4412   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4413   CHECK_EQ(0, a0->Length());
4414
4415   const char* fun2 = "f(11)";
4416   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4417   CHECK_EQ(1, a1->Length());
4418   CHECK_EQ(11, a1->Get(0)->Int32Value());
4419
4420   const char* fun3 = "f(12, 13)";
4421   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4422   CHECK_EQ(2, a2->Length());
4423   CHECK_EQ(12, a2->Get(0)->Int32Value());
4424   CHECK_EQ(13, a2->Get(1)->Int32Value());
4425
4426   const char* fun4 = "f(14, 15, 16)";
4427   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4428   CHECK_EQ(3, a3->Length());
4429   CHECK_EQ(14, a3->Get(0)->Int32Value());
4430   CHECK_EQ(15, a3->Get(1)->Int32Value());
4431   CHECK_EQ(16, a3->Get(2)->Int32Value());
4432
4433   const char* fun5 = "f(17, 18, 19, 20)";
4434   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4435   CHECK_EQ(4, a4->Length());
4436   CHECK_EQ(17, a4->Get(0)->Int32Value());
4437   CHECK_EQ(18, a4->Get(1)->Int32Value());
4438   CHECK_EQ(19, a4->Get(2)->Int32Value());
4439   CHECK_EQ(20, a4->Get(3)->Int32Value());
4440 }
4441
4442
4443 THREADED_TEST(FunctionCall) {
4444   LocalContext context;
4445   v8::Isolate* isolate = context->GetIsolate();
4446   v8::HandleScope scope(isolate);
4447   CompileRun(
4448     "function Foo() {"
4449     "  var result = [];"
4450     "  for (var i = 0; i < arguments.length; i++) {"
4451     "    result.push(arguments[i]);"
4452     "  }"
4453     "  return result;"
4454     "}"
4455     "function ReturnThisSloppy() {"
4456     "  return this;"
4457     "}"
4458     "function ReturnThisStrict() {"
4459     "  'use strict';"
4460     "  return this;"
4461     "}");
4462   Local<Function> Foo =
4463       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4464   Local<Function> ReturnThisSloppy =
4465       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4466   Local<Function> ReturnThisStrict =
4467       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4468
4469   v8::Handle<Value>* args0 = NULL;
4470   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4471   CHECK_EQ(0, a0->Length());
4472
4473   v8::Handle<Value> args1[] = { v8_num(1.1) };
4474   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4475   CHECK_EQ(1, a1->Length());
4476   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4477
4478   v8::Handle<Value> args2[] = { v8_num(2.2),
4479                                 v8_num(3.3) };
4480   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4481   CHECK_EQ(2, a2->Length());
4482   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4483   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4484
4485   v8::Handle<Value> args3[] = { v8_num(4.4),
4486                                 v8_num(5.5),
4487                                 v8_num(6.6) };
4488   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4489   CHECK_EQ(3, a3->Length());
4490   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4491   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4492   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4493
4494   v8::Handle<Value> args4[] = { v8_num(7.7),
4495                                 v8_num(8.8),
4496                                 v8_num(9.9),
4497                                 v8_num(10.11) };
4498   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4499   CHECK_EQ(4, a4->Length());
4500   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4501   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4502   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4503   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4504
4505   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4506   CHECK(r1->StrictEquals(context->Global()));
4507   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4508   CHECK(r2->StrictEquals(context->Global()));
4509   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4510   CHECK(r3->IsNumberObject());
4511   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4512   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4513   CHECK(r4->IsStringObject());
4514   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4515   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4516   CHECK(r5->IsBooleanObject());
4517   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4518
4519   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4520   CHECK(r6->IsUndefined());
4521   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4522   CHECK(r7->IsNull());
4523   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4524   CHECK(r8->StrictEquals(v8_num(42)));
4525   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4526   CHECK(r9->StrictEquals(v8_str("hello")));
4527   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4528   CHECK(r10->StrictEquals(v8::True(isolate)));
4529 }
4530
4531
4532 THREADED_TEST(ConstructCall) {
4533   LocalContext context;
4534   v8::Isolate* isolate = context->GetIsolate();
4535   v8::HandleScope scope(isolate);
4536   CompileRun(
4537     "function Foo() {"
4538     "  var result = [];"
4539     "  for (var i = 0; i < arguments.length; i++) {"
4540     "    result.push(arguments[i]);"
4541     "  }"
4542     "  return result;"
4543     "}");
4544   Local<Function> Foo =
4545       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4546
4547   v8::Handle<Value>* args0 = NULL;
4548   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4549   CHECK_EQ(0, a0->Length());
4550
4551   v8::Handle<Value> args1[] = { v8_num(1.1) };
4552   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4553   CHECK_EQ(1, a1->Length());
4554   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4555
4556   v8::Handle<Value> args2[] = { v8_num(2.2),
4557                                 v8_num(3.3) };
4558   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4559   CHECK_EQ(2, a2->Length());
4560   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4561   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4562
4563   v8::Handle<Value> args3[] = { v8_num(4.4),
4564                                 v8_num(5.5),
4565                                 v8_num(6.6) };
4566   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4567   CHECK_EQ(3, a3->Length());
4568   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4569   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4570   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4571
4572   v8::Handle<Value> args4[] = { v8_num(7.7),
4573                                 v8_num(8.8),
4574                                 v8_num(9.9),
4575                                 v8_num(10.11) };
4576   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4577   CHECK_EQ(4, a4->Length());
4578   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4579   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4580   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4581   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4582 }
4583
4584
4585 static void CheckUncle(v8::TryCatch* try_catch) {
4586   CHECK(try_catch->HasCaught());
4587   String::Utf8Value str_value(try_catch->Exception());
4588   CHECK_EQ(*str_value, "uncle?");
4589   try_catch->Reset();
4590 }
4591
4592
4593 THREADED_TEST(ConversionNumber) {
4594   LocalContext env;
4595   v8::HandleScope scope(env->GetIsolate());
4596   // Very large number.
4597   CompileRun("var obj = Math.pow(2,32) * 1237;");
4598   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4599   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4600   CHECK_EQ(0, obj->ToInt32()->Value());
4601   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4602   // Large number.
4603   CompileRun("var obj = -1234567890123;");
4604   obj = env->Global()->Get(v8_str("obj"));
4605   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4606   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4607   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4608   // Small positive integer.
4609   CompileRun("var obj = 42;");
4610   obj = env->Global()->Get(v8_str("obj"));
4611   CHECK_EQ(42.0, obj->ToNumber()->Value());
4612   CHECK_EQ(42, obj->ToInt32()->Value());
4613   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4614   // Negative integer.
4615   CompileRun("var obj = -37;");
4616   obj = env->Global()->Get(v8_str("obj"));
4617   CHECK_EQ(-37.0, obj->ToNumber()->Value());
4618   CHECK_EQ(-37, obj->ToInt32()->Value());
4619   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4620   // Positive non-int32 integer.
4621   CompileRun("var obj = 0x81234567;");
4622   obj = env->Global()->Get(v8_str("obj"));
4623   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4624   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4625   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4626   // Fraction.
4627   CompileRun("var obj = 42.3;");
4628   obj = env->Global()->Get(v8_str("obj"));
4629   CHECK_EQ(42.3, obj->ToNumber()->Value());
4630   CHECK_EQ(42, obj->ToInt32()->Value());
4631   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4632   // Large negative fraction.
4633   CompileRun("var obj = -5726623061.75;");
4634   obj = env->Global()->Get(v8_str("obj"));
4635   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4636   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4637   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4638 }
4639
4640
4641 THREADED_TEST(isNumberType) {
4642   LocalContext env;
4643   v8::HandleScope scope(env->GetIsolate());
4644   // Very large number.
4645   CompileRun("var obj = Math.pow(2,32) * 1237;");
4646   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4647   CHECK(!obj->IsInt32());
4648   CHECK(!obj->IsUint32());
4649   // Large negative number.
4650   CompileRun("var obj = -1234567890123;");
4651   obj = env->Global()->Get(v8_str("obj"));
4652   CHECK(!obj->IsInt32());
4653   CHECK(!obj->IsUint32());
4654   // Small positive integer.
4655   CompileRun("var obj = 42;");
4656   obj = env->Global()->Get(v8_str("obj"));
4657   CHECK(obj->IsInt32());
4658   CHECK(obj->IsUint32());
4659   // Negative integer.
4660   CompileRun("var obj = -37;");
4661   obj = env->Global()->Get(v8_str("obj"));
4662   CHECK(obj->IsInt32());
4663   CHECK(!obj->IsUint32());
4664   // Positive non-int32 integer.
4665   CompileRun("var obj = 0x81234567;");
4666   obj = env->Global()->Get(v8_str("obj"));
4667   CHECK(!obj->IsInt32());
4668   CHECK(obj->IsUint32());
4669   // Fraction.
4670   CompileRun("var obj = 42.3;");
4671   obj = env->Global()->Get(v8_str("obj"));
4672   CHECK(!obj->IsInt32());
4673   CHECK(!obj->IsUint32());
4674   // Large negative fraction.
4675   CompileRun("var obj = -5726623061.75;");
4676   obj = env->Global()->Get(v8_str("obj"));
4677   CHECK(!obj->IsInt32());
4678   CHECK(!obj->IsUint32());
4679   // Positive zero
4680   CompileRun("var obj = 0.0;");
4681   obj = env->Global()->Get(v8_str("obj"));
4682   CHECK(obj->IsInt32());
4683   CHECK(obj->IsUint32());
4684   // Positive zero
4685   CompileRun("var obj = -0.0;");
4686   obj = env->Global()->Get(v8_str("obj"));
4687   CHECK(!obj->IsInt32());
4688   CHECK(!obj->IsUint32());
4689 }
4690
4691
4692 THREADED_TEST(ConversionException) {
4693   LocalContext env;
4694   v8::Isolate* isolate = env->GetIsolate();
4695   v8::HandleScope scope(isolate);
4696   CompileRun(
4697     "function TestClass() { };"
4698     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4699     "var obj = new TestClass();");
4700   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4701
4702   v8::TryCatch try_catch;
4703
4704   Local<Value> to_string_result = obj->ToString();
4705   CHECK(to_string_result.IsEmpty());
4706   CheckUncle(&try_catch);
4707
4708   Local<Value> to_number_result = obj->ToNumber();
4709   CHECK(to_number_result.IsEmpty());
4710   CheckUncle(&try_catch);
4711
4712   Local<Value> to_integer_result = obj->ToInteger();
4713   CHECK(to_integer_result.IsEmpty());
4714   CheckUncle(&try_catch);
4715
4716   Local<Value> to_uint32_result = obj->ToUint32();
4717   CHECK(to_uint32_result.IsEmpty());
4718   CheckUncle(&try_catch);
4719
4720   Local<Value> to_int32_result = obj->ToInt32();
4721   CHECK(to_int32_result.IsEmpty());
4722   CheckUncle(&try_catch);
4723
4724   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4725   CHECK(to_object_result.IsEmpty());
4726   CHECK(try_catch.HasCaught());
4727   try_catch.Reset();
4728
4729   int32_t int32_value = obj->Int32Value();
4730   CHECK_EQ(0, int32_value);
4731   CheckUncle(&try_catch);
4732
4733   uint32_t uint32_value = obj->Uint32Value();
4734   CHECK_EQ(0, uint32_value);
4735   CheckUncle(&try_catch);
4736
4737   double number_value = obj->NumberValue();
4738   CHECK_NE(0, std::isnan(number_value));
4739   CheckUncle(&try_catch);
4740
4741   int64_t integer_value = obj->IntegerValue();
4742   CHECK_EQ(0.0, static_cast<double>(integer_value));
4743   CheckUncle(&try_catch);
4744 }
4745
4746
4747 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4748   ApiTestFuzzer::Fuzz();
4749   args.GetIsolate()->ThrowException(v8_str("konto"));
4750 }
4751
4752
4753 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4754   if (args.Length() < 1) {
4755     args.GetReturnValue().Set(false);
4756     return;
4757   }
4758   v8::HandleScope scope(args.GetIsolate());
4759   v8::TryCatch try_catch;
4760   Local<Value> result = CompileRun(args[0]->ToString());
4761   CHECK(!try_catch.HasCaught() || result.IsEmpty());
4762   args.GetReturnValue().Set(try_catch.HasCaught());
4763 }
4764
4765
4766 THREADED_TEST(APICatch) {
4767   v8::Isolate* isolate = CcTest::isolate();
4768   v8::HandleScope scope(isolate);
4769   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4770   templ->Set(v8_str("ThrowFromC"),
4771              v8::FunctionTemplate::New(isolate, ThrowFromC));
4772   LocalContext context(0, templ);
4773   CompileRun(
4774     "var thrown = false;"
4775     "try {"
4776     "  ThrowFromC();"
4777     "} catch (e) {"
4778     "  thrown = true;"
4779     "}");
4780   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4781   CHECK(thrown->BooleanValue());
4782 }
4783
4784
4785 THREADED_TEST(APIThrowTryCatch) {
4786   v8::Isolate* isolate = CcTest::isolate();
4787   v8::HandleScope scope(isolate);
4788   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4789   templ->Set(v8_str("ThrowFromC"),
4790              v8::FunctionTemplate::New(isolate, ThrowFromC));
4791   LocalContext context(0, templ);
4792   v8::TryCatch try_catch;
4793   CompileRun("ThrowFromC();");
4794   CHECK(try_catch.HasCaught());
4795 }
4796
4797
4798 // Test that a try-finally block doesn't shadow a try-catch block
4799 // when setting up an external handler.
4800 //
4801 // BUG(271): Some of the exception propagation does not work on the
4802 // ARM simulator because the simulator separates the C++ stack and the
4803 // JS stack.  This test therefore fails on the simulator.  The test is
4804 // not threaded to allow the threading tests to run on the simulator.
4805 TEST(TryCatchInTryFinally) {
4806   v8::Isolate* isolate = CcTest::isolate();
4807   v8::HandleScope scope(isolate);
4808   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4809   templ->Set(v8_str("CCatcher"),
4810              v8::FunctionTemplate::New(isolate, CCatcher));
4811   LocalContext context(0, templ);
4812   Local<Value> result = CompileRun("try {"
4813                                    "  try {"
4814                                    "    CCatcher('throw 7;');"
4815                                    "  } finally {"
4816                                    "  }"
4817                                    "} catch (e) {"
4818                                    "}");
4819   CHECK(result->IsTrue());
4820 }
4821
4822
4823 static void check_reference_error_message(
4824     v8::Handle<v8::Message> message,
4825     v8::Handle<v8::Value> data) {
4826   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4827   CHECK(message->Get()->Equals(v8_str(reference_error)));
4828 }
4829
4830
4831 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4832   ApiTestFuzzer::Fuzz();
4833   CHECK(false);
4834 }
4835
4836
4837 // Test that overwritten methods are not invoked on uncaught exception
4838 // formatting. However, they are invoked when performing normal error
4839 // string conversions.
4840 TEST(APIThrowMessageOverwrittenToString) {
4841   v8::Isolate* isolate = CcTest::isolate();
4842   v8::HandleScope scope(isolate);
4843   v8::V8::AddMessageListener(check_reference_error_message);
4844   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4845   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4846   LocalContext context(NULL, templ);
4847   CompileRun("asdf;");
4848   CompileRun("var limit = {};"
4849              "limit.valueOf = fail;"
4850              "Error.stackTraceLimit = limit;");
4851   CompileRun("asdf");
4852   CompileRun("Array.prototype.pop = fail;");
4853   CompileRun("Object.prototype.hasOwnProperty = fail;");
4854   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4855   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4856   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4857   CompileRun("ReferenceError.prototype.toString ="
4858              "  function() { return 'Whoops' }");
4859   CompileRun("asdf;");
4860   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4861   CompileRun("asdf;");
4862   CompileRun("ReferenceError.prototype.constructor = void 0;");
4863   CompileRun("asdf;");
4864   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4865   CompileRun("asdf;");
4866   CompileRun("ReferenceError.prototype = new Object();");
4867   CompileRun("asdf;");
4868   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4869   CHECK(string->Equals(v8_str("Whoops")));
4870   CompileRun("ReferenceError.prototype.constructor = new Object();"
4871              "ReferenceError.prototype.constructor.name = 1;"
4872              "Number.prototype.toString = function() { return 'Whoops'; };"
4873              "ReferenceError.prototype.toString = Object.prototype.toString;");
4874   CompileRun("asdf;");
4875   v8::V8::RemoveMessageListeners(check_reference_error_message);
4876 }
4877
4878
4879 static void check_custom_error_tostring(
4880     v8::Handle<v8::Message> message,
4881     v8::Handle<v8::Value> data) {
4882   const char* uncaught_error = "Uncaught MyError toString";
4883   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4884 }
4885
4886
4887 TEST(CustomErrorToString) {
4888   LocalContext context;
4889   v8::HandleScope scope(context->GetIsolate());
4890   v8::V8::AddMessageListener(check_custom_error_tostring);
4891   CompileRun(
4892     "function MyError(name, message) {                   "
4893     "  this.name = name;                                 "
4894     "  this.message = message;                           "
4895     "}                                                   "
4896     "MyError.prototype = Object.create(Error.prototype); "
4897     "MyError.prototype.toString = function() {           "
4898     "  return 'MyError toString';                        "
4899     "};                                                  "
4900     "throw new MyError('my name', 'my message');         ");
4901   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4902 }
4903
4904
4905 static void check_custom_error_message(
4906     v8::Handle<v8::Message> message,
4907     v8::Handle<v8::Value> data) {
4908   const char* uncaught_error = "Uncaught MyError: my message";
4909   printf("%s\n", *v8::String::Utf8Value(message->Get()));
4910   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4911 }
4912
4913
4914 TEST(CustomErrorMessage) {
4915   LocalContext context;
4916   v8::HandleScope scope(context->GetIsolate());
4917   v8::V8::AddMessageListener(check_custom_error_message);
4918
4919   // Handlebars.
4920   CompileRun(
4921     "function MyError(msg) {                             "
4922     "  this.name = 'MyError';                            "
4923     "  this.message = msg;                               "
4924     "}                                                   "
4925     "MyError.prototype = new Error();                    "
4926     "throw new MyError('my message');                    ");
4927
4928   // Closure.
4929   CompileRun(
4930     "function MyError(msg) {                             "
4931     "  this.name = 'MyError';                            "
4932     "  this.message = msg;                               "
4933     "}                                                   "
4934     "inherits = function(childCtor, parentCtor) {        "
4935     "    function tempCtor() {};                         "
4936     "    tempCtor.prototype = parentCtor.prototype;      "
4937     "    childCtor.superClass_ = parentCtor.prototype;   "
4938     "    childCtor.prototype = new tempCtor();           "
4939     "    childCtor.prototype.constructor = childCtor;    "
4940     "};                                                  "
4941     "inherits(MyError, Error);                           "
4942     "throw new MyError('my message');                    ");
4943
4944   // Object.create.
4945   CompileRun(
4946     "function MyError(msg) {                             "
4947     "  this.name = 'MyError';                            "
4948     "  this.message = msg;                               "
4949     "}                                                   "
4950     "MyError.prototype = Object.create(Error.prototype); "
4951     "throw new MyError('my message');                    ");
4952
4953   v8::V8::RemoveMessageListeners(check_custom_error_message);
4954 }
4955
4956
4957 static void receive_message(v8::Handle<v8::Message> message,
4958                             v8::Handle<v8::Value> data) {
4959   message->Get();
4960   message_received = true;
4961 }
4962
4963
4964 TEST(APIThrowMessage) {
4965   message_received = false;
4966   v8::Isolate* isolate = CcTest::isolate();
4967   v8::HandleScope scope(isolate);
4968   v8::V8::AddMessageListener(receive_message);
4969   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4970   templ->Set(v8_str("ThrowFromC"),
4971              v8::FunctionTemplate::New(isolate, ThrowFromC));
4972   LocalContext context(0, templ);
4973   CompileRun("ThrowFromC();");
4974   CHECK(message_received);
4975   v8::V8::RemoveMessageListeners(receive_message);
4976 }
4977
4978
4979 TEST(APIThrowMessageAndVerboseTryCatch) {
4980   message_received = false;
4981   v8::Isolate* isolate = CcTest::isolate();
4982   v8::HandleScope scope(isolate);
4983   v8::V8::AddMessageListener(receive_message);
4984   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4985   templ->Set(v8_str("ThrowFromC"),
4986              v8::FunctionTemplate::New(isolate, ThrowFromC));
4987   LocalContext context(0, templ);
4988   v8::TryCatch try_catch;
4989   try_catch.SetVerbose(true);
4990   Local<Value> result = CompileRun("ThrowFromC();");
4991   CHECK(try_catch.HasCaught());
4992   CHECK(result.IsEmpty());
4993   CHECK(message_received);
4994   v8::V8::RemoveMessageListeners(receive_message);
4995 }
4996
4997
4998 TEST(APIStackOverflowAndVerboseTryCatch) {
4999   message_received = false;
5000   LocalContext context;
5001   v8::HandleScope scope(context->GetIsolate());
5002   v8::V8::AddMessageListener(receive_message);
5003   v8::TryCatch try_catch;
5004   try_catch.SetVerbose(true);
5005   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5006   CHECK(try_catch.HasCaught());
5007   CHECK(result.IsEmpty());
5008   CHECK(message_received);
5009   v8::V8::RemoveMessageListeners(receive_message);
5010 }
5011
5012
5013 THREADED_TEST(ExternalScriptException) {
5014   v8::Isolate* isolate = CcTest::isolate();
5015   v8::HandleScope scope(isolate);
5016   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5017   templ->Set(v8_str("ThrowFromC"),
5018              v8::FunctionTemplate::New(isolate, ThrowFromC));
5019   LocalContext context(0, templ);
5020
5021   v8::TryCatch try_catch;
5022   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5023   CHECK(result.IsEmpty());
5024   CHECK(try_catch.HasCaught());
5025   String::Utf8Value exception_value(try_catch.Exception());
5026   CHECK_EQ("konto", *exception_value);
5027 }
5028
5029
5030
5031 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5032   ApiTestFuzzer::Fuzz();
5033   CHECK_EQ(4, args.Length());
5034   int count = args[0]->Int32Value();
5035   int cInterval = args[2]->Int32Value();
5036   if (count == 0) {
5037     args.GetIsolate()->ThrowException(v8_str("FromC"));
5038     return;
5039   } else {
5040     Local<v8::Object> global =
5041         args.GetIsolate()->GetCurrentContext()->Global();
5042     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5043     v8::Handle<Value> argv[] = { v8_num(count - 1),
5044                                  args[1],
5045                                  args[2],
5046                                  args[3] };
5047     if (count % cInterval == 0) {
5048       v8::TryCatch try_catch;
5049       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5050       int expected = args[3]->Int32Value();
5051       if (try_catch.HasCaught()) {
5052         CHECK_EQ(expected, count);
5053         CHECK(result.IsEmpty());
5054         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5055       } else {
5056         CHECK_NE(expected, count);
5057       }
5058       args.GetReturnValue().Set(result);
5059       return;
5060     } else {
5061       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5062       return;
5063     }
5064   }
5065 }
5066
5067
5068 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5069   ApiTestFuzzer::Fuzz();
5070   CHECK_EQ(3, args.Length());
5071   bool equality = args[0]->BooleanValue();
5072   int count = args[1]->Int32Value();
5073   int expected = args[2]->Int32Value();
5074   if (equality) {
5075     CHECK_EQ(count, expected);
5076   } else {
5077     CHECK_NE(count, expected);
5078   }
5079 }
5080
5081
5082 THREADED_TEST(EvalInTryFinally) {
5083   LocalContext context;
5084   v8::HandleScope scope(context->GetIsolate());
5085   v8::TryCatch try_catch;
5086   CompileRun("(function() {"
5087              "  try {"
5088              "    eval('asldkf (*&^&*^');"
5089              "  } finally {"
5090              "    return;"
5091              "  }"
5092              "})()");
5093   CHECK(!try_catch.HasCaught());
5094 }
5095
5096
5097 // This test works by making a stack of alternating JavaScript and C
5098 // activations.  These activations set up exception handlers with regular
5099 // intervals, one interval for C activations and another for JavaScript
5100 // activations.  When enough activations have been created an exception is
5101 // thrown and we check that the right activation catches the exception and that
5102 // no other activations do.  The right activation is always the topmost one with
5103 // a handler, regardless of whether it is in JavaScript or C.
5104 //
5105 // The notation used to describe a test case looks like this:
5106 //
5107 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5108 //
5109 // Each entry is an activation, either JS or C.  The index is the count at that
5110 // level.  Stars identify activations with exception handlers, the @ identifies
5111 // the exception handler that should catch the exception.
5112 //
5113 // BUG(271): Some of the exception propagation does not work on the
5114 // ARM simulator because the simulator separates the C++ stack and the
5115 // JS stack.  This test therefore fails on the simulator.  The test is
5116 // not threaded to allow the threading tests to run on the simulator.
5117 TEST(ExceptionOrder) {
5118   v8::Isolate* isolate = CcTest::isolate();
5119   v8::HandleScope scope(isolate);
5120   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5121   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5122   templ->Set(v8_str("CThrowCountDown"),
5123              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5124   LocalContext context(0, templ);
5125   CompileRun(
5126     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5127     "  if (count == 0) throw 'FromJS';"
5128     "  if (count % jsInterval == 0) {"
5129     "    try {"
5130     "      var value = CThrowCountDown(count - 1,"
5131     "                                  jsInterval,"
5132     "                                  cInterval,"
5133     "                                  expected);"
5134     "      check(false, count, expected);"
5135     "      return value;"
5136     "    } catch (e) {"
5137     "      check(true, count, expected);"
5138     "    }"
5139     "  } else {"
5140     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5141     "  }"
5142     "}");
5143   Local<Function> fun =
5144       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5145
5146   const int argc = 4;
5147   //                             count      jsInterval cInterval  expected
5148
5149   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5150   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5151   fun->Call(fun, argc, a0);
5152
5153   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5154   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5155   fun->Call(fun, argc, a1);
5156
5157   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5158   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5159   fun->Call(fun, argc, a2);
5160
5161   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5162   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5163   fun->Call(fun, argc, a3);
5164
5165   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5166   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5167   fun->Call(fun, argc, a4);
5168
5169   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5170   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5171   fun->Call(fun, argc, a5);
5172 }
5173
5174
5175 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5176   ApiTestFuzzer::Fuzz();
5177   CHECK_EQ(1, args.Length());
5178   args.GetIsolate()->ThrowException(args[0]);
5179 }
5180
5181
5182 THREADED_TEST(ThrowValues) {
5183   v8::Isolate* isolate = CcTest::isolate();
5184   v8::HandleScope scope(isolate);
5185   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5186   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5187   LocalContext context(0, templ);
5188   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5189     "function Run(obj) {"
5190     "  try {"
5191     "    Throw(obj);"
5192     "  } catch (e) {"
5193     "    return e;"
5194     "  }"
5195     "  return 'no exception';"
5196     "}"
5197     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5198   CHECK_EQ(5, result->Length());
5199   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5200   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5201   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5202   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5203   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5204   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5205   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5206 }
5207
5208
5209 THREADED_TEST(CatchZero) {
5210   LocalContext context;
5211   v8::HandleScope scope(context->GetIsolate());
5212   v8::TryCatch try_catch;
5213   CHECK(!try_catch.HasCaught());
5214   CompileRun("throw 10");
5215   CHECK(try_catch.HasCaught());
5216   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5217   try_catch.Reset();
5218   CHECK(!try_catch.HasCaught());
5219   CompileRun("throw 0");
5220   CHECK(try_catch.HasCaught());
5221   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5222 }
5223
5224
5225 THREADED_TEST(CatchExceptionFromWith) {
5226   LocalContext context;
5227   v8::HandleScope scope(context->GetIsolate());
5228   v8::TryCatch try_catch;
5229   CHECK(!try_catch.HasCaught());
5230   CompileRun("var o = {}; with (o) { throw 42; }");
5231   CHECK(try_catch.HasCaught());
5232 }
5233
5234
5235 THREADED_TEST(TryCatchAndFinallyHidingException) {
5236   LocalContext context;
5237   v8::HandleScope scope(context->GetIsolate());
5238   v8::TryCatch try_catch;
5239   CHECK(!try_catch.HasCaught());
5240   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5241   CompileRun("f({toString: function() { throw 42; }});");
5242   CHECK(!try_catch.HasCaught());
5243 }
5244
5245
5246 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5247   v8::TryCatch try_catch;
5248 }
5249
5250
5251 THREADED_TEST(TryCatchAndFinally) {
5252   LocalContext context;
5253   v8::Isolate* isolate = context->GetIsolate();
5254   v8::HandleScope scope(isolate);
5255   context->Global()->Set(
5256       v8_str("native_with_try_catch"),
5257       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5258   v8::TryCatch try_catch;
5259   CHECK(!try_catch.HasCaught());
5260   CompileRun(
5261       "try {\n"
5262       "  throw new Error('a');\n"
5263       "} finally {\n"
5264       "  native_with_try_catch();\n"
5265       "}\n");
5266   CHECK(try_catch.HasCaught());
5267 }
5268
5269
5270 static void TryCatchNestedHelper(int depth) {
5271   if (depth > 0) {
5272     v8::TryCatch try_catch;
5273     try_catch.SetVerbose(true);
5274     TryCatchNestedHelper(depth - 1);
5275     CHECK(try_catch.HasCaught());
5276     try_catch.ReThrow();
5277   } else {
5278     CcTest::isolate()->ThrowException(v8_str("back"));
5279   }
5280 }
5281
5282
5283 TEST(TryCatchNested) {
5284   v8::V8::Initialize();
5285   LocalContext context;
5286   v8::HandleScope scope(context->GetIsolate());
5287   v8::TryCatch try_catch;
5288   TryCatchNestedHelper(5);
5289   CHECK(try_catch.HasCaught());
5290   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5291 }
5292
5293
5294 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5295   CHECK(try_catch->HasCaught());
5296   Handle<Message> message = try_catch->Message();
5297   Handle<Value> resource = message->GetScriptResourceName();
5298   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5299   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5300                      "Uncaught Error: a"));
5301   CHECK_EQ(1, message->GetLineNumber());
5302   CHECK_EQ(6, message->GetStartColumn());
5303 }
5304
5305
5306 void TryCatchMixedNestingHelper(
5307     const v8::FunctionCallbackInfo<v8::Value>& args) {
5308   ApiTestFuzzer::Fuzz();
5309   v8::TryCatch try_catch;
5310   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5311   CHECK(try_catch.HasCaught());
5312   TryCatchMixedNestingCheck(&try_catch);
5313   try_catch.ReThrow();
5314 }
5315
5316
5317 // This test ensures that an outer TryCatch in the following situation:
5318 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5319 // does not clobber the Message object generated for the inner TryCatch.
5320 // This exercises the ability of TryCatch.ReThrow() to restore the
5321 // inner pending Message before throwing the exception again.
5322 TEST(TryCatchMixedNesting) {
5323   v8::Isolate* isolate = CcTest::isolate();
5324   v8::HandleScope scope(isolate);
5325   v8::V8::Initialize();
5326   v8::TryCatch try_catch;
5327   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5328   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5329              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5330   LocalContext context(0, templ);
5331   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5332   TryCatchMixedNestingCheck(&try_catch);
5333 }
5334
5335
5336 THREADED_TEST(Equality) {
5337   LocalContext context;
5338   v8::Isolate* isolate = context->GetIsolate();
5339   v8::HandleScope scope(context->GetIsolate());
5340   // Check that equality works at all before relying on CHECK_EQ
5341   CHECK(v8_str("a")->Equals(v8_str("a")));
5342   CHECK(!v8_str("a")->Equals(v8_str("b")));
5343
5344   CHECK_EQ(v8_str("a"), v8_str("a"));
5345   CHECK_NE(v8_str("a"), v8_str("b"));
5346   CHECK_EQ(v8_num(1), v8_num(1));
5347   CHECK_EQ(v8_num(1.00), v8_num(1));
5348   CHECK_NE(v8_num(1), v8_num(2));
5349
5350   // Assume String is not internalized.
5351   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5352   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5353   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5354   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5355   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5356   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5357   Local<Value> not_a_number = v8_num(i::OS::nan_value());
5358   CHECK(!not_a_number->StrictEquals(not_a_number));
5359   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5360   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5361
5362   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5363   v8::Persistent<v8::Object> alias(isolate, obj);
5364   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5365   alias.Reset();
5366
5367   CHECK(v8_str("a")->SameValue(v8_str("a")));
5368   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5369   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5370   CHECK(v8_num(1)->SameValue(v8_num(1)));
5371   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5372   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5373   CHECK(not_a_number->SameValue(not_a_number));
5374   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5375   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5376 }
5377
5378
5379 THREADED_TEST(MultiRun) {
5380   LocalContext context;
5381   v8::HandleScope scope(context->GetIsolate());
5382   Local<Script> script = v8_compile("x");
5383   for (int i = 0; i < 10; i++)
5384     script->Run();
5385 }
5386
5387
5388 static void GetXValue(Local<String> name,
5389                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5390   ApiTestFuzzer::Fuzz();
5391   CHECK_EQ(info.Data(), v8_str("donut"));
5392   CHECK_EQ(name, v8_str("x"));
5393   info.GetReturnValue().Set(name);
5394 }
5395
5396
5397 THREADED_TEST(SimplePropertyRead) {
5398   LocalContext context;
5399   v8::Isolate* isolate = context->GetIsolate();
5400   v8::HandleScope scope(isolate);
5401   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5402   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5403   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5404   Local<Script> script = v8_compile("obj.x");
5405   for (int i = 0; i < 10; i++) {
5406     Local<Value> result = script->Run();
5407     CHECK_EQ(result, v8_str("x"));
5408   }
5409 }
5410
5411
5412 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5413   LocalContext context;
5414   v8::Isolate* isolate = context->GetIsolate();
5415   v8::HandleScope scope(isolate);
5416   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5417   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5418   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5419
5420   // Uses getOwnPropertyDescriptor to check the configurable status
5421   Local<Script> script_desc = v8_compile(
5422       "var prop = Object.getOwnPropertyDescriptor( "
5423       "obj, 'x');"
5424       "prop.configurable;");
5425   Local<Value> result = script_desc->Run();
5426   CHECK_EQ(result->BooleanValue(), true);
5427
5428   // Redefine get - but still configurable
5429   Local<Script> script_define = v8_compile(
5430       "var desc = { get: function(){return 42; },"
5431       "            configurable: true };"
5432       "Object.defineProperty(obj, 'x', desc);"
5433       "obj.x");
5434   result = script_define->Run();
5435   CHECK_EQ(result, v8_num(42));
5436
5437   // Check that the accessor is still configurable
5438   result = script_desc->Run();
5439   CHECK_EQ(result->BooleanValue(), true);
5440
5441   // Redefine to a non-configurable
5442   script_define = v8_compile(
5443       "var desc = { get: function(){return 43; },"
5444       "             configurable: false };"
5445       "Object.defineProperty(obj, 'x', desc);"
5446       "obj.x");
5447   result = script_define->Run();
5448   CHECK_EQ(result, v8_num(43));
5449   result = script_desc->Run();
5450   CHECK_EQ(result->BooleanValue(), false);
5451
5452   // Make sure that it is not possible to redefine again
5453   v8::TryCatch try_catch;
5454   result = script_define->Run();
5455   CHECK(try_catch.HasCaught());
5456   String::Utf8Value exception_value(try_catch.Exception());
5457   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5458 }
5459
5460
5461 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5462   v8::Isolate* isolate = CcTest::isolate();
5463   v8::HandleScope scope(isolate);
5464   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5465   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5466   LocalContext context;
5467   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5468
5469   Local<Script> script_desc = v8_compile(
5470       "var prop ="
5471       "Object.getOwnPropertyDescriptor( "
5472       "obj, 'x');"
5473       "prop.configurable;");
5474   Local<Value> result = script_desc->Run();
5475   CHECK_EQ(result->BooleanValue(), true);
5476
5477   Local<Script> script_define = v8_compile(
5478       "var desc = {get: function(){return 42; },"
5479       "            configurable: true };"
5480       "Object.defineProperty(obj, 'x', desc);"
5481       "obj.x");
5482   result = script_define->Run();
5483   CHECK_EQ(result, v8_num(42));
5484
5485
5486   result = script_desc->Run();
5487   CHECK_EQ(result->BooleanValue(), true);
5488
5489
5490   script_define = v8_compile(
5491       "var desc = {get: function(){return 43; },"
5492       "            configurable: false };"
5493       "Object.defineProperty(obj, 'x', desc);"
5494       "obj.x");
5495   result = script_define->Run();
5496   CHECK_EQ(result, v8_num(43));
5497   result = script_desc->Run();
5498
5499   CHECK_EQ(result->BooleanValue(), false);
5500
5501   v8::TryCatch try_catch;
5502   result = script_define->Run();
5503   CHECK(try_catch.HasCaught());
5504   String::Utf8Value exception_value(try_catch.Exception());
5505   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5506 }
5507
5508
5509 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5510                                                 char const* name) {
5511   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5512 }
5513
5514
5515 THREADED_TEST(DefineAPIAccessorOnObject) {
5516   v8::Isolate* isolate = CcTest::isolate();
5517   v8::HandleScope scope(isolate);
5518   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5519   LocalContext context;
5520
5521   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5522   CompileRun("var obj2 = {};");
5523
5524   CHECK(CompileRun("obj1.x")->IsUndefined());
5525   CHECK(CompileRun("obj2.x")->IsUndefined());
5526
5527   CHECK(GetGlobalProperty(&context, "obj1")->
5528       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5529
5530   ExpectString("obj1.x", "x");
5531   CHECK(CompileRun("obj2.x")->IsUndefined());
5532
5533   CHECK(GetGlobalProperty(&context, "obj2")->
5534       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5535
5536   ExpectString("obj1.x", "x");
5537   ExpectString("obj2.x", "x");
5538
5539   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5540   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5541
5542   CompileRun("Object.defineProperty(obj1, 'x',"
5543              "{ get: function() { return 'y'; }, configurable: true })");
5544
5545   ExpectString("obj1.x", "y");
5546   ExpectString("obj2.x", "x");
5547
5548   CompileRun("Object.defineProperty(obj2, 'x',"
5549              "{ get: function() { return 'y'; }, configurable: true })");
5550
5551   ExpectString("obj1.x", "y");
5552   ExpectString("obj2.x", "y");
5553
5554   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5555   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5556
5557   CHECK(GetGlobalProperty(&context, "obj1")->
5558       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5559   CHECK(GetGlobalProperty(&context, "obj2")->
5560       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5561
5562   ExpectString("obj1.x", "x");
5563   ExpectString("obj2.x", "x");
5564
5565   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5566   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5567
5568   // Define getters/setters, but now make them not configurable.
5569   CompileRun("Object.defineProperty(obj1, 'x',"
5570              "{ get: function() { return 'z'; }, configurable: false })");
5571   CompileRun("Object.defineProperty(obj2, 'x',"
5572              "{ get: function() { return 'z'; }, configurable: false })");
5573
5574   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5575   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5576
5577   ExpectString("obj1.x", "z");
5578   ExpectString("obj2.x", "z");
5579
5580   CHECK(!GetGlobalProperty(&context, "obj1")->
5581       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5582   CHECK(!GetGlobalProperty(&context, "obj2")->
5583       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5584
5585   ExpectString("obj1.x", "z");
5586   ExpectString("obj2.x", "z");
5587 }
5588
5589
5590 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5591   v8::Isolate* isolate = CcTest::isolate();
5592   v8::HandleScope scope(isolate);
5593   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5594   LocalContext context;
5595
5596   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5597   CompileRun("var obj2 = {};");
5598
5599   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5600         v8_str("x"),
5601         GetXValue, NULL,
5602         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5603   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5604         v8_str("x"),
5605         GetXValue, NULL,
5606         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5607
5608   ExpectString("obj1.x", "x");
5609   ExpectString("obj2.x", "x");
5610
5611   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5612   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5613
5614   CHECK(!GetGlobalProperty(&context, "obj1")->
5615       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5616   CHECK(!GetGlobalProperty(&context, "obj2")->
5617       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5618
5619   {
5620     v8::TryCatch try_catch;
5621     CompileRun("Object.defineProperty(obj1, 'x',"
5622         "{get: function() { return 'func'; }})");
5623     CHECK(try_catch.HasCaught());
5624     String::Utf8Value exception_value(try_catch.Exception());
5625     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5626   }
5627   {
5628     v8::TryCatch try_catch;
5629     CompileRun("Object.defineProperty(obj2, 'x',"
5630         "{get: function() { return 'func'; }})");
5631     CHECK(try_catch.HasCaught());
5632     String::Utf8Value exception_value(try_catch.Exception());
5633     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5634   }
5635 }
5636
5637
5638 static void Get239Value(Local<String> name,
5639                         const v8::PropertyCallbackInfo<v8::Value>& info) {
5640   ApiTestFuzzer::Fuzz();
5641   CHECK_EQ(info.Data(), v8_str("donut"));
5642   CHECK_EQ(name, v8_str("239"));
5643   info.GetReturnValue().Set(name);
5644 }
5645
5646
5647 THREADED_TEST(ElementAPIAccessor) {
5648   v8::Isolate* isolate = CcTest::isolate();
5649   v8::HandleScope scope(isolate);
5650   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5651   LocalContext context;
5652
5653   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5654   CompileRun("var obj2 = {};");
5655
5656   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5657         v8_str("239"),
5658         Get239Value, NULL,
5659         v8_str("donut")));
5660   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5661         v8_str("239"),
5662         Get239Value, NULL,
5663         v8_str("donut")));
5664
5665   ExpectString("obj1[239]", "239");
5666   ExpectString("obj2[239]", "239");
5667   ExpectString("obj1['239']", "239");
5668   ExpectString("obj2['239']", "239");
5669 }
5670
5671
5672 v8::Persistent<Value> xValue;
5673
5674
5675 static void SetXValue(Local<String> name,
5676                       Local<Value> value,
5677                       const v8::PropertyCallbackInfo<void>& info) {
5678   CHECK_EQ(value, v8_num(4));
5679   CHECK_EQ(info.Data(), v8_str("donut"));
5680   CHECK_EQ(name, v8_str("x"));
5681   CHECK(xValue.IsEmpty());
5682   xValue.Reset(info.GetIsolate(), value);
5683 }
5684
5685
5686 THREADED_TEST(SimplePropertyWrite) {
5687   v8::Isolate* isolate = CcTest::isolate();
5688   v8::HandleScope scope(isolate);
5689   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5690   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5691   LocalContext context;
5692   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5693   Local<Script> script = v8_compile("obj.x = 4");
5694   for (int i = 0; i < 10; i++) {
5695     CHECK(xValue.IsEmpty());
5696     script->Run();
5697     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5698     xValue.Reset();
5699   }
5700 }
5701
5702
5703 THREADED_TEST(SetterOnly) {
5704   v8::Isolate* isolate = CcTest::isolate();
5705   v8::HandleScope scope(isolate);
5706   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5707   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5708   LocalContext context;
5709   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5710   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5711   for (int i = 0; i < 10; i++) {
5712     CHECK(xValue.IsEmpty());
5713     script->Run();
5714     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5715     xValue.Reset();
5716   }
5717 }
5718
5719
5720 THREADED_TEST(NoAccessors) {
5721   v8::Isolate* isolate = CcTest::isolate();
5722   v8::HandleScope scope(isolate);
5723   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5724   templ->SetAccessor(v8_str("x"),
5725                      static_cast<v8::AccessorGetterCallback>(NULL),
5726                      NULL,
5727                      v8_str("donut"));
5728   LocalContext context;
5729   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5730   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5731   for (int i = 0; i < 10; i++) {
5732     script->Run();
5733   }
5734 }
5735
5736
5737 static void XPropertyGetter(Local<String> property,
5738                             const v8::PropertyCallbackInfo<v8::Value>& info) {
5739   ApiTestFuzzer::Fuzz();
5740   CHECK(info.Data()->IsUndefined());
5741   info.GetReturnValue().Set(property);
5742 }
5743
5744
5745 THREADED_TEST(NamedInterceptorPropertyRead) {
5746   v8::Isolate* isolate = CcTest::isolate();
5747   v8::HandleScope scope(isolate);
5748   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5749   templ->SetNamedPropertyHandler(XPropertyGetter);
5750   LocalContext context;
5751   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5752   Local<Script> script = v8_compile("obj.x");
5753   for (int i = 0; i < 10; i++) {
5754     Local<Value> result = script->Run();
5755     CHECK_EQ(result, v8_str("x"));
5756   }
5757 }
5758
5759
5760 THREADED_TEST(NamedInterceptorDictionaryIC) {
5761   v8::Isolate* isolate = CcTest::isolate();
5762   v8::HandleScope scope(isolate);
5763   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5764   templ->SetNamedPropertyHandler(XPropertyGetter);
5765   LocalContext context;
5766   // Create an object with a named interceptor.
5767   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5768   Local<Script> script = v8_compile("interceptor_obj.x");
5769   for (int i = 0; i < 10; i++) {
5770     Local<Value> result = script->Run();
5771     CHECK_EQ(result, v8_str("x"));
5772   }
5773   // Create a slow case object and a function accessing a property in
5774   // that slow case object (with dictionary probing in generated
5775   // code). Then force object with a named interceptor into slow-case,
5776   // pass it to the function, and check that the interceptor is called
5777   // instead of accessing the local property.
5778   Local<Value> result =
5779       CompileRun("function get_x(o) { return o.x; };"
5780                  "var obj = { x : 42, y : 0 };"
5781                  "delete obj.y;"
5782                  "for (var i = 0; i < 10; i++) get_x(obj);"
5783                  "interceptor_obj.x = 42;"
5784                  "interceptor_obj.y = 10;"
5785                  "delete interceptor_obj.y;"
5786                  "get_x(interceptor_obj)");
5787   CHECK_EQ(result, v8_str("x"));
5788 }
5789
5790
5791 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5792   v8::Isolate* isolate = CcTest::isolate();
5793   v8::HandleScope scope(isolate);
5794   v8::Local<Context> context1 = Context::New(isolate);
5795
5796   context1->Enter();
5797   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5798   templ->SetNamedPropertyHandler(XPropertyGetter);
5799   // Create an object with a named interceptor.
5800   v8::Local<v8::Object> object = templ->NewInstance();
5801   context1->Global()->Set(v8_str("interceptor_obj"), object);
5802
5803   // Force the object into the slow case.
5804   CompileRun("interceptor_obj.y = 0;"
5805              "delete interceptor_obj.y;");
5806   context1->Exit();
5807
5808   {
5809     // Introduce the object into a different context.
5810     // Repeat named loads to exercise ICs.
5811     LocalContext context2;
5812     context2->Global()->Set(v8_str("interceptor_obj"), object);
5813     Local<Value> result =
5814       CompileRun("function get_x(o) { return o.x; }"
5815                  "interceptor_obj.x = 42;"
5816                  "for (var i=0; i != 10; i++) {"
5817                  "  get_x(interceptor_obj);"
5818                  "}"
5819                  "get_x(interceptor_obj)");
5820     // Check that the interceptor was actually invoked.
5821     CHECK_EQ(result, v8_str("x"));
5822   }
5823
5824   // Return to the original context and force some object to the slow case
5825   // to cause the NormalizedMapCache to verify.
5826   context1->Enter();
5827   CompileRun("var obj = { x : 0 }; delete obj.x;");
5828   context1->Exit();
5829 }
5830
5831
5832 static void SetXOnPrototypeGetter(
5833     Local<String> property,
5834     const v8::PropertyCallbackInfo<v8::Value>& info) {
5835   // Set x on the prototype object and do not handle the get request.
5836   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5837   proto.As<v8::Object>()->Set(v8_str("x"),
5838                               v8::Integer::New(info.GetIsolate(), 23));
5839 }
5840
5841
5842 // This is a regression test for http://crbug.com/20104. Map
5843 // transitions should not interfere with post interceptor lookup.
5844 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5845   v8::Isolate* isolate = CcTest::isolate();
5846   v8::HandleScope scope(isolate);
5847   Local<v8::FunctionTemplate> function_template =
5848       v8::FunctionTemplate::New(isolate);
5849   Local<v8::ObjectTemplate> instance_template
5850       = function_template->InstanceTemplate();
5851   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5852   LocalContext context;
5853   context->Global()->Set(v8_str("F"), function_template->GetFunction());
5854   // Create an instance of F and introduce a map transition for x.
5855   CompileRun("var o = new F(); o.x = 23;");
5856   // Create an instance of F and invoke the getter. The result should be 23.
5857   Local<Value> result = CompileRun("o = new F(); o.x");
5858   CHECK_EQ(result->Int32Value(), 23);
5859 }
5860
5861
5862 static void IndexedPropertyGetter(
5863     uint32_t index,
5864     const v8::PropertyCallbackInfo<v8::Value>& info) {
5865   ApiTestFuzzer::Fuzz();
5866   if (index == 37) {
5867     info.GetReturnValue().Set(v8_num(625));
5868   }
5869 }
5870
5871
5872 static void IndexedPropertySetter(
5873     uint32_t index,
5874     Local<Value> value,
5875     const v8::PropertyCallbackInfo<v8::Value>& info) {
5876   ApiTestFuzzer::Fuzz();
5877   if (index == 39) {
5878     info.GetReturnValue().Set(value);
5879   }
5880 }
5881
5882
5883 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5884   v8::Isolate* isolate = CcTest::isolate();
5885   v8::HandleScope scope(isolate);
5886   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5887   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5888                                    IndexedPropertySetter);
5889   LocalContext context;
5890   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5891   Local<Script> getter_script = v8_compile(
5892       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
5893   Local<Script> setter_script = v8_compile(
5894       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5895       "obj[17] = 23;"
5896       "obj.foo;");
5897   Local<Script> interceptor_setter_script = v8_compile(
5898       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5899       "obj[39] = 47;"
5900       "obj.foo;");  // This setter should not run, due to the interceptor.
5901   Local<Script> interceptor_getter_script = v8_compile(
5902       "obj[37];");
5903   Local<Value> result = getter_script->Run();
5904   CHECK_EQ(v8_num(5), result);
5905   result = setter_script->Run();
5906   CHECK_EQ(v8_num(23), result);
5907   result = interceptor_setter_script->Run();
5908   CHECK_EQ(v8_num(23), result);
5909   result = interceptor_getter_script->Run();
5910   CHECK_EQ(v8_num(625), result);
5911 }
5912
5913
5914 static void UnboxedDoubleIndexedPropertyGetter(
5915     uint32_t index,
5916     const v8::PropertyCallbackInfo<v8::Value>& info) {
5917   ApiTestFuzzer::Fuzz();
5918   if (index < 25) {
5919     info.GetReturnValue().Set(v8_num(index));
5920   }
5921 }
5922
5923
5924 static void UnboxedDoubleIndexedPropertySetter(
5925     uint32_t index,
5926     Local<Value> value,
5927     const v8::PropertyCallbackInfo<v8::Value>& info) {
5928   ApiTestFuzzer::Fuzz();
5929   if (index < 25) {
5930     info.GetReturnValue().Set(v8_num(index));
5931   }
5932 }
5933
5934
5935 void UnboxedDoubleIndexedPropertyEnumerator(
5936     const v8::PropertyCallbackInfo<v8::Array>& info) {
5937   // Force the list of returned keys to be stored in a FastDoubleArray.
5938   Local<Script> indexed_property_names_script = v8_compile(
5939       "keys = new Array(); keys[125000] = 1;"
5940       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5941       "keys.length = 25; keys;");
5942   Local<Value> result = indexed_property_names_script->Run();
5943   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5944 }
5945
5946
5947 // Make sure that the the interceptor code in the runtime properly handles
5948 // merging property name lists for double-array-backed arrays.
5949 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5950   v8::Isolate* isolate = CcTest::isolate();
5951   v8::HandleScope scope(isolate);
5952   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5953   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5954                                    UnboxedDoubleIndexedPropertySetter,
5955                                    0,
5956                                    0,
5957                                    UnboxedDoubleIndexedPropertyEnumerator);
5958   LocalContext context;
5959   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5960   // When obj is created, force it to be Stored in a FastDoubleArray.
5961   Local<Script> create_unboxed_double_script = v8_compile(
5962       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
5963       "key_count = 0; "
5964       "for (x in obj) {key_count++;};"
5965       "obj;");
5966   Local<Value> result = create_unboxed_double_script->Run();
5967   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
5968   Local<Script> key_count_check = v8_compile("key_count;");
5969   result = key_count_check->Run();
5970   CHECK_EQ(v8_num(40013), result);
5971 }
5972
5973
5974 void SloppyArgsIndexedPropertyEnumerator(
5975     const v8::PropertyCallbackInfo<v8::Array>& info) {
5976   // Force the list of returned keys to be stored in a Arguments object.
5977   Local<Script> indexed_property_names_script = v8_compile(
5978       "function f(w,x) {"
5979       " return arguments;"
5980       "}"
5981       "keys = f(0, 1, 2, 3);"
5982       "keys;");
5983   Local<Object> result =
5984       Local<Object>::Cast(indexed_property_names_script->Run());
5985   // Have to populate the handle manually, as it's not Cast-able.
5986   i::Handle<i::JSObject> o =
5987       v8::Utils::OpenHandle<Object, i::JSObject>(result);
5988   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
5989   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
5990 }
5991
5992
5993 static void SloppyIndexedPropertyGetter(
5994     uint32_t index,
5995     const v8::PropertyCallbackInfo<v8::Value>& info) {
5996   ApiTestFuzzer::Fuzz();
5997   if (index < 4) {
5998     info.GetReturnValue().Set(v8_num(index));
5999   }
6000 }
6001
6002
6003 // Make sure that the the interceptor code in the runtime properly handles
6004 // merging property name lists for non-string arguments arrays.
6005 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6006   v8::Isolate* isolate = CcTest::isolate();
6007   v8::HandleScope scope(isolate);
6008   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6009   templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6010                                    0,
6011                                    0,
6012                                    0,
6013                                    SloppyArgsIndexedPropertyEnumerator);
6014   LocalContext context;
6015   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6016   Local<Script> create_args_script = v8_compile(
6017       "var key_count = 0;"
6018       "for (x in obj) {key_count++;} key_count;");
6019   Local<Value> result = create_args_script->Run();
6020   CHECK_EQ(v8_num(4), result);
6021 }
6022
6023
6024 static void IdentityIndexedPropertyGetter(
6025     uint32_t index,
6026     const v8::PropertyCallbackInfo<v8::Value>& info) {
6027   info.GetReturnValue().Set(index);
6028 }
6029
6030
6031 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6032   v8::Isolate* isolate = CcTest::isolate();
6033   v8::HandleScope scope(isolate);
6034   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6035   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6036
6037   LocalContext context;
6038   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6039
6040   // Check fast object case.
6041   const char* fast_case_code =
6042       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6043   ExpectString(fast_case_code, "0");
6044
6045   // Check slow case.
6046   const char* slow_case_code =
6047       "obj.x = 1; delete obj.x;"
6048       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6049   ExpectString(slow_case_code, "1");
6050 }
6051
6052
6053 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6054   v8::Isolate* isolate = CcTest::isolate();
6055   v8::HandleScope scope(isolate);
6056   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6057   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6058
6059   LocalContext context;
6060   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6061
6062   const char* code =
6063       "try {"
6064       "  obj[0] = 239;"
6065       "  for (var i = 0; i < 100; i++) {"
6066       "    var v = obj[0];"
6067       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6068       "  }"
6069       "  'PASSED'"
6070       "} catch(e) {"
6071       "  e"
6072       "}";
6073   ExpectString(code, "PASSED");
6074 }
6075
6076
6077 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6078   v8::Isolate* isolate = CcTest::isolate();
6079   v8::HandleScope scope(isolate);
6080   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6081   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6082
6083   LocalContext context;
6084   Local<v8::Object> obj = templ->NewInstance();
6085   obj->TurnOnAccessCheck();
6086   context->Global()->Set(v8_str("obj"), obj);
6087
6088   const char* code =
6089       "try {"
6090       "  for (var i = 0; i < 100; i++) {"
6091       "    var v = obj[0];"
6092       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6093       "  }"
6094       "  'PASSED'"
6095       "} catch(e) {"
6096       "  e"
6097       "}";
6098   ExpectString(code, "PASSED");
6099 }
6100
6101
6102 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6103   i::FLAG_allow_natives_syntax = true;
6104   v8::Isolate* isolate = CcTest::isolate();
6105   v8::HandleScope scope(isolate);
6106   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6107   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6108
6109   LocalContext context;
6110   Local<v8::Object> obj = templ->NewInstance();
6111   context->Global()->Set(v8_str("obj"), obj);
6112
6113   const char* code =
6114       "try {"
6115       "  for (var i = 0; i < 100; i++) {"
6116       "    var expected = i;"
6117       "    if (i == 5) {"
6118       "      %EnableAccessChecks(obj);"
6119       "      expected = undefined;"
6120       "    }"
6121       "    var v = obj[i];"
6122       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6123       "    if (i == 5) %DisableAccessChecks(obj);"
6124       "  }"
6125       "  'PASSED'"
6126       "} catch(e) {"
6127       "  e"
6128       "}";
6129   ExpectString(code, "PASSED");
6130 }
6131
6132
6133 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6134   v8::Isolate* isolate = CcTest::isolate();
6135   v8::HandleScope scope(isolate);
6136   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6137   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6138
6139   LocalContext context;
6140   Local<v8::Object> obj = templ->NewInstance();
6141   context->Global()->Set(v8_str("obj"), obj);
6142
6143   const char* code =
6144       "try {"
6145       "  for (var i = 0; i < 100; i++) {"
6146       "    var v = obj[i];"
6147       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6148       "  }"
6149       "  'PASSED'"
6150       "} catch(e) {"
6151       "  e"
6152       "}";
6153   ExpectString(code, "PASSED");
6154 }
6155
6156
6157 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6158   v8::Isolate* isolate = CcTest::isolate();
6159   v8::HandleScope scope(isolate);
6160   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6161   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6162
6163   LocalContext context;
6164   Local<v8::Object> obj = templ->NewInstance();
6165   context->Global()->Set(v8_str("obj"), obj);
6166
6167   const char* code =
6168       "try {"
6169       "  for (var i = 0; i < 100; i++) {"
6170       "    var expected = i;"
6171       "    var key = i;"
6172       "    if (i == 25) {"
6173       "       key = -1;"
6174       "       expected = undefined;"
6175       "    }"
6176       "    if (i == 50) {"
6177       "       /* probe minimal Smi number on 32-bit platforms */"
6178       "       key = -(1 << 30);"
6179       "       expected = undefined;"
6180       "    }"
6181       "    if (i == 75) {"
6182       "       /* probe minimal Smi number on 64-bit platforms */"
6183       "       key = 1 << 31;"
6184       "       expected = undefined;"
6185       "    }"
6186       "    var v = obj[key];"
6187       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6188       "  }"
6189       "  'PASSED'"
6190       "} catch(e) {"
6191       "  e"
6192       "}";
6193   ExpectString(code, "PASSED");
6194 }
6195
6196
6197 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6198   v8::Isolate* isolate = CcTest::isolate();
6199   v8::HandleScope scope(isolate);
6200   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6201   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6202
6203   LocalContext context;
6204   Local<v8::Object> obj = templ->NewInstance();
6205   context->Global()->Set(v8_str("obj"), obj);
6206
6207   const char* code =
6208       "try {"
6209       "  for (var i = 0; i < 100; i++) {"
6210       "    var expected = i;"
6211       "    var key = i;"
6212       "    if (i == 50) {"
6213       "       key = 'foobar';"
6214       "       expected = undefined;"
6215       "    }"
6216       "    var v = obj[key];"
6217       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6218       "  }"
6219       "  'PASSED'"
6220       "} catch(e) {"
6221       "  e"
6222       "}";
6223   ExpectString(code, "PASSED");
6224 }
6225
6226
6227 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6228   v8::Isolate* isolate = CcTest::isolate();
6229   v8::HandleScope scope(isolate);
6230   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6231   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6232
6233   LocalContext context;
6234   Local<v8::Object> obj = templ->NewInstance();
6235   context->Global()->Set(v8_str("obj"), obj);
6236
6237   const char* code =
6238       "var original = obj;"
6239       "try {"
6240       "  for (var i = 0; i < 100; i++) {"
6241       "    var expected = i;"
6242       "    if (i == 50) {"
6243       "       obj = {50: 'foobar'};"
6244       "       expected = 'foobar';"
6245       "    }"
6246       "    var v = obj[i];"
6247       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6248       "    if (i == 50) obj = original;"
6249       "  }"
6250       "  'PASSED'"
6251       "} catch(e) {"
6252       "  e"
6253       "}";
6254   ExpectString(code, "PASSED");
6255 }
6256
6257
6258 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6259   v8::Isolate* isolate = CcTest::isolate();
6260   v8::HandleScope scope(isolate);
6261   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6262   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6263
6264   LocalContext context;
6265   Local<v8::Object> obj = templ->NewInstance();
6266   context->Global()->Set(v8_str("obj"), obj);
6267
6268   const char* code =
6269       "var original = obj;"
6270       "try {"
6271       "  for (var i = 0; i < 100; i++) {"
6272       "    var expected = i;"
6273       "    if (i == 5) {"
6274       "       obj = 239;"
6275       "       expected = undefined;"
6276       "    }"
6277       "    var v = obj[i];"
6278       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6279       "    if (i == 5) obj = original;"
6280       "  }"
6281       "  'PASSED'"
6282       "} catch(e) {"
6283       "  e"
6284       "}";
6285   ExpectString(code, "PASSED");
6286 }
6287
6288
6289 THREADED_TEST(IndexedInterceptorOnProto) {
6290   v8::Isolate* isolate = CcTest::isolate();
6291   v8::HandleScope scope(isolate);
6292   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6293   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6294
6295   LocalContext context;
6296   Local<v8::Object> obj = templ->NewInstance();
6297   context->Global()->Set(v8_str("obj"), obj);
6298
6299   const char* code =
6300       "var o = {__proto__: obj};"
6301       "try {"
6302       "  for (var i = 0; i < 100; i++) {"
6303       "    var v = o[i];"
6304       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6305       "  }"
6306       "  'PASSED'"
6307       "} catch(e) {"
6308       "  e"
6309       "}";
6310   ExpectString(code, "PASSED");
6311 }
6312
6313
6314 THREADED_TEST(MultiContexts) {
6315   v8::Isolate* isolate = CcTest::isolate();
6316   v8::HandleScope scope(isolate);
6317   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6318   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6319                                                         DummyCallHandler));
6320
6321   Local<String> password = v8_str("Password");
6322
6323   // Create an environment
6324   LocalContext context0(0, templ);
6325   context0->SetSecurityToken(password);
6326   v8::Handle<v8::Object> global0 = context0->Global();
6327   global0->Set(v8_str("custom"), v8_num(1234));
6328   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6329
6330   // Create an independent environment
6331   LocalContext context1(0, templ);
6332   context1->SetSecurityToken(password);
6333   v8::Handle<v8::Object> global1 = context1->Global();
6334   global1->Set(v8_str("custom"), v8_num(1234));
6335   CHECK_NE(global0, global1);
6336   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6337   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6338
6339   // Now create a new context with the old global
6340   LocalContext context2(0, templ, global1);
6341   context2->SetSecurityToken(password);
6342   v8::Handle<v8::Object> global2 = context2->Global();
6343   CHECK_EQ(global1, global2);
6344   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6345   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6346 }
6347
6348
6349 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6350   // Make sure that functions created by cloning boilerplates cannot
6351   // communicate through their __proto__ field.
6352
6353   v8::HandleScope scope(CcTest::isolate());
6354
6355   LocalContext env0;
6356   v8::Handle<v8::Object> global0 =
6357       env0->Global();
6358   v8::Handle<v8::Object> object0 =
6359       global0->Get(v8_str("Object")).As<v8::Object>();
6360   v8::Handle<v8::Object> tostring0 =
6361       object0->Get(v8_str("toString")).As<v8::Object>();
6362   v8::Handle<v8::Object> proto0 =
6363       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6364   proto0->Set(v8_str("custom"), v8_num(1234));
6365
6366   LocalContext env1;
6367   v8::Handle<v8::Object> global1 =
6368       env1->Global();
6369   v8::Handle<v8::Object> object1 =
6370       global1->Get(v8_str("Object")).As<v8::Object>();
6371   v8::Handle<v8::Object> tostring1 =
6372       object1->Get(v8_str("toString")).As<v8::Object>();
6373   v8::Handle<v8::Object> proto1 =
6374       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6375   CHECK(!proto1->Has(v8_str("custom")));
6376 }
6377
6378
6379 THREADED_TEST(Regress892105) {
6380   // Make sure that object and array literals created by cloning
6381   // boilerplates cannot communicate through their __proto__
6382   // field. This is rather difficult to check, but we try to add stuff
6383   // to Object.prototype and Array.prototype and create a new
6384   // environment. This should succeed.
6385
6386   v8::HandleScope scope(CcTest::isolate());
6387
6388   Local<String> source = v8_str("Object.prototype.obj = 1234;"
6389                                 "Array.prototype.arr = 4567;"
6390                                 "8901");
6391
6392   LocalContext env0;
6393   Local<Script> script0 = v8_compile(source);
6394   CHECK_EQ(8901.0, script0->Run()->NumberValue());
6395
6396   LocalContext env1;
6397   Local<Script> script1 = v8_compile(source);
6398   CHECK_EQ(8901.0, script1->Run()->NumberValue());
6399 }
6400
6401
6402 THREADED_TEST(UndetectableObject) {
6403   LocalContext env;
6404   v8::HandleScope scope(env->GetIsolate());
6405
6406   Local<v8::FunctionTemplate> desc =
6407       v8::FunctionTemplate::New(env->GetIsolate());
6408   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6409
6410   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6411   env->Global()->Set(v8_str("undetectable"), obj);
6412
6413   ExpectString("undetectable.toString()", "[object Object]");
6414   ExpectString("typeof undetectable", "undefined");
6415   ExpectString("typeof(undetectable)", "undefined");
6416   ExpectBoolean("typeof undetectable == 'undefined'", true);
6417   ExpectBoolean("typeof undetectable == 'object'", false);
6418   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6419   ExpectBoolean("!undetectable", true);
6420
6421   ExpectObject("true&&undetectable", obj);
6422   ExpectBoolean("false&&undetectable", false);
6423   ExpectBoolean("true||undetectable", true);
6424   ExpectObject("false||undetectable", obj);
6425
6426   ExpectObject("undetectable&&true", obj);
6427   ExpectObject("undetectable&&false", obj);
6428   ExpectBoolean("undetectable||true", true);
6429   ExpectBoolean("undetectable||false", false);
6430
6431   ExpectBoolean("undetectable==null", true);
6432   ExpectBoolean("null==undetectable", true);
6433   ExpectBoolean("undetectable==undefined", true);
6434   ExpectBoolean("undefined==undetectable", true);
6435   ExpectBoolean("undetectable==undetectable", true);
6436
6437
6438   ExpectBoolean("undetectable===null", false);
6439   ExpectBoolean("null===undetectable", false);
6440   ExpectBoolean("undetectable===undefined", false);
6441   ExpectBoolean("undefined===undetectable", false);
6442   ExpectBoolean("undetectable===undetectable", true);
6443 }
6444
6445
6446 THREADED_TEST(VoidLiteral) {
6447   LocalContext env;
6448   v8::Isolate* isolate = env->GetIsolate();
6449   v8::HandleScope scope(isolate);
6450
6451   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6452   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6453
6454   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6455   env->Global()->Set(v8_str("undetectable"), obj);
6456
6457   ExpectBoolean("undefined == void 0", true);
6458   ExpectBoolean("undetectable == void 0", true);
6459   ExpectBoolean("null == void 0", true);
6460   ExpectBoolean("undefined === void 0", true);
6461   ExpectBoolean("undetectable === void 0", false);
6462   ExpectBoolean("null === void 0", false);
6463
6464   ExpectBoolean("void 0 == undefined", true);
6465   ExpectBoolean("void 0 == undetectable", true);
6466   ExpectBoolean("void 0 == null", true);
6467   ExpectBoolean("void 0 === undefined", true);
6468   ExpectBoolean("void 0 === undetectable", false);
6469   ExpectBoolean("void 0 === null", false);
6470
6471   ExpectString("(function() {"
6472                "  try {"
6473                "    return x === void 0;"
6474                "  } catch(e) {"
6475                "    return e.toString();"
6476                "  }"
6477                "})()",
6478                "ReferenceError: x is not defined");
6479   ExpectString("(function() {"
6480                "  try {"
6481                "    return void 0 === x;"
6482                "  } catch(e) {"
6483                "    return e.toString();"
6484                "  }"
6485                "})()",
6486                "ReferenceError: x is not defined");
6487 }
6488
6489
6490 THREADED_TEST(ExtensibleOnUndetectable) {
6491   LocalContext env;
6492   v8::Isolate* isolate = env->GetIsolate();
6493   v8::HandleScope scope(isolate);
6494
6495   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6496   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6497
6498   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6499   env->Global()->Set(v8_str("undetectable"), obj);
6500
6501   Local<String> source = v8_str("undetectable.x = 42;"
6502                                 "undetectable.x");
6503
6504   Local<Script> script = v8_compile(source);
6505
6506   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6507
6508   ExpectBoolean("Object.isExtensible(undetectable)", true);
6509
6510   source = v8_str("Object.preventExtensions(undetectable);");
6511   script = v8_compile(source);
6512   script->Run();
6513   ExpectBoolean("Object.isExtensible(undetectable)", false);
6514
6515   source = v8_str("undetectable.y = 2000;");
6516   script = v8_compile(source);
6517   script->Run();
6518   ExpectBoolean("undetectable.y == undefined", true);
6519 }
6520
6521
6522
6523 THREADED_TEST(UndetectableString) {
6524   LocalContext env;
6525   v8::HandleScope scope(env->GetIsolate());
6526
6527   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6528                                           String::kUndetectableString);
6529   env->Global()->Set(v8_str("undetectable"), obj);
6530
6531   ExpectString("undetectable", "foo");
6532   ExpectString("typeof undetectable", "undefined");
6533   ExpectString("typeof(undetectable)", "undefined");
6534   ExpectBoolean("typeof undetectable == 'undefined'", true);
6535   ExpectBoolean("typeof undetectable == 'string'", false);
6536   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6537   ExpectBoolean("!undetectable", true);
6538
6539   ExpectObject("true&&undetectable", obj);
6540   ExpectBoolean("false&&undetectable", false);
6541   ExpectBoolean("true||undetectable", true);
6542   ExpectObject("false||undetectable", obj);
6543
6544   ExpectObject("undetectable&&true", obj);
6545   ExpectObject("undetectable&&false", obj);
6546   ExpectBoolean("undetectable||true", true);
6547   ExpectBoolean("undetectable||false", false);
6548
6549   ExpectBoolean("undetectable==null", true);
6550   ExpectBoolean("null==undetectable", true);
6551   ExpectBoolean("undetectable==undefined", true);
6552   ExpectBoolean("undefined==undetectable", true);
6553   ExpectBoolean("undetectable==undetectable", true);
6554
6555
6556   ExpectBoolean("undetectable===null", false);
6557   ExpectBoolean("null===undetectable", false);
6558   ExpectBoolean("undetectable===undefined", false);
6559   ExpectBoolean("undefined===undetectable", false);
6560   ExpectBoolean("undetectable===undetectable", true);
6561 }
6562
6563
6564 TEST(UndetectableOptimized) {
6565   i::FLAG_allow_natives_syntax = true;
6566   LocalContext env;
6567   v8::HandleScope scope(env->GetIsolate());
6568
6569   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6570                                           String::kUndetectableString);
6571   env->Global()->Set(v8_str("undetectable"), obj);
6572   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6573
6574   ExpectString(
6575       "function testBranch() {"
6576       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
6577       "  if (%_IsUndetectableObject(detectable)) throw 2;"
6578       "}\n"
6579       "function testBool() {"
6580       "  var b1 = !%_IsUndetectableObject(undetectable);"
6581       "  var b2 = %_IsUndetectableObject(detectable);"
6582       "  if (b1) throw 3;"
6583       "  if (b2) throw 4;"
6584       "  return b1 == b2;"
6585       "}\n"
6586       "%OptimizeFunctionOnNextCall(testBranch);"
6587       "%OptimizeFunctionOnNextCall(testBool);"
6588       "for (var i = 0; i < 10; i++) {"
6589       "  testBranch();"
6590       "  testBool();"
6591       "}\n"
6592       "\"PASS\"",
6593       "PASS");
6594 }
6595
6596
6597 template <typename T> static void USE(T) { }
6598
6599
6600 // The point of this test is type checking. We run it only so compilers
6601 // don't complain about an unused function.
6602 TEST(PersistentHandles) {
6603   LocalContext env;
6604   v8::Isolate* isolate = CcTest::isolate();
6605   v8::HandleScope scope(isolate);
6606   Local<String> str = v8_str("foo");
6607   v8::Persistent<String> p_str(isolate, str);
6608   p_str.Reset();
6609   Local<Script> scr = v8_compile("");
6610   v8::Persistent<Script> p_scr(isolate, scr);
6611   p_scr.Reset();
6612   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6613   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6614   p_templ.Reset();
6615 }
6616
6617
6618 static void HandleLogDelegator(
6619     const v8::FunctionCallbackInfo<v8::Value>& args) {
6620   ApiTestFuzzer::Fuzz();
6621 }
6622
6623
6624 THREADED_TEST(GlobalObjectTemplate) {
6625   v8::Isolate* isolate = CcTest::isolate();
6626   v8::HandleScope handle_scope(isolate);
6627   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6628   global_template->Set(v8_str("JSNI_Log"),
6629                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6630   v8::Local<Context> context = Context::New(isolate, 0, global_template);
6631   Context::Scope context_scope(context);
6632   CompileRun("JSNI_Log('LOG')");
6633 }
6634
6635
6636 static const char* kSimpleExtensionSource =
6637   "function Foo() {"
6638   "  return 4;"
6639   "}";
6640
6641
6642 TEST(SimpleExtensions) {
6643   v8::HandleScope handle_scope(CcTest::isolate());
6644   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6645   const char* extension_names[] = { "simpletest" };
6646   v8::ExtensionConfiguration extensions(1, extension_names);
6647   v8::Handle<Context> context =
6648       Context::New(CcTest::isolate(), &extensions);
6649   Context::Scope lock(context);
6650   v8::Handle<Value> result = CompileRun("Foo()");
6651   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6652 }
6653
6654
6655 TEST(NullExtensions) {
6656   v8::HandleScope handle_scope(CcTest::isolate());
6657   v8::RegisterExtension(new Extension("nulltest", NULL));
6658   const char* extension_names[] = { "nulltest" };
6659   v8::ExtensionConfiguration extensions(1, extension_names);
6660   v8::Handle<Context> context =
6661       Context::New(CcTest::isolate(), &extensions);
6662   Context::Scope lock(context);
6663   v8::Handle<Value> result = CompileRun("1+3");
6664   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6665 }
6666
6667
6668 static const char* kEmbeddedExtensionSource =
6669     "function Ret54321(){return 54321;}~~@@$"
6670     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6671 static const int kEmbeddedExtensionSourceValidLen = 34;
6672
6673
6674 TEST(ExtensionMissingSourceLength) {
6675   v8::HandleScope handle_scope(CcTest::isolate());
6676   v8::RegisterExtension(new Extension("srclentest_fail",
6677                                       kEmbeddedExtensionSource));
6678   const char* extension_names[] = { "srclentest_fail" };
6679   v8::ExtensionConfiguration extensions(1, extension_names);
6680   v8::Handle<Context> context =
6681       Context::New(CcTest::isolate(), &extensions);
6682   CHECK_EQ(0, *context);
6683 }
6684
6685
6686 TEST(ExtensionWithSourceLength) {
6687   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6688        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6689     v8::HandleScope handle_scope(CcTest::isolate());
6690     i::ScopedVector<char> extension_name(32);
6691     i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6692     v8::RegisterExtension(new Extension(extension_name.start(),
6693                                         kEmbeddedExtensionSource, 0, 0,
6694                                         source_len));
6695     const char* extension_names[1] = { extension_name.start() };
6696     v8::ExtensionConfiguration extensions(1, extension_names);
6697     v8::Handle<Context> context =
6698       Context::New(CcTest::isolate(), &extensions);
6699     if (source_len == kEmbeddedExtensionSourceValidLen) {
6700       Context::Scope lock(context);
6701       v8::Handle<Value> result = CompileRun("Ret54321()");
6702       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6703     } else {
6704       // Anything but exactly the right length should fail to compile.
6705       CHECK_EQ(0, *context);
6706     }
6707   }
6708 }
6709
6710
6711 static const char* kEvalExtensionSource1 =
6712   "function UseEval1() {"
6713   "  var x = 42;"
6714   "  return eval('x');"
6715   "}";
6716
6717
6718 static const char* kEvalExtensionSource2 =
6719   "(function() {"
6720   "  var x = 42;"
6721   "  function e() {"
6722   "    return eval('x');"
6723   "  }"
6724   "  this.UseEval2 = e;"
6725   "})()";
6726
6727
6728 TEST(UseEvalFromExtension) {
6729   v8::HandleScope handle_scope(CcTest::isolate());
6730   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6731   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6732   const char* extension_names[] = { "evaltest1", "evaltest2" };
6733   v8::ExtensionConfiguration extensions(2, extension_names);
6734   v8::Handle<Context> context =
6735       Context::New(CcTest::isolate(), &extensions);
6736   Context::Scope lock(context);
6737   v8::Handle<Value> result = CompileRun("UseEval1()");
6738   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6739   result = CompileRun("UseEval2()");
6740   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6741 }
6742
6743
6744 static const char* kWithExtensionSource1 =
6745   "function UseWith1() {"
6746   "  var x = 42;"
6747   "  with({x:87}) { return x; }"
6748   "}";
6749
6750
6751
6752 static const char* kWithExtensionSource2 =
6753   "(function() {"
6754   "  var x = 42;"
6755   "  function e() {"
6756   "    with ({x:87}) { return x; }"
6757   "  }"
6758   "  this.UseWith2 = e;"
6759   "})()";
6760
6761
6762 TEST(UseWithFromExtension) {
6763   v8::HandleScope handle_scope(CcTest::isolate());
6764   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6765   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6766   const char* extension_names[] = { "withtest1", "withtest2" };
6767   v8::ExtensionConfiguration extensions(2, extension_names);
6768   v8::Handle<Context> context =
6769       Context::New(CcTest::isolate(), &extensions);
6770   Context::Scope lock(context);
6771   v8::Handle<Value> result = CompileRun("UseWith1()");
6772   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6773   result = CompileRun("UseWith2()");
6774   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6775 }
6776
6777
6778 TEST(AutoExtensions) {
6779   v8::HandleScope handle_scope(CcTest::isolate());
6780   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6781   extension->set_auto_enable(true);
6782   v8::RegisterExtension(extension);
6783   v8::Handle<Context> context =
6784       Context::New(CcTest::isolate());
6785   Context::Scope lock(context);
6786   v8::Handle<Value> result = CompileRun("Foo()");
6787   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6788 }
6789
6790
6791 static const char* kSyntaxErrorInExtensionSource =
6792     "[";
6793
6794
6795 // Test that a syntax error in an extension does not cause a fatal
6796 // error but results in an empty context.
6797 TEST(SyntaxErrorExtensions) {
6798   v8::HandleScope handle_scope(CcTest::isolate());
6799   v8::RegisterExtension(new Extension("syntaxerror",
6800                                       kSyntaxErrorInExtensionSource));
6801   const char* extension_names[] = { "syntaxerror" };
6802   v8::ExtensionConfiguration extensions(1, extension_names);
6803   v8::Handle<Context> context =
6804       Context::New(CcTest::isolate(), &extensions);
6805   CHECK(context.IsEmpty());
6806 }
6807
6808
6809 static const char* kExceptionInExtensionSource =
6810     "throw 42";
6811
6812
6813 // Test that an exception when installing an extension does not cause
6814 // a fatal error but results in an empty context.
6815 TEST(ExceptionExtensions) {
6816   v8::HandleScope handle_scope(CcTest::isolate());
6817   v8::RegisterExtension(new Extension("exception",
6818                                       kExceptionInExtensionSource));
6819   const char* extension_names[] = { "exception" };
6820   v8::ExtensionConfiguration extensions(1, extension_names);
6821   v8::Handle<Context> context =
6822       Context::New(CcTest::isolate(), &extensions);
6823   CHECK(context.IsEmpty());
6824 }
6825
6826
6827 static const char* kNativeCallInExtensionSource =
6828     "function call_runtime_last_index_of(x) {"
6829     "  return %StringLastIndexOf(x, 'bob', 10);"
6830     "}";
6831
6832
6833 static const char* kNativeCallTest =
6834     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6835
6836 // Test that a native runtime calls are supported in extensions.
6837 TEST(NativeCallInExtensions) {
6838   v8::HandleScope handle_scope(CcTest::isolate());
6839   v8::RegisterExtension(new Extension("nativecall",
6840                                       kNativeCallInExtensionSource));
6841   const char* extension_names[] = { "nativecall" };
6842   v8::ExtensionConfiguration extensions(1, extension_names);
6843   v8::Handle<Context> context =
6844       Context::New(CcTest::isolate(), &extensions);
6845   Context::Scope lock(context);
6846   v8::Handle<Value> result = CompileRun(kNativeCallTest);
6847   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6848 }
6849
6850
6851 class NativeFunctionExtension : public Extension {
6852  public:
6853   NativeFunctionExtension(const char* name,
6854                           const char* source,
6855                           v8::FunctionCallback fun = &Echo)
6856       : Extension(name, source),
6857         function_(fun) { }
6858
6859   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6860       v8::Isolate* isolate,
6861       v8::Handle<v8::String> name) {
6862     return v8::FunctionTemplate::New(isolate, function_);
6863   }
6864
6865   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6866     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6867   }
6868  private:
6869   v8::FunctionCallback function_;
6870 };
6871
6872
6873 TEST(NativeFunctionDeclaration) {
6874   v8::HandleScope handle_scope(CcTest::isolate());
6875   const char* name = "nativedecl";
6876   v8::RegisterExtension(new NativeFunctionExtension(name,
6877                                                     "native function foo();"));
6878   const char* extension_names[] = { name };
6879   v8::ExtensionConfiguration extensions(1, extension_names);
6880   v8::Handle<Context> context =
6881       Context::New(CcTest::isolate(), &extensions);
6882   Context::Scope lock(context);
6883   v8::Handle<Value> result = CompileRun("foo(42);");
6884   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6885 }
6886
6887
6888 TEST(NativeFunctionDeclarationError) {
6889   v8::HandleScope handle_scope(CcTest::isolate());
6890   const char* name = "nativedeclerr";
6891   // Syntax error in extension code.
6892   v8::RegisterExtension(new NativeFunctionExtension(name,
6893                                                     "native\nfunction foo();"));
6894   const char* extension_names[] = { name };
6895   v8::ExtensionConfiguration extensions(1, extension_names);
6896   v8::Handle<Context> context =
6897       Context::New(CcTest::isolate(), &extensions);
6898   CHECK(context.IsEmpty());
6899 }
6900
6901
6902 TEST(NativeFunctionDeclarationErrorEscape) {
6903   v8::HandleScope handle_scope(CcTest::isolate());
6904   const char* name = "nativedeclerresc";
6905   // Syntax error in extension code - escape code in "native" means that
6906   // it's not treated as a keyword.
6907   v8::RegisterExtension(new NativeFunctionExtension(
6908       name,
6909       "nativ\\u0065 function foo();"));
6910   const char* extension_names[] = { name };
6911   v8::ExtensionConfiguration extensions(1, extension_names);
6912   v8::Handle<Context> context =
6913       Context::New(CcTest::isolate(), &extensions);
6914   CHECK(context.IsEmpty());
6915 }
6916
6917
6918 static void CheckDependencies(const char* name, const char* expected) {
6919   v8::HandleScope handle_scope(CcTest::isolate());
6920   v8::ExtensionConfiguration config(1, &name);
6921   LocalContext context(&config);
6922   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6923            context->Global()->Get(v8_str("loaded")));
6924 }
6925
6926
6927 /*
6928  * Configuration:
6929  *
6930  *     /-- B <--\
6931  * A <-          -- D <-- E
6932  *     \-- C <--/
6933  */
6934 THREADED_TEST(ExtensionDependency) {
6935   static const char* kEDeps[] = { "D" };
6936   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6937   static const char* kDDeps[] = { "B", "C" };
6938   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6939   static const char* kBCDeps[] = { "A" };
6940   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6941   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6942   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6943   CheckDependencies("A", "undefinedA");
6944   CheckDependencies("B", "undefinedAB");
6945   CheckDependencies("C", "undefinedAC");
6946   CheckDependencies("D", "undefinedABCD");
6947   CheckDependencies("E", "undefinedABCDE");
6948   v8::HandleScope handle_scope(CcTest::isolate());
6949   static const char* exts[2] = { "C", "E" };
6950   v8::ExtensionConfiguration config(2, exts);
6951   LocalContext context(&config);
6952   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6953 }
6954
6955
6956 static const char* kExtensionTestScript =
6957   "native function A();"
6958   "native function B();"
6959   "native function C();"
6960   "function Foo(i) {"
6961   "  if (i == 0) return A();"
6962   "  if (i == 1) return B();"
6963   "  if (i == 2) return C();"
6964   "}";
6965
6966
6967 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6968   ApiTestFuzzer::Fuzz();
6969   if (args.IsConstructCall()) {
6970     args.This()->Set(v8_str("data"), args.Data());
6971     args.GetReturnValue().SetNull();
6972     return;
6973   }
6974   args.GetReturnValue().Set(args.Data());
6975 }
6976
6977
6978 class FunctionExtension : public Extension {
6979  public:
6980   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
6981   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6982       v8::Isolate* isolate,
6983       v8::Handle<String> name);
6984 };
6985
6986
6987 static int lookup_count = 0;
6988 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
6989     v8::Isolate* isolate, v8::Handle<String> name) {
6990   lookup_count++;
6991   if (name->Equals(v8_str("A"))) {
6992     return v8::FunctionTemplate::New(
6993         isolate, CallFun, v8::Integer::New(isolate, 8));
6994   } else if (name->Equals(v8_str("B"))) {
6995     return v8::FunctionTemplate::New(
6996         isolate, CallFun, v8::Integer::New(isolate, 7));
6997   } else if (name->Equals(v8_str("C"))) {
6998     return v8::FunctionTemplate::New(
6999         isolate, CallFun, v8::Integer::New(isolate, 6));
7000   } else {
7001     return v8::Handle<v8::FunctionTemplate>();
7002   }
7003 }
7004
7005
7006 THREADED_TEST(FunctionLookup) {
7007   v8::RegisterExtension(new FunctionExtension());
7008   v8::HandleScope handle_scope(CcTest::isolate());
7009   static const char* exts[1] = { "functiontest" };
7010   v8::ExtensionConfiguration config(1, exts);
7011   LocalContext context(&config);
7012   CHECK_EQ(3, lookup_count);
7013   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7014            CompileRun("Foo(0)"));
7015   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7016            CompileRun("Foo(1)"));
7017   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7018            CompileRun("Foo(2)"));
7019 }
7020
7021
7022 THREADED_TEST(NativeFunctionConstructCall) {
7023   v8::RegisterExtension(new FunctionExtension());
7024   v8::HandleScope handle_scope(CcTest::isolate());
7025   static const char* exts[1] = { "functiontest" };
7026   v8::ExtensionConfiguration config(1, exts);
7027   LocalContext context(&config);
7028   for (int i = 0; i < 10; i++) {
7029     // Run a few times to ensure that allocation of objects doesn't
7030     // change behavior of a constructor function.
7031     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7032              CompileRun("(new A()).data"));
7033     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7034              CompileRun("(new B()).data"));
7035     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7036              CompileRun("(new C()).data"));
7037   }
7038 }
7039
7040
7041 static const char* last_location;
7042 static const char* last_message;
7043 void StoringErrorCallback(const char* location, const char* message) {
7044   if (last_location == NULL) {
7045     last_location = location;
7046     last_message = message;
7047   }
7048 }
7049
7050
7051 // ErrorReporting creates a circular extensions configuration and
7052 // tests that the fatal error handler gets called.  This renders V8
7053 // unusable and therefore this test cannot be run in parallel.
7054 TEST(ErrorReporting) {
7055   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7056   static const char* aDeps[] = { "B" };
7057   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7058   static const char* bDeps[] = { "A" };
7059   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7060   last_location = NULL;
7061   v8::ExtensionConfiguration config(1, bDeps);
7062   v8::Handle<Context> context =
7063       Context::New(CcTest::isolate(), &config);
7064   CHECK(context.IsEmpty());
7065   CHECK_NE(last_location, NULL);
7066 }
7067
7068
7069 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7070                                              v8::Handle<Value> data) {
7071   CHECK(message->GetScriptResourceName()->IsUndefined());
7072   CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7073   message->GetLineNumber();
7074   message->GetSourceLine();
7075 }
7076
7077
7078 THREADED_TEST(ErrorWithMissingScriptInfo) {
7079   LocalContext context;
7080   v8::HandleScope scope(context->GetIsolate());
7081   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7082   CompileRun("throw Error()");
7083   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7084 }
7085
7086
7087 struct FlagAndPersistent {
7088   bool flag;
7089   v8::Persistent<v8::Object> handle;
7090 };
7091
7092
7093 static void DisposeAndSetFlag(
7094     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7095   data.GetParameter()->handle.Reset();
7096   data.GetParameter()->flag = true;
7097 }
7098
7099
7100 THREADED_TEST(IndependentWeakHandle) {
7101   v8::Isolate* iso = CcTest::isolate();
7102   v8::HandleScope scope(iso);
7103   v8::Handle<Context> context = Context::New(iso);
7104   Context::Scope context_scope(context);
7105
7106   FlagAndPersistent object_a, object_b;
7107
7108   {
7109     v8::HandleScope handle_scope(iso);
7110     object_a.handle.Reset(iso, v8::Object::New(iso));
7111     object_b.handle.Reset(iso, v8::Object::New(iso));
7112   }
7113
7114   object_a.flag = false;
7115   object_b.flag = false;
7116   object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7117   object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7118   CHECK(!object_b.handle.IsIndependent());
7119   object_a.handle.MarkIndependent();
7120   object_b.handle.MarkIndependent();
7121   CHECK(object_b.handle.IsIndependent());
7122   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7123   CHECK(object_a.flag);
7124   CHECK(object_b.flag);
7125 }
7126
7127
7128 static void InvokeScavenge() {
7129   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7130 }
7131
7132
7133 static void InvokeMarkSweep() {
7134   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7135 }
7136
7137
7138 static void ForceScavenge(
7139     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7140   data.GetParameter()->handle.Reset();
7141   data.GetParameter()->flag = true;
7142   InvokeScavenge();
7143 }
7144
7145
7146 static void ForceMarkSweep(
7147     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7148   data.GetParameter()->handle.Reset();
7149   data.GetParameter()->flag = true;
7150   InvokeMarkSweep();
7151 }
7152
7153
7154 THREADED_TEST(GCFromWeakCallbacks) {
7155   v8::Isolate* isolate = CcTest::isolate();
7156   v8::HandleScope scope(isolate);
7157   v8::Handle<Context> context = Context::New(isolate);
7158   Context::Scope context_scope(context);
7159
7160   static const int kNumberOfGCTypes = 2;
7161   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7162       Callback;
7163   Callback gc_forcing_callback[kNumberOfGCTypes] =
7164       {&ForceScavenge, &ForceMarkSweep};
7165
7166   typedef void (*GCInvoker)();
7167   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7168
7169   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7170     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7171       FlagAndPersistent object;
7172       {
7173         v8::HandleScope handle_scope(isolate);
7174         object.handle.Reset(isolate, v8::Object::New(isolate));
7175       }
7176       object.flag = false;
7177       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7178       object.handle.MarkIndependent();
7179       invoke_gc[outer_gc]();
7180       CHECK(object.flag);
7181     }
7182   }
7183 }
7184
7185
7186 static void RevivingCallback(
7187     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7188   data.GetParameter()->handle.ClearWeak();
7189   data.GetParameter()->flag = true;
7190 }
7191
7192
7193 THREADED_TEST(IndependentHandleRevival) {
7194   v8::Isolate* isolate = CcTest::isolate();
7195   v8::HandleScope scope(isolate);
7196   v8::Handle<Context> context = Context::New(isolate);
7197   Context::Scope context_scope(context);
7198
7199   FlagAndPersistent object;
7200   {
7201     v8::HandleScope handle_scope(isolate);
7202     v8::Local<v8::Object> o = v8::Object::New(isolate);
7203     object.handle.Reset(isolate, o);
7204     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7205     v8::Local<String> y_str = v8_str("y");
7206     o->Set(y_str, y_str);
7207   }
7208   object.flag = false;
7209   object.handle.SetWeak(&object, &RevivingCallback);
7210   object.handle.MarkIndependent();
7211   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7212   CHECK(object.flag);
7213   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7214   {
7215     v8::HandleScope handle_scope(isolate);
7216     v8::Local<v8::Object> o =
7217         v8::Local<v8::Object>::New(isolate, object.handle);
7218     v8::Local<String> y_str = v8_str("y");
7219     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7220     CHECK(o->Get(y_str)->Equals(y_str));
7221   }
7222 }
7223
7224
7225 v8::Handle<Function> args_fun;
7226
7227
7228 static void ArgumentsTestCallback(
7229     const v8::FunctionCallbackInfo<v8::Value>& args) {
7230   ApiTestFuzzer::Fuzz();
7231   v8::Isolate* isolate = args.GetIsolate();
7232   CHECK_EQ(args_fun, args.Callee());
7233   CHECK_EQ(3, args.Length());
7234   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7235   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7236   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7237   CHECK_EQ(v8::Undefined(isolate), args[3]);
7238   v8::HandleScope scope(args.GetIsolate());
7239   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7240 }
7241
7242
7243 THREADED_TEST(Arguments) {
7244   v8::Isolate* isolate = CcTest::isolate();
7245   v8::HandleScope scope(isolate);
7246   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7247   global->Set(v8_str("f"),
7248               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7249   LocalContext context(NULL, global);
7250   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7251   v8_compile("f(1, 2, 3)")->Run();
7252 }
7253
7254
7255 static void NoBlockGetterX(Local<String> name,
7256                            const v8::PropertyCallbackInfo<v8::Value>&) {
7257 }
7258
7259
7260 static void NoBlockGetterI(uint32_t index,
7261                            const v8::PropertyCallbackInfo<v8::Value>&) {
7262 }
7263
7264
7265 static void PDeleter(Local<String> name,
7266                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7267   if (!name->Equals(v8_str("foo"))) {
7268     return;  // not intercepted
7269   }
7270
7271   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7272 }
7273
7274
7275 static void IDeleter(uint32_t index,
7276                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7277   if (index != 2) {
7278     return;  // not intercepted
7279   }
7280
7281   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7282 }
7283
7284
7285 THREADED_TEST(Deleter) {
7286   v8::Isolate* isolate = CcTest::isolate();
7287   v8::HandleScope scope(isolate);
7288   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7289   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7290   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7291   LocalContext context;
7292   context->Global()->Set(v8_str("k"), obj->NewInstance());
7293   CompileRun(
7294     "k.foo = 'foo';"
7295     "k.bar = 'bar';"
7296     "k[2] = 2;"
7297     "k[4] = 4;");
7298   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7299   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7300
7301   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7302   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7303
7304   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7305   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7306
7307   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7308   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7309 }
7310
7311
7312 static void GetK(Local<String> name,
7313                  const v8::PropertyCallbackInfo<v8::Value>& info) {
7314   ApiTestFuzzer::Fuzz();
7315   if (name->Equals(v8_str("foo")) ||
7316       name->Equals(v8_str("bar")) ||
7317       name->Equals(v8_str("baz"))) {
7318     info.GetReturnValue().SetUndefined();
7319   }
7320 }
7321
7322
7323 static void IndexedGetK(uint32_t index,
7324                         const v8::PropertyCallbackInfo<v8::Value>& info) {
7325   ApiTestFuzzer::Fuzz();
7326   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7327 }
7328
7329
7330 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7331   ApiTestFuzzer::Fuzz();
7332   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7333   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7334   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7335   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7336   info.GetReturnValue().Set(result);
7337 }
7338
7339
7340 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7341   ApiTestFuzzer::Fuzz();
7342   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7343   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7344   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7345   info.GetReturnValue().Set(result);
7346 }
7347
7348
7349 THREADED_TEST(Enumerators) {
7350   v8::Isolate* isolate = CcTest::isolate();
7351   v8::HandleScope scope(isolate);
7352   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7353   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7354   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7355   LocalContext context;
7356   context->Global()->Set(v8_str("k"), obj->NewInstance());
7357   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7358     "k[10] = 0;"
7359     "k.a = 0;"
7360     "k[5] = 0;"
7361     "k.b = 0;"
7362     "k[4294967295] = 0;"
7363     "k.c = 0;"
7364     "k[4294967296] = 0;"
7365     "k.d = 0;"
7366     "k[140000] = 0;"
7367     "k.e = 0;"
7368     "k[30000000000] = 0;"
7369     "k.f = 0;"
7370     "var result = [];"
7371     "for (var prop in k) {"
7372     "  result.push(prop);"
7373     "}"
7374     "result"));
7375   // Check that we get all the property names returned including the
7376   // ones from the enumerators in the right order: indexed properties
7377   // in numerical order, indexed interceptor properties, named
7378   // properties in insertion order, named interceptor properties.
7379   // This order is not mandated by the spec, so this test is just
7380   // documenting our behavior.
7381   CHECK_EQ(17, result->Length());
7382   // Indexed properties in numerical order.
7383   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7384   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7385   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7386   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7387   // Indexed interceptor properties in the order they are returned
7388   // from the enumerator interceptor.
7389   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7390   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7391   // Named properties in insertion order.
7392   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7393   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7394   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7395   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7396   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7397   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7398   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7399   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7400   // Named interceptor properties.
7401   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7402   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7403   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7404 }
7405
7406
7407 int p_getter_count;
7408 int p_getter_count2;
7409
7410
7411 static void PGetter(Local<String> name,
7412                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7413   ApiTestFuzzer::Fuzz();
7414   p_getter_count++;
7415   v8::Handle<v8::Object> global =
7416       info.GetIsolate()->GetCurrentContext()->Global();
7417   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7418   if (name->Equals(v8_str("p1"))) {
7419     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7420   } else if (name->Equals(v8_str("p2"))) {
7421     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7422   } else if (name->Equals(v8_str("p3"))) {
7423     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7424   } else if (name->Equals(v8_str("p4"))) {
7425     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7426   }
7427 }
7428
7429
7430 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7431   ApiTestFuzzer::Fuzz();
7432   LocalContext context;
7433   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7434   CompileRun(
7435     "o1.__proto__ = { };"
7436     "var o2 = { __proto__: o1 };"
7437     "var o3 = { __proto__: o2 };"
7438     "var o4 = { __proto__: o3 };"
7439     "for (var i = 0; i < 10; i++) o4.p4;"
7440     "for (var i = 0; i < 10; i++) o3.p3;"
7441     "for (var i = 0; i < 10; i++) o2.p2;"
7442     "for (var i = 0; i < 10; i++) o1.p1;");
7443 }
7444
7445
7446 static void PGetter2(Local<String> name,
7447                      const v8::PropertyCallbackInfo<v8::Value>& info) {
7448   ApiTestFuzzer::Fuzz();
7449   p_getter_count2++;
7450   v8::Handle<v8::Object> global =
7451       info.GetIsolate()->GetCurrentContext()->Global();
7452   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7453   if (name->Equals(v8_str("p1"))) {
7454     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7455   } else if (name->Equals(v8_str("p2"))) {
7456     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7457   } else if (name->Equals(v8_str("p3"))) {
7458     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7459   } else if (name->Equals(v8_str("p4"))) {
7460     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7461   }
7462 }
7463
7464
7465 THREADED_TEST(GetterHolders) {
7466   v8::Isolate* isolate = CcTest::isolate();
7467   v8::HandleScope scope(isolate);
7468   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7469   obj->SetAccessor(v8_str("p1"), PGetter);
7470   obj->SetAccessor(v8_str("p2"), PGetter);
7471   obj->SetAccessor(v8_str("p3"), PGetter);
7472   obj->SetAccessor(v8_str("p4"), PGetter);
7473   p_getter_count = 0;
7474   RunHolderTest(obj);
7475   CHECK_EQ(40, p_getter_count);
7476 }
7477
7478
7479 THREADED_TEST(PreInterceptorHolders) {
7480   v8::Isolate* isolate = CcTest::isolate();
7481   v8::HandleScope scope(isolate);
7482   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7483   obj->SetNamedPropertyHandler(PGetter2);
7484   p_getter_count2 = 0;
7485   RunHolderTest(obj);
7486   CHECK_EQ(40, p_getter_count2);
7487 }
7488
7489
7490 THREADED_TEST(ObjectInstantiation) {
7491   v8::Isolate* isolate = CcTest::isolate();
7492   v8::HandleScope scope(isolate);
7493   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7494   templ->SetAccessor(v8_str("t"), PGetter2);
7495   LocalContext context;
7496   context->Global()->Set(v8_str("o"), templ->NewInstance());
7497   for (int i = 0; i < 100; i++) {
7498     v8::HandleScope inner_scope(CcTest::isolate());
7499     v8::Handle<v8::Object> obj = templ->NewInstance();
7500     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7501     context->Global()->Set(v8_str("o2"), obj);
7502     v8::Handle<Value> value =
7503         CompileRun("o.__proto__ === o2.__proto__");
7504     CHECK_EQ(v8::True(isolate), value);
7505     context->Global()->Set(v8_str("o"), obj);
7506   }
7507 }
7508
7509
7510 static int StrCmp16(uint16_t* a, uint16_t* b) {
7511   while (true) {
7512     if (*a == 0 && *b == 0) return 0;
7513     if (*a != *b) return 0 + *a - *b;
7514     a++;
7515     b++;
7516   }
7517 }
7518
7519
7520 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7521   while (true) {
7522     if (n-- == 0) return 0;
7523     if (*a == 0 && *b == 0) return 0;
7524     if (*a != *b) return 0 + *a - *b;
7525     a++;
7526     b++;
7527   }
7528 }
7529
7530
7531 int GetUtf8Length(Handle<String> str) {
7532   int len = str->Utf8Length();
7533   if (len < 0) {
7534     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7535     i::FlattenString(istr);
7536     len = str->Utf8Length();
7537   }
7538   return len;
7539 }
7540
7541
7542 THREADED_TEST(StringWrite) {
7543   LocalContext context;
7544   v8::HandleScope scope(context->GetIsolate());
7545   v8::Handle<String> str = v8_str("abcde");
7546   // abc<Icelandic eth><Unicode snowman>.
7547   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7548   v8::Handle<String> str3 = v8::String::NewFromUtf8(
7549       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7550   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7551   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7552   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7553       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7554   // single lead surrogate
7555   uint16_t lead[1] = { 0xd800 };
7556   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7557       context->GetIsolate(), lead, v8::String::kNormalString, 1);
7558   // single trail surrogate
7559   uint16_t trail[1] = { 0xdc00 };
7560   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7561       context->GetIsolate(), trail, v8::String::kNormalString, 1);
7562   // surrogate pair
7563   uint16_t pair[2] = { 0xd800,  0xdc00 };
7564   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7565       context->GetIsolate(), pair, v8::String::kNormalString, 2);
7566   const int kStride = 4;  // Must match stride in for loops in JS below.
7567   CompileRun(
7568       "var left = '';"
7569       "for (var i = 0; i < 0xd800; i += 4) {"
7570       "  left = left + String.fromCharCode(i);"
7571       "}");
7572   CompileRun(
7573       "var right = '';"
7574       "for (var i = 0; i < 0xd800; i += 4) {"
7575       "  right = String.fromCharCode(i) + right;"
7576       "}");
7577   v8::Handle<v8::Object> global = context->Global();
7578   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7579   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7580
7581   CHECK_EQ(5, str2->Length());
7582   CHECK_EQ(0xd800 / kStride, left_tree->Length());
7583   CHECK_EQ(0xd800 / kStride, right_tree->Length());
7584
7585   char buf[100];
7586   char utf8buf[0xd800 * 3];
7587   uint16_t wbuf[100];
7588   int len;
7589   int charlen;
7590
7591   memset(utf8buf, 0x1, 1000);
7592   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7593   CHECK_EQ(9, len);
7594   CHECK_EQ(5, charlen);
7595   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7596
7597   memset(utf8buf, 0x1, 1000);
7598   len = str2->WriteUtf8(utf8buf, 8, &charlen);
7599   CHECK_EQ(8, len);
7600   CHECK_EQ(5, charlen);
7601   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7602
7603   memset(utf8buf, 0x1, 1000);
7604   len = str2->WriteUtf8(utf8buf, 7, &charlen);
7605   CHECK_EQ(5, len);
7606   CHECK_EQ(4, charlen);
7607   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7608
7609   memset(utf8buf, 0x1, 1000);
7610   len = str2->WriteUtf8(utf8buf, 6, &charlen);
7611   CHECK_EQ(5, len);
7612   CHECK_EQ(4, charlen);
7613   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7614
7615   memset(utf8buf, 0x1, 1000);
7616   len = str2->WriteUtf8(utf8buf, 5, &charlen);
7617   CHECK_EQ(5, len);
7618   CHECK_EQ(4, charlen);
7619   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7620
7621   memset(utf8buf, 0x1, 1000);
7622   len = str2->WriteUtf8(utf8buf, 4, &charlen);
7623   CHECK_EQ(3, len);
7624   CHECK_EQ(3, charlen);
7625   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7626
7627   memset(utf8buf, 0x1, 1000);
7628   len = str2->WriteUtf8(utf8buf, 3, &charlen);
7629   CHECK_EQ(3, len);
7630   CHECK_EQ(3, charlen);
7631   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7632
7633   memset(utf8buf, 0x1, 1000);
7634   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7635   CHECK_EQ(2, len);
7636   CHECK_EQ(2, charlen);
7637   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7638
7639   // allow orphan surrogates by default
7640   memset(utf8buf, 0x1, 1000);
7641   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7642   CHECK_EQ(13, len);
7643   CHECK_EQ(8, charlen);
7644   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7645
7646   // replace orphan surrogates with unicode replacement character
7647   memset(utf8buf, 0x1, 1000);
7648   len = orphans_str->WriteUtf8(utf8buf,
7649                                sizeof(utf8buf),
7650                                &charlen,
7651                                String::REPLACE_INVALID_UTF8);
7652   CHECK_EQ(13, len);
7653   CHECK_EQ(8, charlen);
7654   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7655
7656   // replace single lead surrogate with unicode replacement character
7657   memset(utf8buf, 0x1, 1000);
7658   len = lead_str->WriteUtf8(utf8buf,
7659                             sizeof(utf8buf),
7660                             &charlen,
7661                             String::REPLACE_INVALID_UTF8);
7662   CHECK_EQ(4, len);
7663   CHECK_EQ(1, charlen);
7664   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7665
7666   // replace single trail surrogate with unicode replacement character
7667   memset(utf8buf, 0x1, 1000);
7668   len = trail_str->WriteUtf8(utf8buf,
7669                              sizeof(utf8buf),
7670                              &charlen,
7671                              String::REPLACE_INVALID_UTF8);
7672   CHECK_EQ(4, len);
7673   CHECK_EQ(1, charlen);
7674   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7675
7676   // do not replace / write anything if surrogate pair does not fit the buffer
7677   // space
7678   memset(utf8buf, 0x1, 1000);
7679   len = pair_str->WriteUtf8(utf8buf,
7680                              3,
7681                              &charlen,
7682                              String::REPLACE_INVALID_UTF8);
7683   CHECK_EQ(0, len);
7684   CHECK_EQ(0, charlen);
7685
7686   memset(utf8buf, 0x1, sizeof(utf8buf));
7687   len = GetUtf8Length(left_tree);
7688   int utf8_expected =
7689       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7690   CHECK_EQ(utf8_expected, len);
7691   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7692   CHECK_EQ(utf8_expected, len);
7693   CHECK_EQ(0xd800 / kStride, charlen);
7694   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7695   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7696   CHECK_EQ(0xc0 - kStride,
7697            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7698   CHECK_EQ(1, utf8buf[utf8_expected]);
7699
7700   memset(utf8buf, 0x1, sizeof(utf8buf));
7701   len = GetUtf8Length(right_tree);
7702   CHECK_EQ(utf8_expected, len);
7703   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7704   CHECK_EQ(utf8_expected, len);
7705   CHECK_EQ(0xd800 / kStride, charlen);
7706   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7707   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7708   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7709   CHECK_EQ(1, utf8buf[utf8_expected]);
7710
7711   memset(buf, 0x1, sizeof(buf));
7712   memset(wbuf, 0x1, sizeof(wbuf));
7713   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7714   CHECK_EQ(5, len);
7715   len = str->Write(wbuf);
7716   CHECK_EQ(5, len);
7717   CHECK_EQ(0, strcmp("abcde", buf));
7718   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7719   CHECK_EQ(0, StrCmp16(answer1, wbuf));
7720
7721   memset(buf, 0x1, sizeof(buf));
7722   memset(wbuf, 0x1, sizeof(wbuf));
7723   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7724   CHECK_EQ(4, len);
7725   len = str->Write(wbuf, 0, 4);
7726   CHECK_EQ(4, len);
7727   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7728   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7729   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7730
7731   memset(buf, 0x1, sizeof(buf));
7732   memset(wbuf, 0x1, sizeof(wbuf));
7733   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7734   CHECK_EQ(5, len);
7735   len = str->Write(wbuf, 0, 5);
7736   CHECK_EQ(5, len);
7737   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7738   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7739   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7740
7741   memset(buf, 0x1, sizeof(buf));
7742   memset(wbuf, 0x1, sizeof(wbuf));
7743   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7744   CHECK_EQ(5, len);
7745   len = str->Write(wbuf, 0, 6);
7746   CHECK_EQ(5, len);
7747   CHECK_EQ(0, strcmp("abcde", buf));
7748   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7749   CHECK_EQ(0, StrCmp16(answer4, wbuf));
7750
7751   memset(buf, 0x1, sizeof(buf));
7752   memset(wbuf, 0x1, sizeof(wbuf));
7753   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7754   CHECK_EQ(1, len);
7755   len = str->Write(wbuf, 4, -1);
7756   CHECK_EQ(1, len);
7757   CHECK_EQ(0, strcmp("e", buf));
7758   uint16_t answer5[] = {'e', '\0'};
7759   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7760
7761   memset(buf, 0x1, sizeof(buf));
7762   memset(wbuf, 0x1, sizeof(wbuf));
7763   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7764   CHECK_EQ(1, len);
7765   len = str->Write(wbuf, 4, 6);
7766   CHECK_EQ(1, len);
7767   CHECK_EQ(0, strcmp("e", buf));
7768   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7769
7770   memset(buf, 0x1, sizeof(buf));
7771   memset(wbuf, 0x1, sizeof(wbuf));
7772   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7773   CHECK_EQ(1, len);
7774   len = str->Write(wbuf, 4, 1);
7775   CHECK_EQ(1, len);
7776   CHECK_EQ(0, strncmp("e\1", buf, 2));
7777   uint16_t answer6[] = {'e', 0x101};
7778   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7779
7780   memset(buf, 0x1, sizeof(buf));
7781   memset(wbuf, 0x1, sizeof(wbuf));
7782   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7783   CHECK_EQ(1, len);
7784   len = str->Write(wbuf, 3, 1);
7785   CHECK_EQ(1, len);
7786   CHECK_EQ(0, strncmp("d\1", buf, 2));
7787   uint16_t answer7[] = {'d', 0x101};
7788   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7789
7790   memset(wbuf, 0x1, sizeof(wbuf));
7791   wbuf[5] = 'X';
7792   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7793   CHECK_EQ(5, len);
7794   CHECK_EQ('X', wbuf[5]);
7795   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7796   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7797   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7798   CHECK_NE(0, StrCmp16(answer8b, wbuf));
7799   wbuf[5] = '\0';
7800   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7801
7802   memset(buf, 0x1, sizeof(buf));
7803   buf[5] = 'X';
7804   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7805                           0,
7806                           6,
7807                           String::NO_NULL_TERMINATION);
7808   CHECK_EQ(5, len);
7809   CHECK_EQ('X', buf[5]);
7810   CHECK_EQ(0, strncmp("abcde", buf, 5));
7811   CHECK_NE(0, strcmp("abcde", buf));
7812   buf[5] = '\0';
7813   CHECK_EQ(0, strcmp("abcde", buf));
7814
7815   memset(utf8buf, 0x1, sizeof(utf8buf));
7816   utf8buf[8] = 'X';
7817   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7818                         String::NO_NULL_TERMINATION);
7819   CHECK_EQ(8, len);
7820   CHECK_EQ('X', utf8buf[8]);
7821   CHECK_EQ(5, charlen);
7822   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7823   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7824   utf8buf[8] = '\0';
7825   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7826
7827   memset(utf8buf, 0x1, sizeof(utf8buf));
7828   utf8buf[5] = 'X';
7829   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7830                         String::NO_NULL_TERMINATION);
7831   CHECK_EQ(5, len);
7832   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
7833   CHECK_EQ(5, charlen);
7834   utf8buf[5] = '\0';
7835   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7836
7837   memset(buf, 0x1, sizeof(buf));
7838   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7839   CHECK_EQ(7, len);
7840   CHECK_EQ(0, strcmp("abc", buf));
7841   CHECK_EQ(0, buf[3]);
7842   CHECK_EQ(0, strcmp("def", buf + 4));
7843
7844   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7845   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7846   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7847 }
7848
7849
7850 static void Utf16Helper(
7851     LocalContext& context,
7852     const char* name,
7853     const char* lengths_name,
7854     int len) {
7855   Local<v8::Array> a =
7856       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7857   Local<v8::Array> alens =
7858       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7859   for (int i = 0; i < len; i++) {
7860     Local<v8::String> string =
7861       Local<v8::String>::Cast(a->Get(i));
7862     Local<v8::Number> expected_len =
7863       Local<v8::Number>::Cast(alens->Get(i));
7864     int length = GetUtf8Length(string);
7865     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7866   }
7867 }
7868
7869
7870 static uint16_t StringGet(Handle<String> str, int index) {
7871   i::Handle<i::String> istring =
7872       v8::Utils::OpenHandle(String::Cast(*str));
7873   return istring->Get(index);
7874 }
7875
7876
7877 static void WriteUtf8Helper(
7878     LocalContext& context,
7879     const char* name,
7880     const char* lengths_name,
7881     int len) {
7882   Local<v8::Array> b =
7883       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7884   Local<v8::Array> alens =
7885       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7886   char buffer[1000];
7887   char buffer2[1000];
7888   for (int i = 0; i < len; i++) {
7889     Local<v8::String> string =
7890       Local<v8::String>::Cast(b->Get(i));
7891     Local<v8::Number> expected_len =
7892       Local<v8::Number>::Cast(alens->Get(i));
7893     int utf8_length = static_cast<int>(expected_len->Value());
7894     for (int j = utf8_length + 1; j >= 0; j--) {
7895       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7896       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7897       int nchars;
7898       int utf8_written =
7899           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7900       int utf8_written2 =
7901           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7902       CHECK_GE(utf8_length + 1, utf8_written);
7903       CHECK_GE(utf8_length, utf8_written2);
7904       for (int k = 0; k < utf8_written2; k++) {
7905         CHECK_EQ(buffer[k], buffer2[k]);
7906       }
7907       CHECK(nchars * 3 >= utf8_written - 1);
7908       CHECK(nchars <= utf8_written);
7909       if (j == utf8_length + 1) {
7910         CHECK_EQ(utf8_written2, utf8_length);
7911         CHECK_EQ(utf8_written2 + 1, utf8_written);
7912       }
7913       CHECK_EQ(buffer[utf8_written], 42);
7914       if (j > utf8_length) {
7915         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7916         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7917         Handle<String> roundtrip = v8_str(buffer);
7918         CHECK(roundtrip->Equals(string));
7919       } else {
7920         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7921       }
7922       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7923       if (nchars >= 2) {
7924         uint16_t trail = StringGet(string, nchars - 1);
7925         uint16_t lead = StringGet(string, nchars - 2);
7926         if (((lead & 0xfc00) == 0xd800) &&
7927             ((trail & 0xfc00) == 0xdc00)) {
7928           unsigned char u1 = buffer2[utf8_written2 - 4];
7929           unsigned char u2 = buffer2[utf8_written2 - 3];
7930           unsigned char u3 = buffer2[utf8_written2 - 2];
7931           unsigned char u4 = buffer2[utf8_written2 - 1];
7932           CHECK_EQ((u1 & 0xf8), 0xf0);
7933           CHECK_EQ((u2 & 0xc0), 0x80);
7934           CHECK_EQ((u3 & 0xc0), 0x80);
7935           CHECK_EQ((u4 & 0xc0), 0x80);
7936           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7937           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7938           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7939           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7940           CHECK_EQ((u1 & 0x3), c >> 18);
7941         }
7942       }
7943     }
7944   }
7945 }
7946
7947
7948 THREADED_TEST(Utf16) {
7949   LocalContext context;
7950   v8::HandleScope scope(context->GetIsolate());
7951   CompileRun(
7952       "var pad = '01234567890123456789';"
7953       "var p = [];"
7954       "var plens = [20, 3, 3];"
7955       "p.push('01234567890123456789');"
7956       "var lead = 0xd800;"
7957       "var trail = 0xdc00;"
7958       "p.push(String.fromCharCode(0xd800));"
7959       "p.push(String.fromCharCode(0xdc00));"
7960       "var a = [];"
7961       "var b = [];"
7962       "var c = [];"
7963       "var alens = [];"
7964       "for (var i = 0; i < 3; i++) {"
7965       "  p[1] = String.fromCharCode(lead++);"
7966       "  for (var j = 0; j < 3; j++) {"
7967       "    p[2] = String.fromCharCode(trail++);"
7968       "    a.push(p[i] + p[j]);"
7969       "    b.push(p[i] + p[j]);"
7970       "    c.push(p[i] + p[j]);"
7971       "    alens.push(plens[i] + plens[j]);"
7972       "  }"
7973       "}"
7974       "alens[5] -= 2;"  // Here the surrogate pairs match up.
7975       "var a2 = [];"
7976       "var b2 = [];"
7977       "var c2 = [];"
7978       "var a2lens = [];"
7979       "for (var m = 0; m < 9; m++) {"
7980       "  for (var n = 0; n < 9; n++) {"
7981       "    a2.push(a[m] + a[n]);"
7982       "    b2.push(b[m] + b[n]);"
7983       "    var newc = 'x' + c[m] + c[n] + 'y';"
7984       "    c2.push(newc.substring(1, newc.length - 1));"
7985       "    var utf = alens[m] + alens[n];"  // And here.
7986            // The 'n's that start with 0xdc.. are 6-8
7987            // The 'm's that end with 0xd8.. are 1, 4 and 7
7988       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
7989       "    a2lens.push(utf);"
7990       "  }"
7991       "}");
7992   Utf16Helper(context, "a", "alens", 9);
7993   Utf16Helper(context, "a2", "a2lens", 81);
7994   WriteUtf8Helper(context, "b", "alens", 9);
7995   WriteUtf8Helper(context, "b2", "a2lens", 81);
7996   WriteUtf8Helper(context, "c2", "a2lens", 81);
7997 }
7998
7999
8000 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8001   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8002   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8003   return *is1 == *is2;
8004 }
8005
8006 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8007                              const char* b) {
8008   Handle<String> symbol1 =
8009       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8010   Handle<String> symbol2 =
8011       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8012   CHECK(SameSymbol(symbol1, symbol2));
8013 }
8014
8015
8016 THREADED_TEST(Utf16Symbol) {
8017   LocalContext context;
8018   v8::HandleScope scope(context->GetIsolate());
8019
8020   Handle<String> symbol1 = v8::String::NewFromUtf8(
8021       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8022   Handle<String> symbol2 = v8::String::NewFromUtf8(
8023       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8024   CHECK(SameSymbol(symbol1, symbol2));
8025
8026   SameSymbolHelper(context->GetIsolate(),
8027                    "\360\220\220\205",  // 4 byte encoding.
8028                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
8029   SameSymbolHelper(context->GetIsolate(),
8030                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
8031                    "\360\220\220\206");  // 4 byte encoding.
8032   SameSymbolHelper(context->GetIsolate(),
8033                    "x\360\220\220\205",  // 4 byte encoding.
8034                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
8035   SameSymbolHelper(context->GetIsolate(),
8036                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
8037                    "x\360\220\220\206");  // 4 byte encoding.
8038   CompileRun(
8039       "var sym0 = 'benedictus';"
8040       "var sym0b = 'S\303\270ren';"
8041       "var sym1 = '\355\240\201\355\260\207';"
8042       "var sym2 = '\360\220\220\210';"
8043       "var sym3 = 'x\355\240\201\355\260\207';"
8044       "var sym4 = 'x\360\220\220\210';"
8045       "if (sym1.length != 2) throw sym1;"
8046       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8047       "if (sym2.length != 2) throw sym2;"
8048       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8049       "if (sym3.length != 3) throw sym3;"
8050       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8051       "if (sym4.length != 3) throw sym4;"
8052       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8053   Handle<String> sym0 = v8::String::NewFromUtf8(
8054       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8055   Handle<String> sym0b = v8::String::NewFromUtf8(
8056       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8057   Handle<String> sym1 =
8058       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8059                               v8::String::kInternalizedString);
8060   Handle<String> sym2 =
8061       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8062                               v8::String::kInternalizedString);
8063   Handle<String> sym3 = v8::String::NewFromUtf8(
8064       context->GetIsolate(), "x\355\240\201\355\260\207",
8065       v8::String::kInternalizedString);
8066   Handle<String> sym4 =
8067       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8068                               v8::String::kInternalizedString);
8069   v8::Local<v8::Object> global = context->Global();
8070   Local<Value> s0 = global->Get(v8_str("sym0"));
8071   Local<Value> s0b = global->Get(v8_str("sym0b"));
8072   Local<Value> s1 = global->Get(v8_str("sym1"));
8073   Local<Value> s2 = global->Get(v8_str("sym2"));
8074   Local<Value> s3 = global->Get(v8_str("sym3"));
8075   Local<Value> s4 = global->Get(v8_str("sym4"));
8076   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8077   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8078   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8079   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8080   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8081   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8082 }
8083
8084
8085 THREADED_TEST(ToArrayIndex) {
8086   LocalContext context;
8087   v8::Isolate* isolate = context->GetIsolate();
8088   v8::HandleScope scope(isolate);
8089
8090   v8::Handle<String> str = v8_str("42");
8091   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8092   CHECK(!index.IsEmpty());
8093   CHECK_EQ(42.0, index->Uint32Value());
8094   str = v8_str("42asdf");
8095   index = str->ToArrayIndex();
8096   CHECK(index.IsEmpty());
8097   str = v8_str("-42");
8098   index = str->ToArrayIndex();
8099   CHECK(index.IsEmpty());
8100   str = v8_str("4294967295");
8101   index = str->ToArrayIndex();
8102   CHECK(!index.IsEmpty());
8103   CHECK_EQ(4294967295.0, index->Uint32Value());
8104   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8105   index = num->ToArrayIndex();
8106   CHECK(!index.IsEmpty());
8107   CHECK_EQ(1.0, index->Uint32Value());
8108   num = v8::Number::New(isolate, -1);
8109   index = num->ToArrayIndex();
8110   CHECK(index.IsEmpty());
8111   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8112   index = obj->ToArrayIndex();
8113   CHECK(index.IsEmpty());
8114 }
8115
8116
8117 THREADED_TEST(ErrorConstruction) {
8118   LocalContext context;
8119   v8::HandleScope scope(context->GetIsolate());
8120
8121   v8::Handle<String> foo = v8_str("foo");
8122   v8::Handle<String> message = v8_str("message");
8123   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8124   CHECK(range_error->IsObject());
8125   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8126   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8127   CHECK(reference_error->IsObject());
8128   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8129   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8130   CHECK(syntax_error->IsObject());
8131   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8132   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8133   CHECK(type_error->IsObject());
8134   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8135   v8::Handle<Value> error = v8::Exception::Error(foo);
8136   CHECK(error->IsObject());
8137   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8138 }
8139
8140
8141 static void YGetter(Local<String> name,
8142                     const v8::PropertyCallbackInfo<v8::Value>& info) {
8143   ApiTestFuzzer::Fuzz();
8144   info.GetReturnValue().Set(v8_num(10));
8145 }
8146
8147
8148 static void YSetter(Local<String> name,
8149                     Local<Value> value,
8150                     const v8::PropertyCallbackInfo<void>& info) {
8151   if (info.This()->Has(name)) {
8152     info.This()->Delete(name);
8153   }
8154   info.This()->Set(name, value);
8155 }
8156
8157
8158 THREADED_TEST(DeleteAccessor) {
8159   v8::Isolate* isolate = CcTest::isolate();
8160   v8::HandleScope scope(isolate);
8161   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8162   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8163   LocalContext context;
8164   v8::Handle<v8::Object> holder = obj->NewInstance();
8165   context->Global()->Set(v8_str("holder"), holder);
8166   v8::Handle<Value> result = CompileRun(
8167       "holder.y = 11; holder.y = 12; holder.y");
8168   CHECK_EQ(12, result->Uint32Value());
8169 }
8170
8171
8172 THREADED_TEST(TypeSwitch) {
8173   v8::Isolate* isolate = CcTest::isolate();
8174   v8::HandleScope scope(isolate);
8175   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8176   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8177   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8178   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8179   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8180   LocalContext context;
8181   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8182   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8183   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8184   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8185   for (int i = 0; i < 10; i++) {
8186     CHECK_EQ(0, type_switch->match(obj0));
8187     CHECK_EQ(1, type_switch->match(obj1));
8188     CHECK_EQ(2, type_switch->match(obj2));
8189     CHECK_EQ(3, type_switch->match(obj3));
8190     CHECK_EQ(3, type_switch->match(obj3));
8191     CHECK_EQ(2, type_switch->match(obj2));
8192     CHECK_EQ(1, type_switch->match(obj1));
8193     CHECK_EQ(0, type_switch->match(obj0));
8194   }
8195 }
8196
8197
8198 // For use within the TestSecurityHandler() test.
8199 static bool g_security_callback_result = false;
8200 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8201                                       Local<Value> name,
8202                                       v8::AccessType type,
8203                                       Local<Value> data) {
8204   // Always allow read access.
8205   if (type == v8::ACCESS_GET)
8206     return true;
8207
8208   // Sometimes allow other access.
8209   return g_security_callback_result;
8210 }
8211
8212
8213 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8214                                         uint32_t key,
8215                                         v8::AccessType type,
8216                                         Local<Value> data) {
8217   // Always allow read access.
8218   if (type == v8::ACCESS_GET)
8219     return true;
8220
8221   // Sometimes allow other access.
8222   return g_security_callback_result;
8223 }
8224
8225
8226 static int trouble_nesting = 0;
8227 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8228   ApiTestFuzzer::Fuzz();
8229   trouble_nesting++;
8230
8231   // Call a JS function that throws an uncaught exception.
8232   Local<v8::Object> arg_this =
8233       args.GetIsolate()->GetCurrentContext()->Global();
8234   Local<Value> trouble_callee = (trouble_nesting == 3) ?
8235     arg_this->Get(v8_str("trouble_callee")) :
8236     arg_this->Get(v8_str("trouble_caller"));
8237   CHECK(trouble_callee->IsFunction());
8238   args.GetReturnValue().Set(
8239       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8240 }
8241
8242
8243 static int report_count = 0;
8244 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8245                                              v8::Handle<Value>) {
8246   report_count++;
8247 }
8248
8249
8250 // Counts uncaught exceptions, but other tests running in parallel
8251 // also have uncaught exceptions.
8252 TEST(ApiUncaughtException) {
8253   report_count = 0;
8254   LocalContext env;
8255   v8::Isolate* isolate = env->GetIsolate();
8256   v8::HandleScope scope(isolate);
8257   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8258
8259   Local<v8::FunctionTemplate> fun =
8260       v8::FunctionTemplate::New(isolate, TroubleCallback);
8261   v8::Local<v8::Object> global = env->Global();
8262   global->Set(v8_str("trouble"), fun->GetFunction());
8263
8264   CompileRun(
8265       "function trouble_callee() {"
8266       "  var x = null;"
8267       "  return x.foo;"
8268       "};"
8269       "function trouble_caller() {"
8270       "  trouble();"
8271       "};");
8272   Local<Value> trouble = global->Get(v8_str("trouble"));
8273   CHECK(trouble->IsFunction());
8274   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8275   CHECK(trouble_callee->IsFunction());
8276   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8277   CHECK(trouble_caller->IsFunction());
8278   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8279   CHECK_EQ(1, report_count);
8280   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8281 }
8282
8283 static const char* script_resource_name = "ExceptionInNativeScript.js";
8284 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8285                                                 v8::Handle<Value>) {
8286   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8287   CHECK(!name_val.IsEmpty() && name_val->IsString());
8288   v8::String::Utf8Value name(message->GetScriptResourceName());
8289   CHECK_EQ(script_resource_name, *name);
8290   CHECK_EQ(3, message->GetLineNumber());
8291   v8::String::Utf8Value source_line(message->GetSourceLine());
8292   CHECK_EQ("  new o.foo();", *source_line);
8293 }
8294
8295
8296 TEST(ExceptionInNativeScript) {
8297   LocalContext env;
8298   v8::Isolate* isolate = env->GetIsolate();
8299   v8::HandleScope scope(isolate);
8300   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8301
8302   Local<v8::FunctionTemplate> fun =
8303       v8::FunctionTemplate::New(isolate, TroubleCallback);
8304   v8::Local<v8::Object> global = env->Global();
8305   global->Set(v8_str("trouble"), fun->GetFunction());
8306
8307   CompileRunWithOrigin(
8308       "function trouble() {\n"
8309       "  var o = {};\n"
8310       "  new o.foo();\n"
8311       "};",
8312       script_resource_name);
8313   Local<Value> trouble = global->Get(v8_str("trouble"));
8314   CHECK(trouble->IsFunction());
8315   Function::Cast(*trouble)->Call(global, 0, NULL);
8316   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8317 }
8318
8319
8320 TEST(CompilationErrorUsingTryCatchHandler) {
8321   LocalContext env;
8322   v8::HandleScope scope(env->GetIsolate());
8323   v8::TryCatch try_catch;
8324   v8_compile("This doesn't &*&@#$&*^ compile.");
8325   CHECK_NE(NULL, *try_catch.Exception());
8326   CHECK(try_catch.HasCaught());
8327 }
8328
8329
8330 TEST(TryCatchFinallyUsingTryCatchHandler) {
8331   LocalContext env;
8332   v8::HandleScope scope(env->GetIsolate());
8333   v8::TryCatch try_catch;
8334   CompileRun("try { throw ''; } catch (e) {}");
8335   CHECK(!try_catch.HasCaught());
8336   CompileRun("try { throw ''; } finally {}");
8337   CHECK(try_catch.HasCaught());
8338   try_catch.Reset();
8339   CompileRun(
8340       "(function() {"
8341       "try { throw ''; } finally { return; }"
8342       "})()");
8343   CHECK(!try_catch.HasCaught());
8344   CompileRun(
8345       "(function()"
8346       "  { try { throw ''; } finally { throw 0; }"
8347       "})()");
8348   CHECK(try_catch.HasCaught());
8349 }
8350
8351
8352 // SecurityHandler can't be run twice
8353 TEST(SecurityHandler) {
8354   v8::Isolate* isolate = CcTest::isolate();
8355   v8::HandleScope scope0(isolate);
8356   v8::Handle<v8::ObjectTemplate> global_template =
8357       v8::ObjectTemplate::New(isolate);
8358   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8359                                            IndexedSecurityTestCallback);
8360   // Create an environment
8361   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8362   context0->Enter();
8363
8364   v8::Handle<v8::Object> global0 = context0->Global();
8365   v8::Handle<Script> script0 = v8_compile("foo = 111");
8366   script0->Run();
8367   global0->Set(v8_str("0"), v8_num(999));
8368   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8369   CHECK_EQ(111, foo0->Int32Value());
8370   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8371   CHECK_EQ(999, z0->Int32Value());
8372
8373   // Create another environment, should fail security checks.
8374   v8::HandleScope scope1(isolate);
8375
8376   v8::Handle<Context> context1 =
8377     Context::New(isolate, NULL, global_template);
8378   context1->Enter();
8379
8380   v8::Handle<v8::Object> global1 = context1->Global();
8381   global1->Set(v8_str("othercontext"), global0);
8382   // This set will fail the security check.
8383   v8::Handle<Script> script1 =
8384     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8385   script1->Run();
8386   // This read will pass the security check.
8387   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8388   CHECK_EQ(111, foo1->Int32Value());
8389   // This read will pass the security check.
8390   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8391   CHECK_EQ(999, z1->Int32Value());
8392
8393   // Create another environment, should pass security checks.
8394   { g_security_callback_result = true;  // allow security handler to pass.
8395     v8::HandleScope scope2(isolate);
8396     LocalContext context2;
8397     v8::Handle<v8::Object> global2 = context2->Global();
8398     global2->Set(v8_str("othercontext"), global0);
8399     v8::Handle<Script> script2 =
8400         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8401     script2->Run();
8402     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8403     CHECK_EQ(333, foo2->Int32Value());
8404     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8405     CHECK_EQ(888, z2->Int32Value());
8406   }
8407
8408   context1->Exit();
8409   context0->Exit();
8410 }
8411
8412
8413 THREADED_TEST(SecurityChecks) {
8414   LocalContext env1;
8415   v8::HandleScope handle_scope(env1->GetIsolate());
8416   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8417
8418   Local<Value> foo = v8_str("foo");
8419   Local<Value> bar = v8_str("bar");
8420
8421   // Set to the same domain.
8422   env1->SetSecurityToken(foo);
8423
8424   // Create a function in env1.
8425   CompileRun("spy=function(){return spy;}");
8426   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8427   CHECK(spy->IsFunction());
8428
8429   // Create another function accessing global objects.
8430   CompileRun("spy2=function(){return new this.Array();}");
8431   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8432   CHECK(spy2->IsFunction());
8433
8434   // Switch to env2 in the same domain and invoke spy on env2.
8435   {
8436     env2->SetSecurityToken(foo);
8437     // Enter env2
8438     Context::Scope scope_env2(env2);
8439     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8440     CHECK(result->IsFunction());
8441   }
8442
8443   {
8444     env2->SetSecurityToken(bar);
8445     Context::Scope scope_env2(env2);
8446
8447     // Call cross_domain_call, it should throw an exception
8448     v8::TryCatch try_catch;
8449     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8450     CHECK(try_catch.HasCaught());
8451   }
8452 }
8453
8454
8455 // Regression test case for issue 1183439.
8456 THREADED_TEST(SecurityChecksForPrototypeChain) {
8457   LocalContext current;
8458   v8::HandleScope scope(current->GetIsolate());
8459   v8::Handle<Context> other = Context::New(current->GetIsolate());
8460
8461   // Change context to be able to get to the Object function in the
8462   // other context without hitting the security checks.
8463   v8::Local<Value> other_object;
8464   { Context::Scope scope(other);
8465     other_object = other->Global()->Get(v8_str("Object"));
8466     other->Global()->Set(v8_num(42), v8_num(87));
8467   }
8468
8469   current->Global()->Set(v8_str("other"), other->Global());
8470   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8471
8472   // Make sure the security check fails here and we get an undefined
8473   // result instead of getting the Object function. Repeat in a loop
8474   // to make sure to exercise the IC code.
8475   v8::Local<Script> access_other0 = v8_compile("other.Object");
8476   v8::Local<Script> access_other1 = v8_compile("other[42]");
8477   for (int i = 0; i < 5; i++) {
8478     CHECK(!access_other0->Run()->Equals(other_object));
8479     CHECK(access_other0->Run()->IsUndefined());
8480     CHECK(!access_other1->Run()->Equals(v8_num(87)));
8481     CHECK(access_other1->Run()->IsUndefined());
8482   }
8483
8484   // Create an object that has 'other' in its prototype chain and make
8485   // sure we cannot access the Object function indirectly through
8486   // that. Repeat in a loop to make sure to exercise the IC code.
8487   v8_compile("function F() { };"
8488              "F.prototype = other;"
8489              "var f = new F();")->Run();
8490   v8::Local<Script> access_f0 = v8_compile("f.Object");
8491   v8::Local<Script> access_f1 = v8_compile("f[42]");
8492   for (int j = 0; j < 5; j++) {
8493     CHECK(!access_f0->Run()->Equals(other_object));
8494     CHECK(access_f0->Run()->IsUndefined());
8495     CHECK(!access_f1->Run()->Equals(v8_num(87)));
8496     CHECK(access_f1->Run()->IsUndefined());
8497   }
8498
8499   // Now it gets hairy: Set the prototype for the other global object
8500   // to be the current global object. The prototype chain for 'f' now
8501   // goes through 'other' but ends up in the current global object.
8502   { Context::Scope scope(other);
8503     other->Global()->Set(v8_str("__proto__"), current->Global());
8504   }
8505   // Set a named and an index property on the current global
8506   // object. To force the lookup to go through the other global object,
8507   // the properties must not exist in the other global object.
8508   current->Global()->Set(v8_str("foo"), v8_num(100));
8509   current->Global()->Set(v8_num(99), v8_num(101));
8510   // Try to read the properties from f and make sure that the access
8511   // gets stopped by the security checks on the other global object.
8512   Local<Script> access_f2 = v8_compile("f.foo");
8513   Local<Script> access_f3 = v8_compile("f[99]");
8514   for (int k = 0; k < 5; k++) {
8515     CHECK(!access_f2->Run()->Equals(v8_num(100)));
8516     CHECK(access_f2->Run()->IsUndefined());
8517     CHECK(!access_f3->Run()->Equals(v8_num(101)));
8518     CHECK(access_f3->Run()->IsUndefined());
8519   }
8520 }
8521
8522
8523 THREADED_TEST(CrossDomainDelete) {
8524   LocalContext env1;
8525   v8::HandleScope handle_scope(env1->GetIsolate());
8526   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8527
8528   Local<Value> foo = v8_str("foo");
8529   Local<Value> bar = v8_str("bar");
8530
8531   // Set to the same domain.
8532   env1->SetSecurityToken(foo);
8533   env2->SetSecurityToken(foo);
8534
8535   env1->Global()->Set(v8_str("prop"), v8_num(3));
8536   env2->Global()->Set(v8_str("env1"), env1->Global());
8537
8538   // Change env2 to a different domain and delete env1.prop.
8539   env2->SetSecurityToken(bar);
8540   {
8541     Context::Scope scope_env2(env2);
8542     Local<Value> result =
8543         CompileRun("delete env1.prop");
8544     CHECK(result->IsFalse());
8545   }
8546
8547   // Check that env1.prop still exists.
8548   Local<Value> v = env1->Global()->Get(v8_str("prop"));
8549   CHECK(v->IsNumber());
8550   CHECK_EQ(3, v->Int32Value());
8551 }
8552
8553
8554 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8555   LocalContext env1;
8556   v8::HandleScope handle_scope(env1->GetIsolate());
8557   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8558
8559   Local<Value> foo = v8_str("foo");
8560   Local<Value> bar = v8_str("bar");
8561
8562   // Set to the same domain.
8563   env1->SetSecurityToken(foo);
8564   env2->SetSecurityToken(foo);
8565
8566   env1->Global()->Set(v8_str("prop"), v8_num(3));
8567   env2->Global()->Set(v8_str("env1"), env1->Global());
8568
8569   // env1.prop is enumerable in env2.
8570   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8571   {
8572     Context::Scope scope_env2(env2);
8573     Local<Value> result = CompileRun(test);
8574     CHECK(result->IsTrue());
8575   }
8576
8577   // Change env2 to a different domain and test again.
8578   env2->SetSecurityToken(bar);
8579   {
8580     Context::Scope scope_env2(env2);
8581     Local<Value> result = CompileRun(test);
8582     CHECK(result->IsFalse());
8583   }
8584 }
8585
8586
8587 THREADED_TEST(CrossDomainForIn) {
8588   LocalContext env1;
8589   v8::HandleScope handle_scope(env1->GetIsolate());
8590   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8591
8592   Local<Value> foo = v8_str("foo");
8593   Local<Value> bar = v8_str("bar");
8594
8595   // Set to the same domain.
8596   env1->SetSecurityToken(foo);
8597   env2->SetSecurityToken(foo);
8598
8599   env1->Global()->Set(v8_str("prop"), v8_num(3));
8600   env2->Global()->Set(v8_str("env1"), env1->Global());
8601
8602   // Change env2 to a different domain and set env1's global object
8603   // as the __proto__ of an object in env2 and enumerate properties
8604   // in for-in. It shouldn't enumerate properties on env1's global
8605   // object.
8606   env2->SetSecurityToken(bar);
8607   {
8608     Context::Scope scope_env2(env2);
8609     Local<Value> result =
8610         CompileRun("(function(){var obj = {'__proto__':env1};"
8611                    "for (var p in obj)"
8612                    "   if (p == 'prop') return false;"
8613                    "return true;})()");
8614     CHECK(result->IsTrue());
8615   }
8616 }
8617
8618
8619 TEST(ContextDetachGlobal) {
8620   LocalContext env1;
8621   v8::HandleScope handle_scope(env1->GetIsolate());
8622   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8623
8624   Local<v8::Object> global1 = env1->Global();
8625
8626   Local<Value> foo = v8_str("foo");
8627
8628   // Set to the same domain.
8629   env1->SetSecurityToken(foo);
8630   env2->SetSecurityToken(foo);
8631
8632   // Enter env2
8633   env2->Enter();
8634
8635   // Create a function in env2 and add a reference to it in env1.
8636   Local<v8::Object> global2 = env2->Global();
8637   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8638   CompileRun("function getProp() {return prop;}");
8639
8640   env1->Global()->Set(v8_str("getProp"),
8641                       global2->Get(v8_str("getProp")));
8642
8643   // Detach env2's global, and reuse the global object of env2
8644   env2->Exit();
8645   env2->DetachGlobal();
8646
8647   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8648                                           0,
8649                                           v8::Handle<v8::ObjectTemplate>(),
8650                                           global2);
8651   env3->SetSecurityToken(v8_str("bar"));
8652   env3->Enter();
8653
8654   Local<v8::Object> global3 = env3->Global();
8655   CHECK_EQ(global2, global3);
8656   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8657   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8658   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8659   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8660   env3->Exit();
8661
8662   // Call getProp in env1, and it should return the value 1
8663   {
8664     Local<Value> get_prop = global1->Get(v8_str("getProp"));
8665     CHECK(get_prop->IsFunction());
8666     v8::TryCatch try_catch;
8667     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8668     CHECK(!try_catch.HasCaught());
8669     CHECK_EQ(1, r->Int32Value());
8670   }
8671
8672   // Check that env3 is not accessible from env1
8673   {
8674     Local<Value> r = global3->Get(v8_str("prop2"));
8675     CHECK(r->IsUndefined());
8676   }
8677 }
8678
8679
8680 TEST(DetachGlobal) {
8681   LocalContext env1;
8682   v8::HandleScope scope(env1->GetIsolate());
8683
8684   // Create second environment.
8685   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8686
8687   Local<Value> foo = v8_str("foo");
8688
8689   // Set same security token for env1 and env2.
8690   env1->SetSecurityToken(foo);
8691   env2->SetSecurityToken(foo);
8692
8693   // Create a property on the global object in env2.
8694   {
8695     v8::Context::Scope scope(env2);
8696     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8697   }
8698
8699   // Create a reference to env2 global from env1 global.
8700   env1->Global()->Set(v8_str("other"), env2->Global());
8701
8702   // Check that we have access to other.p in env2 from env1.
8703   Local<Value> result = CompileRun("other.p");
8704   CHECK(result->IsInt32());
8705   CHECK_EQ(42, result->Int32Value());
8706
8707   // Hold on to global from env2 and detach global from env2.
8708   Local<v8::Object> global2 = env2->Global();
8709   env2->DetachGlobal();
8710
8711   // Check that the global has been detached. No other.p property can
8712   // be found.
8713   result = CompileRun("other.p");
8714   CHECK(result->IsUndefined());
8715
8716   // Reuse global2 for env3.
8717   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8718                                           0,
8719                                           v8::Handle<v8::ObjectTemplate>(),
8720                                           global2);
8721   CHECK_EQ(global2, env3->Global());
8722
8723   // Start by using the same security token for env3 as for env1 and env2.
8724   env3->SetSecurityToken(foo);
8725
8726   // Create a property on the global object in env3.
8727   {
8728     v8::Context::Scope scope(env3);
8729     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8730   }
8731
8732   // Check that other.p is now the property in env3 and that we have access.
8733   result = CompileRun("other.p");
8734   CHECK(result->IsInt32());
8735   CHECK_EQ(24, result->Int32Value());
8736
8737   // Change security token for env3 to something different from env1 and env2.
8738   env3->SetSecurityToken(v8_str("bar"));
8739
8740   // Check that we do not have access to other.p in env1. |other| is now
8741   // the global object for env3 which has a different security token,
8742   // so access should be blocked.
8743   result = CompileRun("other.p");
8744   CHECK(result->IsUndefined());
8745 }
8746
8747
8748 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8749   info.GetReturnValue().Set(
8750       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8751 }
8752
8753
8754 TEST(DetachedAccesses) {
8755   LocalContext env1;
8756   v8::HandleScope scope(env1->GetIsolate());
8757
8758   // Create second environment.
8759   Local<ObjectTemplate> inner_global_template =
8760       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8761   inner_global_template ->SetAccessorProperty(
8762       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8763   v8::Local<Context> env2 =
8764       Context::New(env1->GetIsolate(), NULL, inner_global_template);
8765
8766   Local<Value> foo = v8_str("foo");
8767
8768   // Set same security token for env1 and env2.
8769   env1->SetSecurityToken(foo);
8770   env2->SetSecurityToken(foo);
8771
8772   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8773
8774   {
8775     v8::Context::Scope scope(env2);
8776     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8777     CompileRun(
8778         "function bound_x() { return x; }"
8779         "function get_x()   { return this.x; }"
8780         "function get_x_w() { return (function() {return this.x;})(); }");
8781     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8782     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8783     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8784     env1->Global()->Set(
8785         v8_str("this_x"),
8786         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8787   }
8788
8789   Local<Object> env2_global = env2->Global();
8790   env2_global->TurnOnAccessCheck();
8791   env2->DetachGlobal();
8792
8793   Local<Value> result;
8794   result = CompileRun("bound_x()");
8795   CHECK_EQ(v8_str("env2_x"), result);
8796   result = CompileRun("get_x()");
8797   CHECK(result->IsUndefined());
8798   result = CompileRun("get_x_w()");
8799   CHECK(result->IsUndefined());
8800   result = CompileRun("this_x()");
8801   CHECK_EQ(v8_str("env2_x"), result);
8802
8803   // Reattach env2's proxy
8804   env2 = Context::New(env1->GetIsolate(),
8805                       0,
8806                       v8::Handle<v8::ObjectTemplate>(),
8807                       env2_global);
8808   env2->SetSecurityToken(foo);
8809   {
8810     v8::Context::Scope scope(env2);
8811     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8812     env2->Global()->Set(v8_str("env1"), env1->Global());
8813     result = CompileRun(
8814         "results = [];"
8815         "for (var i = 0; i < 4; i++ ) {"
8816         "  results.push(env1.bound_x());"
8817         "  results.push(env1.get_x());"
8818         "  results.push(env1.get_x_w());"
8819         "  results.push(env1.this_x());"
8820         "}"
8821         "results");
8822     Local<v8::Array> results = Local<v8::Array>::Cast(result);
8823     CHECK_EQ(16, results->Length());
8824     for (int i = 0; i < 16; i += 4) {
8825       CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8826       CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8827       CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8828       CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8829     }
8830   }
8831
8832   result = CompileRun(
8833       "results = [];"
8834       "for (var i = 0; i < 4; i++ ) {"
8835       "  results.push(bound_x());"
8836       "  results.push(get_x());"
8837       "  results.push(get_x_w());"
8838       "  results.push(this_x());"
8839       "}"
8840       "results");
8841   Local<v8::Array> results = Local<v8::Array>::Cast(result);
8842   CHECK_EQ(16, results->Length());
8843   for (int i = 0; i < 16; i += 4) {
8844     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8845     CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
8846     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8847     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8848   }
8849
8850   result = CompileRun(
8851       "results = [];"
8852       "for (var i = 0; i < 4; i++ ) {"
8853       "  results.push(this.bound_x());"
8854       "  results.push(this.get_x());"
8855       "  results.push(this.get_x_w());"
8856       "  results.push(this.this_x());"
8857       "}"
8858       "results");
8859   results = Local<v8::Array>::Cast(result);
8860   CHECK_EQ(16, results->Length());
8861   for (int i = 0; i < 16; i += 4) {
8862     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8863     CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8864     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8865     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8866   }
8867 }
8868
8869
8870 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8871 static bool NamedAccessBlocker(Local<v8::Object> global,
8872                                Local<Value> name,
8873                                v8::AccessType type,
8874                                Local<Value> data) {
8875   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8876       allowed_access_type[type];
8877 }
8878
8879
8880 static bool IndexedAccessBlocker(Local<v8::Object> global,
8881                                  uint32_t key,
8882                                  v8::AccessType type,
8883                                  Local<Value> data) {
8884   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8885       allowed_access_type[type];
8886 }
8887
8888
8889 static int g_echo_value_1 = -1;
8890 static int g_echo_value_2 = -1;
8891
8892
8893 static void EchoGetter(
8894     Local<String> name,
8895     const v8::PropertyCallbackInfo<v8::Value>& info) {
8896   info.GetReturnValue().Set(v8_num(g_echo_value_1));
8897 }
8898
8899
8900 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8901   info.GetReturnValue().Set(v8_num(g_echo_value_2));
8902 }
8903
8904
8905 static void EchoSetter(Local<String> name,
8906                        Local<Value> value,
8907                        const v8::PropertyCallbackInfo<void>&) {
8908   if (value->IsNumber())
8909     g_echo_value_1 = value->Int32Value();
8910 }
8911
8912
8913 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8914   v8::Handle<v8::Value> value = info[0];
8915   if (value->IsNumber())
8916     g_echo_value_2 = value->Int32Value();
8917 }
8918
8919
8920 static void UnreachableGetter(
8921     Local<String> name,
8922     const v8::PropertyCallbackInfo<v8::Value>& info) {
8923   CHECK(false);  // This function should not be called..
8924 }
8925
8926
8927 static void UnreachableSetter(Local<String>,
8928                               Local<Value>,
8929                               const v8::PropertyCallbackInfo<void>&) {
8930   CHECK(false);  // This function should nto be called.
8931 }
8932
8933
8934 static void UnreachableFunction(
8935     const v8::FunctionCallbackInfo<v8::Value>& info) {
8936   CHECK(false);  // This function should not be called..
8937 }
8938
8939
8940 TEST(AccessControl) {
8941   v8::Isolate* isolate = CcTest::isolate();
8942   v8::HandleScope handle_scope(isolate);
8943   v8::Handle<v8::ObjectTemplate> global_template =
8944       v8::ObjectTemplate::New(isolate);
8945
8946   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8947                                            IndexedAccessBlocker);
8948
8949   // Add an accessor accessible by cross-domain JS code.
8950   global_template->SetAccessor(
8951       v8_str("accessible_prop"),
8952       EchoGetter, EchoSetter,
8953       v8::Handle<Value>(),
8954       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8955
8956
8957   global_template->SetAccessorProperty(
8958       v8_str("accessible_js_prop"),
8959       v8::FunctionTemplate::New(isolate, EchoGetter),
8960       v8::FunctionTemplate::New(isolate, EchoSetter),
8961       v8::None,
8962       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8963
8964   // Add an accessor that is not accessible by cross-domain JS code.
8965   global_template->SetAccessor(v8_str("blocked_prop"),
8966                                UnreachableGetter, UnreachableSetter,
8967                                v8::Handle<Value>(),
8968                                v8::DEFAULT);
8969
8970   global_template->SetAccessorProperty(
8971       v8_str("blocked_js_prop"),
8972       v8::FunctionTemplate::New(isolate, UnreachableFunction),
8973       v8::FunctionTemplate::New(isolate, UnreachableFunction),
8974       v8::None,
8975       v8::DEFAULT);
8976
8977   // Create an environment
8978   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8979   context0->Enter();
8980
8981   v8::Handle<v8::Object> global0 = context0->Global();
8982
8983   // Define a property with JS getter and setter.
8984   CompileRun(
8985       "function getter() { return 'getter'; };\n"
8986       "function setter() { return 'setter'; }\n"
8987       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8988
8989   Local<Value> getter = global0->Get(v8_str("getter"));
8990   Local<Value> setter = global0->Get(v8_str("setter"));
8991
8992   // And define normal element.
8993   global0->Set(239, v8_str("239"));
8994
8995   // Define an element with JS getter and setter.
8996   CompileRun(
8997       "function el_getter() { return 'el_getter'; };\n"
8998       "function el_setter() { return 'el_setter'; };\n"
8999       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9000
9001   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9002   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9003
9004   v8::HandleScope scope1(isolate);
9005
9006   v8::Local<Context> context1 = Context::New(isolate);
9007   context1->Enter();
9008
9009   v8::Handle<v8::Object> global1 = context1->Global();
9010   global1->Set(v8_str("other"), global0);
9011
9012   // Access blocked property.
9013   CompileRun("other.blocked_prop = 1");
9014
9015   ExpectUndefined("other.blocked_prop");
9016   ExpectUndefined(
9017       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9018   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
9019
9020   // Enable ACCESS_HAS
9021   allowed_access_type[v8::ACCESS_HAS] = true;
9022   ExpectUndefined("other.blocked_prop");
9023   // ... and now we can get the descriptor...
9024   ExpectUndefined(
9025       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9026   // ... and enumerate the property.
9027   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9028   allowed_access_type[v8::ACCESS_HAS] = false;
9029
9030   // Access blocked element.
9031   CompileRun("other[239] = 1");
9032
9033   ExpectUndefined("other[239]");
9034   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9035   ExpectFalse("propertyIsEnumerable.call(other, '239')");
9036
9037   // Enable ACCESS_HAS
9038   allowed_access_type[v8::ACCESS_HAS] = true;
9039   ExpectUndefined("other[239]");
9040   // ... and now we can get the descriptor...
9041   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9042   // ... and enumerate the property.
9043   ExpectTrue("propertyIsEnumerable.call(other, '239')");
9044   allowed_access_type[v8::ACCESS_HAS] = false;
9045
9046   // Access a property with JS accessor.
9047   CompileRun("other.js_accessor_p = 2");
9048
9049   ExpectUndefined("other.js_accessor_p");
9050   ExpectUndefined(
9051       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9052
9053   // Enable ACCESS_HAS.
9054   allowed_access_type[v8::ACCESS_HAS] = true;
9055   ExpectUndefined("other.js_accessor_p");
9056   ExpectUndefined(
9057       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9058   ExpectUndefined(
9059       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9060   ExpectUndefined(
9061       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9062   allowed_access_type[v8::ACCESS_HAS] = false;
9063
9064   // Enable both ACCESS_HAS and ACCESS_GET.
9065   allowed_access_type[v8::ACCESS_HAS] = true;
9066   allowed_access_type[v8::ACCESS_GET] = true;
9067
9068   ExpectString("other.js_accessor_p", "getter");
9069   ExpectObject(
9070       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9071   ExpectUndefined(
9072       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9073   ExpectUndefined(
9074       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9075
9076   allowed_access_type[v8::ACCESS_GET] = false;
9077   allowed_access_type[v8::ACCESS_HAS] = false;
9078
9079   // Enable both ACCESS_HAS and ACCESS_SET.
9080   allowed_access_type[v8::ACCESS_HAS] = true;
9081   allowed_access_type[v8::ACCESS_SET] = true;
9082
9083   ExpectUndefined("other.js_accessor_p");
9084   ExpectUndefined(
9085       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9086   ExpectObject(
9087       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9088   ExpectUndefined(
9089       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9090
9091   allowed_access_type[v8::ACCESS_SET] = false;
9092   allowed_access_type[v8::ACCESS_HAS] = false;
9093
9094   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9095   allowed_access_type[v8::ACCESS_HAS] = true;
9096   allowed_access_type[v8::ACCESS_GET] = true;
9097   allowed_access_type[v8::ACCESS_SET] = true;
9098
9099   ExpectString("other.js_accessor_p", "getter");
9100   ExpectObject(
9101       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9102   ExpectObject(
9103       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9104   ExpectUndefined(
9105       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9106
9107   allowed_access_type[v8::ACCESS_SET] = false;
9108   allowed_access_type[v8::ACCESS_GET] = false;
9109   allowed_access_type[v8::ACCESS_HAS] = false;
9110
9111   // Access an element with JS accessor.
9112   CompileRun("other[42] = 2");
9113
9114   ExpectUndefined("other[42]");
9115   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9116
9117   // Enable ACCESS_HAS.
9118   allowed_access_type[v8::ACCESS_HAS] = true;
9119   ExpectUndefined("other[42]");
9120   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9121   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9122   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9123   allowed_access_type[v8::ACCESS_HAS] = false;
9124
9125   // Enable both ACCESS_HAS and ACCESS_GET.
9126   allowed_access_type[v8::ACCESS_HAS] = true;
9127   allowed_access_type[v8::ACCESS_GET] = true;
9128
9129   ExpectString("other[42]", "el_getter");
9130   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9131   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9132   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9133
9134   allowed_access_type[v8::ACCESS_GET] = false;
9135   allowed_access_type[v8::ACCESS_HAS] = false;
9136
9137   // Enable both ACCESS_HAS and ACCESS_SET.
9138   allowed_access_type[v8::ACCESS_HAS] = true;
9139   allowed_access_type[v8::ACCESS_SET] = true;
9140
9141   ExpectUndefined("other[42]");
9142   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9143   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9144   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9145
9146   allowed_access_type[v8::ACCESS_SET] = false;
9147   allowed_access_type[v8::ACCESS_HAS] = false;
9148
9149   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9150   allowed_access_type[v8::ACCESS_HAS] = true;
9151   allowed_access_type[v8::ACCESS_GET] = true;
9152   allowed_access_type[v8::ACCESS_SET] = true;
9153
9154   ExpectString("other[42]", "el_getter");
9155   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9156   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9157   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9158
9159   allowed_access_type[v8::ACCESS_SET] = false;
9160   allowed_access_type[v8::ACCESS_GET] = false;
9161   allowed_access_type[v8::ACCESS_HAS] = false;
9162
9163   v8::Handle<Value> value;
9164
9165   // Access accessible property
9166   value = CompileRun("other.accessible_prop = 3");
9167   CHECK(value->IsNumber());
9168   CHECK_EQ(3, value->Int32Value());
9169   CHECK_EQ(3, g_echo_value_1);
9170
9171   // Access accessible js property
9172   value = CompileRun("other.accessible_js_prop = 3");
9173   CHECK(value->IsNumber());
9174   CHECK_EQ(3, value->Int32Value());
9175   CHECK_EQ(3, g_echo_value_2);
9176
9177   value = CompileRun("other.accessible_prop");
9178   CHECK(value->IsNumber());
9179   CHECK_EQ(3, value->Int32Value());
9180
9181   value = CompileRun("other.accessible_js_prop");
9182   CHECK(value->IsNumber());
9183   CHECK_EQ(3, value->Int32Value());
9184
9185   value = CompileRun(
9186       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9187   CHECK(value->IsNumber());
9188   CHECK_EQ(3, value->Int32Value());
9189
9190   value = CompileRun(
9191       "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9192   CHECK(value->IsNumber());
9193   CHECK_EQ(3, value->Int32Value());
9194
9195   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9196   CHECK(value->IsTrue());
9197
9198   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9199   CHECK(value->IsTrue());
9200
9201   // Enumeration doesn't enumerate accessors from inaccessible objects in
9202   // the prototype chain even if the accessors are in themselves accessible.
9203   value =
9204       CompileRun("(function(){var obj = {'__proto__':other};"
9205                  "for (var p in obj)"
9206                  "   if (p == 'accessible_prop' ||"
9207                  "       p == 'accessible_js_prop' ||"
9208                  "       p == 'blocked_js_prop' ||"
9209                  "       p == 'blocked_js_prop') {"
9210                  "     return false;"
9211                  "   }"
9212                  "return true;})()");
9213   CHECK(value->IsTrue());
9214
9215   context1->Exit();
9216   context0->Exit();
9217 }
9218
9219
9220 TEST(AccessControlES5) {
9221   v8::Isolate* isolate = CcTest::isolate();
9222   v8::HandleScope handle_scope(isolate);
9223   v8::Handle<v8::ObjectTemplate> global_template =
9224       v8::ObjectTemplate::New(isolate);
9225
9226   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9227                                            IndexedAccessBlocker);
9228
9229   // Add accessible accessor.
9230   global_template->SetAccessor(
9231       v8_str("accessible_prop"),
9232       EchoGetter, EchoSetter,
9233       v8::Handle<Value>(),
9234       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9235
9236
9237   // Add an accessor that is not accessible by cross-domain JS code.
9238   global_template->SetAccessor(v8_str("blocked_prop"),
9239                                UnreachableGetter, UnreachableSetter,
9240                                v8::Handle<Value>(),
9241                                v8::DEFAULT);
9242
9243   // Create an environment
9244   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9245   context0->Enter();
9246
9247   v8::Handle<v8::Object> global0 = context0->Global();
9248
9249   v8::Local<Context> context1 = Context::New(isolate);
9250   context1->Enter();
9251   v8::Handle<v8::Object> global1 = context1->Global();
9252   global1->Set(v8_str("other"), global0);
9253
9254   // Regression test for issue 1154.
9255   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9256
9257   ExpectUndefined("other.blocked_prop");
9258
9259   // Regression test for issue 1027.
9260   CompileRun("Object.defineProperty(\n"
9261              "  other, 'blocked_prop', {configurable: false})");
9262   ExpectUndefined("other.blocked_prop");
9263   ExpectUndefined(
9264       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9265
9266   // Regression test for issue 1171.
9267   ExpectTrue("Object.isExtensible(other)");
9268   CompileRun("Object.preventExtensions(other)");
9269   ExpectTrue("Object.isExtensible(other)");
9270
9271   // Object.seal and Object.freeze.
9272   CompileRun("Object.freeze(other)");
9273   ExpectTrue("Object.isExtensible(other)");
9274
9275   CompileRun("Object.seal(other)");
9276   ExpectTrue("Object.isExtensible(other)");
9277
9278   // Regression test for issue 1250.
9279   // Make sure that we can set the accessible accessors value using normal
9280   // assignment.
9281   CompileRun("other.accessible_prop = 42");
9282   CHECK_EQ(42, g_echo_value_1);
9283
9284   v8::Handle<Value> value;
9285   // We follow Safari in ignoring assignments to host object accessors.
9286   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9287   value = CompileRun("other.accessible_prop == 42");
9288   CHECK(value->IsTrue());
9289 }
9290
9291
9292 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9293                                             Local<Value> name,
9294                                             v8::AccessType type,
9295                                             Local<Value> data) {
9296   return false;
9297 }
9298
9299
9300 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9301                                               uint32_t key,
9302                                               v8::AccessType type,
9303                                               Local<Value> data) {
9304   return false;
9305 }
9306
9307
9308 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9309   v8::Isolate* isolate = CcTest::isolate();
9310   v8::HandleScope handle_scope(isolate);
9311   v8::Handle<v8::ObjectTemplate> obj_template =
9312       v8::ObjectTemplate::New(isolate);
9313
9314   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9315   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9316                                         GetOwnPropertyNamesIndexedBlocker);
9317
9318   // Create an environment
9319   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9320   context0->Enter();
9321
9322   v8::Handle<v8::Object> global0 = context0->Global();
9323
9324   v8::HandleScope scope1(CcTest::isolate());
9325
9326   v8::Local<Context> context1 = Context::New(isolate);
9327   context1->Enter();
9328
9329   v8::Handle<v8::Object> global1 = context1->Global();
9330   global1->Set(v8_str("other"), global0);
9331   global1->Set(v8_str("object"), obj_template->NewInstance());
9332
9333   v8::Handle<Value> value;
9334
9335   // Attempt to get the property names of the other global object and
9336   // of an object that requires access checks.  Accessing the other
9337   // global object should be blocked by access checks on the global
9338   // proxy object.  Accessing the object that requires access checks
9339   // is blocked by the access checks on the object itself.
9340   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9341   CHECK(value->IsTrue());
9342
9343   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9344   CHECK(value->IsTrue());
9345
9346   context1->Exit();
9347   context0->Exit();
9348 }
9349
9350
9351 static void IndexedPropertyEnumerator(
9352     const v8::PropertyCallbackInfo<v8::Array>& info) {
9353   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9354   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9355   result->Set(1, v8::Object::New(info.GetIsolate()));
9356   info.GetReturnValue().Set(result);
9357 }
9358
9359
9360 static void NamedPropertyEnumerator(
9361     const v8::PropertyCallbackInfo<v8::Array>& info) {
9362   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9363   result->Set(0, v8_str("x"));
9364   result->Set(1, v8::Object::New(info.GetIsolate()));
9365   info.GetReturnValue().Set(result);
9366 }
9367
9368
9369 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9370   v8::Isolate* isolate = CcTest::isolate();
9371   v8::HandleScope handle_scope(isolate);
9372   v8::Handle<v8::ObjectTemplate> obj_template =
9373       v8::ObjectTemplate::New(isolate);
9374
9375   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9376   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9377   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9378                                           IndexedPropertyEnumerator);
9379   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9380                                         NamedPropertyEnumerator);
9381
9382   LocalContext context;
9383   v8::Handle<v8::Object> global = context->Global();
9384   global->Set(v8_str("object"), obj_template->NewInstance());
9385
9386   v8::Handle<v8::Value> result =
9387       CompileRun("Object.getOwnPropertyNames(object)");
9388   CHECK(result->IsArray());
9389   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9390   CHECK_EQ(3, result_array->Length());
9391   CHECK(result_array->Get(0)->IsString());
9392   CHECK(result_array->Get(1)->IsString());
9393   CHECK(result_array->Get(2)->IsString());
9394   CHECK_EQ(v8_str("7"), result_array->Get(0));
9395   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9396   CHECK_EQ(v8_str("x"), result_array->Get(2));
9397 }
9398
9399
9400 static void ConstTenGetter(Local<String> name,
9401                            const v8::PropertyCallbackInfo<v8::Value>& info) {
9402   info.GetReturnValue().Set(v8_num(10));
9403 }
9404
9405
9406 THREADED_TEST(CrossDomainAccessors) {
9407   v8::Isolate* isolate = CcTest::isolate();
9408   v8::HandleScope handle_scope(isolate);
9409
9410   v8::Handle<v8::FunctionTemplate> func_template =
9411       v8::FunctionTemplate::New(isolate);
9412
9413   v8::Handle<v8::ObjectTemplate> global_template =
9414       func_template->InstanceTemplate();
9415
9416   v8::Handle<v8::ObjectTemplate> proto_template =
9417       func_template->PrototypeTemplate();
9418
9419   // Add an accessor to proto that's accessible by cross-domain JS code.
9420   proto_template->SetAccessor(v8_str("accessible"),
9421                               ConstTenGetter, 0,
9422                               v8::Handle<Value>(),
9423                               v8::ALL_CAN_READ);
9424
9425   // Add an accessor that is not accessible by cross-domain JS code.
9426   global_template->SetAccessor(v8_str("unreachable"),
9427                                UnreachableGetter, 0,
9428                                v8::Handle<Value>(),
9429                                v8::DEFAULT);
9430
9431   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9432   context0->Enter();
9433
9434   Local<v8::Object> global = context0->Global();
9435   // Add a normal property that shadows 'accessible'
9436   global->Set(v8_str("accessible"), v8_num(11));
9437
9438   // Enter a new context.
9439   v8::HandleScope scope1(CcTest::isolate());
9440   v8::Local<Context> context1 = Context::New(isolate);
9441   context1->Enter();
9442
9443   v8::Handle<v8::Object> global1 = context1->Global();
9444   global1->Set(v8_str("other"), global);
9445
9446   // Should return 10, instead of 11
9447   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9448   CHECK(value->IsNumber());
9449   CHECK_EQ(10, value->Int32Value());
9450
9451   value = v8_compile("other.unreachable")->Run();
9452   CHECK(value->IsUndefined());
9453
9454   context1->Exit();
9455   context0->Exit();
9456 }
9457
9458
9459 static int named_access_count = 0;
9460 static int indexed_access_count = 0;
9461
9462 static bool NamedAccessCounter(Local<v8::Object> global,
9463                                Local<Value> name,
9464                                v8::AccessType type,
9465                                Local<Value> data) {
9466   named_access_count++;
9467   return true;
9468 }
9469
9470
9471 static bool IndexedAccessCounter(Local<v8::Object> global,
9472                                  uint32_t key,
9473                                  v8::AccessType type,
9474                                  Local<Value> data) {
9475   indexed_access_count++;
9476   return true;
9477 }
9478
9479
9480 // This one is too easily disturbed by other tests.
9481 TEST(AccessControlIC) {
9482   named_access_count = 0;
9483   indexed_access_count = 0;
9484
9485   v8::Isolate* isolate = CcTest::isolate();
9486   v8::HandleScope handle_scope(isolate);
9487
9488   // Create an environment.
9489   v8::Local<Context> context0 = Context::New(isolate);
9490   context0->Enter();
9491
9492   // Create an object that requires access-check functions to be
9493   // called for cross-domain access.
9494   v8::Handle<v8::ObjectTemplate> object_template =
9495       v8::ObjectTemplate::New(isolate);
9496   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9497                                            IndexedAccessCounter);
9498   Local<v8::Object> object = object_template->NewInstance();
9499
9500   v8::HandleScope scope1(isolate);
9501
9502   // Create another environment.
9503   v8::Local<Context> context1 = Context::New(isolate);
9504   context1->Enter();
9505
9506   // Make easy access to the object from the other environment.
9507   v8::Handle<v8::Object> global1 = context1->Global();
9508   global1->Set(v8_str("obj"), object);
9509
9510   v8::Handle<Value> value;
9511
9512   // Check that the named access-control function is called every time.
9513   CompileRun("function testProp(obj) {"
9514              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
9515              "  for (var j = 0; j < 10; j++) obj.prop;"
9516              "  return obj.prop"
9517              "}");
9518   value = CompileRun("testProp(obj)");
9519   CHECK(value->IsNumber());
9520   CHECK_EQ(1, value->Int32Value());
9521   CHECK_EQ(21, named_access_count);
9522
9523   // Check that the named access-control function is called every time.
9524   CompileRun("var p = 'prop';"
9525              "function testKeyed(obj) {"
9526              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
9527              "  for (var j = 0; j < 10; j++) obj[p];"
9528              "  return obj[p];"
9529              "}");
9530   // Use obj which requires access checks.  No inline caching is used
9531   // in that case.
9532   value = CompileRun("testKeyed(obj)");
9533   CHECK(value->IsNumber());
9534   CHECK_EQ(1, value->Int32Value());
9535   CHECK_EQ(42, named_access_count);
9536   // Force the inline caches into generic state and try again.
9537   CompileRun("testKeyed({ a: 0 })");
9538   CompileRun("testKeyed({ b: 0 })");
9539   value = CompileRun("testKeyed(obj)");
9540   CHECK(value->IsNumber());
9541   CHECK_EQ(1, value->Int32Value());
9542   CHECK_EQ(63, named_access_count);
9543
9544   // Check that the indexed access-control function is called every time.
9545   CompileRun("function testIndexed(obj) {"
9546              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
9547              "  for (var j = 0; j < 10; j++) obj[0];"
9548              "  return obj[0]"
9549              "}");
9550   value = CompileRun("testIndexed(obj)");
9551   CHECK(value->IsNumber());
9552   CHECK_EQ(1, value->Int32Value());
9553   CHECK_EQ(21, indexed_access_count);
9554   // Force the inline caches into generic state.
9555   CompileRun("testIndexed(new Array(1))");
9556   // Test that the indexed access check is called.
9557   value = CompileRun("testIndexed(obj)");
9558   CHECK(value->IsNumber());
9559   CHECK_EQ(1, value->Int32Value());
9560   CHECK_EQ(42, indexed_access_count);
9561
9562   // Check that the named access check is called when invoking
9563   // functions on an object that requires access checks.
9564   CompileRun("obj.f = function() {}");
9565   CompileRun("function testCallNormal(obj) {"
9566              "  for (var i = 0; i < 10; i++) obj.f();"
9567              "}");
9568   CompileRun("testCallNormal(obj)");
9569   CHECK_EQ(74, named_access_count);
9570
9571   // Force obj into slow case.
9572   value = CompileRun("delete obj.prop");
9573   CHECK(value->BooleanValue());
9574   // Force inline caches into dictionary probing mode.
9575   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9576   // Test that the named access check is called.
9577   value = CompileRun("testProp(obj);");
9578   CHECK(value->IsNumber());
9579   CHECK_EQ(1, value->Int32Value());
9580   CHECK_EQ(96, named_access_count);
9581
9582   // Force the call inline cache into dictionary probing mode.
9583   CompileRun("o.f = function() {}; testCallNormal(o)");
9584   // Test that the named access check is still called for each
9585   // invocation of the function.
9586   value = CompileRun("testCallNormal(obj)");
9587   CHECK_EQ(106, named_access_count);
9588
9589   context1->Exit();
9590   context0->Exit();
9591 }
9592
9593
9594 static bool NamedAccessFlatten(Local<v8::Object> global,
9595                                Local<Value> name,
9596                                v8::AccessType type,
9597                                Local<Value> data) {
9598   char buf[100];
9599   int len;
9600
9601   CHECK(name->IsString());
9602
9603   memset(buf, 0x1, sizeof(buf));
9604   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9605   CHECK_EQ(4, len);
9606
9607   uint16_t buf2[100];
9608
9609   memset(buf, 0x1, sizeof(buf));
9610   len = name.As<String>()->Write(buf2);
9611   CHECK_EQ(4, len);
9612
9613   return true;
9614 }
9615
9616
9617 static bool IndexedAccessFlatten(Local<v8::Object> global,
9618                                  uint32_t key,
9619                                  v8::AccessType type,
9620                                  Local<Value> data) {
9621   return true;
9622 }
9623
9624
9625 // Regression test.  In access checks, operations that may cause
9626 // garbage collection are not allowed.  It used to be the case that
9627 // using the Write operation on a string could cause a garbage
9628 // collection due to flattening of the string.  This is no longer the
9629 // case.
9630 THREADED_TEST(AccessControlFlatten) {
9631   named_access_count = 0;
9632   indexed_access_count = 0;
9633
9634   v8::Isolate* isolate = CcTest::isolate();
9635   v8::HandleScope handle_scope(isolate);
9636
9637   // Create an environment.
9638   v8::Local<Context> context0 = Context::New(isolate);
9639   context0->Enter();
9640
9641   // Create an object that requires access-check functions to be
9642   // called for cross-domain access.
9643   v8::Handle<v8::ObjectTemplate> object_template =
9644       v8::ObjectTemplate::New(isolate);
9645   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9646                                            IndexedAccessFlatten);
9647   Local<v8::Object> object = object_template->NewInstance();
9648
9649   v8::HandleScope scope1(isolate);
9650
9651   // Create another environment.
9652   v8::Local<Context> context1 = Context::New(isolate);
9653   context1->Enter();
9654
9655   // Make easy access to the object from the other environment.
9656   v8::Handle<v8::Object> global1 = context1->Global();
9657   global1->Set(v8_str("obj"), object);
9658
9659   v8::Handle<Value> value;
9660
9661   value = v8_compile("var p = 'as' + 'df';")->Run();
9662   value = v8_compile("obj[p];")->Run();
9663
9664   context1->Exit();
9665   context0->Exit();
9666 }
9667
9668
9669 static void AccessControlNamedGetter(
9670     Local<String>,
9671     const v8::PropertyCallbackInfo<v8::Value>& info) {
9672   info.GetReturnValue().Set(42);
9673 }
9674
9675
9676 static void AccessControlNamedSetter(
9677     Local<String>,
9678     Local<Value> value,
9679     const v8::PropertyCallbackInfo<v8::Value>& info) {
9680   info.GetReturnValue().Set(value);
9681 }
9682
9683
9684 static void AccessControlIndexedGetter(
9685       uint32_t index,
9686       const v8::PropertyCallbackInfo<v8::Value>& info) {
9687   info.GetReturnValue().Set(v8_num(42));
9688 }
9689
9690
9691 static void AccessControlIndexedSetter(
9692     uint32_t,
9693     Local<Value> value,
9694     const v8::PropertyCallbackInfo<v8::Value>& info) {
9695   info.GetReturnValue().Set(value);
9696 }
9697
9698
9699 THREADED_TEST(AccessControlInterceptorIC) {
9700   named_access_count = 0;
9701   indexed_access_count = 0;
9702
9703   v8::Isolate* isolate = CcTest::isolate();
9704   v8::HandleScope handle_scope(isolate);
9705
9706   // Create an environment.
9707   v8::Local<Context> context0 = Context::New(isolate);
9708   context0->Enter();
9709
9710   // Create an object that requires access-check functions to be
9711   // called for cross-domain access.  The object also has interceptors
9712   // interceptor.
9713   v8::Handle<v8::ObjectTemplate> object_template =
9714       v8::ObjectTemplate::New(isolate);
9715   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9716                                            IndexedAccessCounter);
9717   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9718                                            AccessControlNamedSetter);
9719   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9720                                              AccessControlIndexedSetter);
9721   Local<v8::Object> object = object_template->NewInstance();
9722
9723   v8::HandleScope scope1(isolate);
9724
9725   // Create another environment.
9726   v8::Local<Context> context1 = Context::New(isolate);
9727   context1->Enter();
9728
9729   // Make easy access to the object from the other environment.
9730   v8::Handle<v8::Object> global1 = context1->Global();
9731   global1->Set(v8_str("obj"), object);
9732
9733   v8::Handle<Value> value;
9734
9735   // Check that the named access-control function is called every time
9736   // eventhough there is an interceptor on the object.
9737   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9738   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9739                      "obj.x")->Run();
9740   CHECK(value->IsNumber());
9741   CHECK_EQ(42, value->Int32Value());
9742   CHECK_EQ(21, named_access_count);
9743
9744   value = v8_compile("var p = 'x';")->Run();
9745   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9746   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9747                      "obj[p]")->Run();
9748   CHECK(value->IsNumber());
9749   CHECK_EQ(42, value->Int32Value());
9750   CHECK_EQ(42, named_access_count);
9751
9752   // Check that the indexed access-control function is called every
9753   // time eventhough there is an interceptor on the object.
9754   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9755   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9756                      "obj[0]")->Run();
9757   CHECK(value->IsNumber());
9758   CHECK_EQ(42, value->Int32Value());
9759   CHECK_EQ(21, indexed_access_count);
9760
9761   context1->Exit();
9762   context0->Exit();
9763 }
9764
9765
9766 THREADED_TEST(Version) {
9767   v8::V8::GetVersion();
9768 }
9769
9770
9771 static void InstanceFunctionCallback(
9772     const v8::FunctionCallbackInfo<v8::Value>& args) {
9773   ApiTestFuzzer::Fuzz();
9774   args.GetReturnValue().Set(v8_num(12));
9775 }
9776
9777
9778 THREADED_TEST(InstanceProperties) {
9779   LocalContext context;
9780   v8::Isolate* isolate = context->GetIsolate();
9781   v8::HandleScope handle_scope(isolate);
9782
9783   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9784   Local<ObjectTemplate> instance = t->InstanceTemplate();
9785
9786   instance->Set(v8_str("x"), v8_num(42));
9787   instance->Set(v8_str("f"),
9788                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9789
9790   Local<Value> o = t->GetFunction()->NewInstance();
9791
9792   context->Global()->Set(v8_str("i"), o);
9793   Local<Value> value = CompileRun("i.x");
9794   CHECK_EQ(42, value->Int32Value());
9795
9796   value = CompileRun("i.f()");
9797   CHECK_EQ(12, value->Int32Value());
9798 }
9799
9800
9801 static void GlobalObjectInstancePropertiesGet(
9802     Local<String> key,
9803     const v8::PropertyCallbackInfo<v8::Value>&) {
9804   ApiTestFuzzer::Fuzz();
9805 }
9806
9807
9808 THREADED_TEST(GlobalObjectInstanceProperties) {
9809   v8::Isolate* isolate = CcTest::isolate();
9810   v8::HandleScope handle_scope(isolate);
9811
9812   Local<Value> global_object;
9813
9814   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9815   t->InstanceTemplate()->SetNamedPropertyHandler(
9816       GlobalObjectInstancePropertiesGet);
9817   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9818   instance_template->Set(v8_str("x"), v8_num(42));
9819   instance_template->Set(v8_str("f"),
9820                          v8::FunctionTemplate::New(isolate,
9821                                                    InstanceFunctionCallback));
9822
9823   // The script to check how Crankshaft compiles missing global function
9824   // invocations.  function g is not defined and should throw on call.
9825   const char* script =
9826       "function wrapper(call) {"
9827       "  var x = 0, y = 1;"
9828       "  for (var i = 0; i < 1000; i++) {"
9829       "    x += i * 100;"
9830       "    y += i * 100;"
9831       "  }"
9832       "  if (call) g();"
9833       "}"
9834       "for (var i = 0; i < 17; i++) wrapper(false);"
9835       "var thrown = 0;"
9836       "try { wrapper(true); } catch (e) { thrown = 1; };"
9837       "thrown";
9838
9839   {
9840     LocalContext env(NULL, instance_template);
9841     // Hold on to the global object so it can be used again in another
9842     // environment initialization.
9843     global_object = env->Global();
9844
9845     Local<Value> value = CompileRun("x");
9846     CHECK_EQ(42, value->Int32Value());
9847     value = CompileRun("f()");
9848     CHECK_EQ(12, value->Int32Value());
9849     value = CompileRun(script);
9850     CHECK_EQ(1, value->Int32Value());
9851   }
9852
9853   {
9854     // Create new environment reusing the global object.
9855     LocalContext env(NULL, instance_template, global_object);
9856     Local<Value> value = CompileRun("x");
9857     CHECK_EQ(42, value->Int32Value());
9858     value = CompileRun("f()");
9859     CHECK_EQ(12, value->Int32Value());
9860     value = CompileRun(script);
9861     CHECK_EQ(1, value->Int32Value());
9862   }
9863 }
9864
9865
9866 THREADED_TEST(CallKnownGlobalReceiver) {
9867   v8::Isolate* isolate = CcTest::isolate();
9868   v8::HandleScope handle_scope(isolate);
9869
9870   Local<Value> global_object;
9871
9872   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9873   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9874
9875   // The script to check that we leave global object not
9876   // global object proxy on stack when we deoptimize from inside
9877   // arguments evaluation.
9878   // To provoke error we need to both force deoptimization
9879   // from arguments evaluation and to force CallIC to take
9880   // CallIC_Miss code path that can't cope with global proxy.
9881   const char* script =
9882       "function bar(x, y) { try { } finally { } }"
9883       "function baz(x) { try { } finally { } }"
9884       "function bom(x) { try { } finally { } }"
9885       "function foo(x) { bar([x], bom(2)); }"
9886       "for (var i = 0; i < 10000; i++) foo(1);"
9887       "foo";
9888
9889   Local<Value> foo;
9890   {
9891     LocalContext env(NULL, instance_template);
9892     // Hold on to the global object so it can be used again in another
9893     // environment initialization.
9894     global_object = env->Global();
9895     foo = CompileRun(script);
9896   }
9897
9898   {
9899     // Create new environment reusing the global object.
9900     LocalContext env(NULL, instance_template, global_object);
9901     env->Global()->Set(v8_str("foo"), foo);
9902     CompileRun("foo()");
9903   }
9904 }
9905
9906
9907 static void ShadowFunctionCallback(
9908     const v8::FunctionCallbackInfo<v8::Value>& args) {
9909   ApiTestFuzzer::Fuzz();
9910   args.GetReturnValue().Set(v8_num(42));
9911 }
9912
9913
9914 static int shadow_y;
9915 static int shadow_y_setter_call_count;
9916 static int shadow_y_getter_call_count;
9917
9918
9919 static void ShadowYSetter(Local<String>,
9920                           Local<Value>,
9921                           const v8::PropertyCallbackInfo<void>&) {
9922   shadow_y_setter_call_count++;
9923   shadow_y = 42;
9924 }
9925
9926
9927 static void ShadowYGetter(Local<String> name,
9928                           const v8::PropertyCallbackInfo<v8::Value>& info) {
9929   ApiTestFuzzer::Fuzz();
9930   shadow_y_getter_call_count++;
9931   info.GetReturnValue().Set(v8_num(shadow_y));
9932 }
9933
9934
9935 static void ShadowIndexedGet(uint32_t index,
9936                              const v8::PropertyCallbackInfo<v8::Value>&) {
9937 }
9938
9939
9940 static void ShadowNamedGet(Local<String> key,
9941                            const v8::PropertyCallbackInfo<v8::Value>&) {
9942 }
9943
9944
9945 THREADED_TEST(ShadowObject) {
9946   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9947   v8::Isolate* isolate = CcTest::isolate();
9948   v8::HandleScope handle_scope(isolate);
9949
9950   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
9951   LocalContext context(NULL, global_template);
9952
9953   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9954   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
9955   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
9956   Local<ObjectTemplate> proto = t->PrototypeTemplate();
9957   Local<ObjectTemplate> instance = t->InstanceTemplate();
9958
9959   proto->Set(v8_str("f"),
9960              v8::FunctionTemplate::New(isolate,
9961                                        ShadowFunctionCallback,
9962                                        Local<Value>()));
9963   proto->Set(v8_str("x"), v8_num(12));
9964
9965   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9966
9967   Local<Value> o = t->GetFunction()->NewInstance();
9968   context->Global()->Set(v8_str("__proto__"), o);
9969
9970   Local<Value> value =
9971       CompileRun("this.propertyIsEnumerable(0)");
9972   CHECK(value->IsBoolean());
9973   CHECK(!value->BooleanValue());
9974
9975   value = CompileRun("x");
9976   CHECK_EQ(12, value->Int32Value());
9977
9978   value = CompileRun("f()");
9979   CHECK_EQ(42, value->Int32Value());
9980
9981   CompileRun("y = 43");
9982   CHECK_EQ(1, shadow_y_setter_call_count);
9983   value = CompileRun("y");
9984   CHECK_EQ(1, shadow_y_getter_call_count);
9985   CHECK_EQ(42, value->Int32Value());
9986 }
9987
9988
9989 THREADED_TEST(HiddenPrototype) {
9990   LocalContext context;
9991   v8::Isolate* isolate = context->GetIsolate();
9992   v8::HandleScope handle_scope(isolate);
9993
9994   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9995   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9996   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9997   t1->SetHiddenPrototype(true);
9998   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9999   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10000   t2->SetHiddenPrototype(true);
10001   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10002   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10003   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10004
10005   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10006   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10007   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10008   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10009
10010   // Setting the prototype on an object skips hidden prototypes.
10011   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10012   o0->Set(v8_str("__proto__"), o1);
10013   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10014   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10015   o0->Set(v8_str("__proto__"), o2);
10016   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10017   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10018   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10019   o0->Set(v8_str("__proto__"), o3);
10020   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10021   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10022   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10023   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10024
10025   // Getting the prototype of o0 should get the first visible one
10026   // which is o3.  Therefore, z should not be defined on the prototype
10027   // object.
10028   Local<Value> proto = o0->Get(v8_str("__proto__"));
10029   CHECK(proto->IsObject());
10030   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10031 }
10032
10033
10034 THREADED_TEST(HiddenPrototypeSet) {
10035   LocalContext context;
10036   v8::Isolate* isolate = context->GetIsolate();
10037   v8::HandleScope handle_scope(isolate);
10038
10039   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10040   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10041   ht->SetHiddenPrototype(true);
10042   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10043   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10044
10045   Local<v8::Object> o = ot->GetFunction()->NewInstance();
10046   Local<v8::Object> h = ht->GetFunction()->NewInstance();
10047   Local<v8::Object> p = pt->GetFunction()->NewInstance();
10048   o->Set(v8_str("__proto__"), h);
10049   h->Set(v8_str("__proto__"), p);
10050
10051   // Setting a property that exists on the hidden prototype goes there.
10052   o->Set(v8_str("x"), v8_num(7));
10053   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10054   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10055   CHECK(p->Get(v8_str("x"))->IsUndefined());
10056
10057   // Setting a new property should not be forwarded to the hidden prototype.
10058   o->Set(v8_str("y"), v8_num(6));
10059   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10060   CHECK(h->Get(v8_str("y"))->IsUndefined());
10061   CHECK(p->Get(v8_str("y"))->IsUndefined());
10062
10063   // Setting a property that only exists on a prototype of the hidden prototype
10064   // is treated normally again.
10065   p->Set(v8_str("z"), v8_num(8));
10066   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10067   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10068   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10069   o->Set(v8_str("z"), v8_num(9));
10070   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10071   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10072   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10073 }
10074
10075
10076 // Regression test for issue 2457.
10077 THREADED_TEST(HiddenPrototypeIdentityHash) {
10078   LocalContext context;
10079   v8::HandleScope handle_scope(context->GetIsolate());
10080
10081   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10082   t->SetHiddenPrototype(true);
10083   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10084   Handle<Object> p = t->GetFunction()->NewInstance();
10085   Handle<Object> o = Object::New(context->GetIsolate());
10086   o->SetPrototype(p);
10087
10088   int hash = o->GetIdentityHash();
10089   USE(hash);
10090   o->Set(v8_str("foo"), v8_num(42));
10091   ASSERT_EQ(hash, o->GetIdentityHash());
10092 }
10093
10094
10095 THREADED_TEST(SetPrototype) {
10096   LocalContext context;
10097   v8::Isolate* isolate = context->GetIsolate();
10098   v8::HandleScope handle_scope(isolate);
10099
10100   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10101   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10102   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10103   t1->SetHiddenPrototype(true);
10104   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10105   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10106   t2->SetHiddenPrototype(true);
10107   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10108   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10109   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10110
10111   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10112   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10113   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10114   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10115
10116   // Setting the prototype on an object does not skip hidden prototypes.
10117   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10118   CHECK(o0->SetPrototype(o1));
10119   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10120   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10121   CHECK(o1->SetPrototype(o2));
10122   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10123   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10124   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10125   CHECK(o2->SetPrototype(o3));
10126   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10127   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10128   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10129   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10130
10131   // Getting the prototype of o0 should get the first visible one
10132   // which is o3.  Therefore, z should not be defined on the prototype
10133   // object.
10134   Local<Value> proto = o0->Get(v8_str("__proto__"));
10135   CHECK(proto->IsObject());
10136   CHECK_EQ(proto.As<v8::Object>(), o3);
10137
10138   // However, Object::GetPrototype ignores hidden prototype.
10139   Local<Value> proto0 = o0->GetPrototype();
10140   CHECK(proto0->IsObject());
10141   CHECK_EQ(proto0.As<v8::Object>(), o1);
10142
10143   Local<Value> proto1 = o1->GetPrototype();
10144   CHECK(proto1->IsObject());
10145   CHECK_EQ(proto1.As<v8::Object>(), o2);
10146
10147   Local<Value> proto2 = o2->GetPrototype();
10148   CHECK(proto2->IsObject());
10149   CHECK_EQ(proto2.As<v8::Object>(), o3);
10150 }
10151
10152
10153 // Getting property names of an object with a prototype chain that
10154 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
10155 // crash the runtime.
10156 THREADED_TEST(Regress91517) {
10157   i::FLAG_allow_natives_syntax = true;
10158   LocalContext context;
10159   v8::Isolate* isolate = context->GetIsolate();
10160   v8::HandleScope handle_scope(isolate);
10161
10162   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10163   t1->SetHiddenPrototype(true);
10164   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10165   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10166   t2->SetHiddenPrototype(true);
10167   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10168   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10169   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10170   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10171   t3->SetHiddenPrototype(true);
10172   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10173   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10174   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10175
10176   // Force dictionary-based properties.
10177   i::ScopedVector<char> name_buf(1024);
10178   for (int i = 1; i <= 1000; i++) {
10179     i::OS::SNPrintF(name_buf, "sdf%d", i);
10180     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10181   }
10182
10183   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10184   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10185   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10186   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10187
10188   // Create prototype chain of hidden prototypes.
10189   CHECK(o4->SetPrototype(o3));
10190   CHECK(o3->SetPrototype(o2));
10191   CHECK(o2->SetPrototype(o1));
10192
10193   // Call the runtime version of GetLocalPropertyNames() on the natively
10194   // created object through JavaScript.
10195   context->Global()->Set(v8_str("obj"), o4);
10196   // PROPERTY_ATTRIBUTES_NONE = 0
10197   CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10198
10199   ExpectInt32("names.length", 1006);
10200   ExpectTrue("names.indexOf(\"baz\") >= 0");
10201   ExpectTrue("names.indexOf(\"boo\") >= 0");
10202   ExpectTrue("names.indexOf(\"foo\") >= 0");
10203   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10204   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10205   ExpectFalse("names[1005] == undefined");
10206 }
10207
10208
10209 // Getting property names of an object with a hidden and inherited
10210 // prototype should not duplicate the accessor properties inherited.
10211 THREADED_TEST(Regress269562) {
10212   i::FLAG_allow_natives_syntax = true;
10213   LocalContext context;
10214   v8::HandleScope handle_scope(context->GetIsolate());
10215
10216   Local<v8::FunctionTemplate> t1 =
10217       v8::FunctionTemplate::New(context->GetIsolate());
10218   t1->SetHiddenPrototype(true);
10219
10220   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10221   i1->SetAccessor(v8_str("foo"),
10222                   SimpleAccessorGetter, SimpleAccessorSetter);
10223   i1->SetAccessor(v8_str("bar"),
10224                   SimpleAccessorGetter, SimpleAccessorSetter);
10225   i1->SetAccessor(v8_str("baz"),
10226                   SimpleAccessorGetter, SimpleAccessorSetter);
10227   i1->Set(v8_str("n1"), v8_num(1));
10228   i1->Set(v8_str("n2"), v8_num(2));
10229
10230   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10231   Local<v8::FunctionTemplate> t2 =
10232       v8::FunctionTemplate::New(context->GetIsolate());
10233   t2->SetHiddenPrototype(true);
10234
10235   // Inherit from t1 and mark prototype as hidden.
10236   t2->Inherit(t1);
10237   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10238
10239   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10240   CHECK(o2->SetPrototype(o1));
10241
10242   v8::Local<v8::Symbol> sym =
10243       v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10244   o1->Set(sym, v8_num(3));
10245   o1->SetHiddenValue(
10246       v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10247
10248   // Call the runtime version of GetLocalPropertyNames() on
10249   // the natively created object through JavaScript.
10250   context->Global()->Set(v8_str("obj"), o2);
10251   context->Global()->Set(v8_str("sym"), sym);
10252   // PROPERTY_ATTRIBUTES_NONE = 0
10253   CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10254
10255   ExpectInt32("names.length", 7);
10256   ExpectTrue("names.indexOf(\"foo\") >= 0");
10257   ExpectTrue("names.indexOf(\"bar\") >= 0");
10258   ExpectTrue("names.indexOf(\"baz\") >= 0");
10259   ExpectTrue("names.indexOf(\"n1\") >= 0");
10260   ExpectTrue("names.indexOf(\"n2\") >= 0");
10261   ExpectTrue("names.indexOf(sym) >= 0");
10262   ExpectTrue("names.indexOf(\"mine\") >= 0");
10263 }
10264
10265
10266 THREADED_TEST(FunctionReadOnlyPrototype) {
10267   LocalContext context;
10268   v8::Isolate* isolate = context->GetIsolate();
10269   v8::HandleScope handle_scope(isolate);
10270
10271   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10272   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10273   t1->ReadOnlyPrototype();
10274   context->Global()->Set(v8_str("func1"), t1->GetFunction());
10275   // Configured value of ReadOnly flag.
10276   CHECK(CompileRun(
10277       "(function() {"
10278       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10279       "  return (descriptor['writable'] == false);"
10280       "})()")->BooleanValue());
10281   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10282   CHECK_EQ(42,
10283            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10284
10285   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10286   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10287   context->Global()->Set(v8_str("func2"), t2->GetFunction());
10288   // Default value of ReadOnly flag.
10289   CHECK(CompileRun(
10290       "(function() {"
10291       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10292       "  return (descriptor['writable'] == true);"
10293       "})()")->BooleanValue());
10294   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10295 }
10296
10297
10298 THREADED_TEST(SetPrototypeThrows) {
10299   LocalContext context;
10300   v8::Isolate* isolate = context->GetIsolate();
10301   v8::HandleScope handle_scope(isolate);
10302
10303   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10304
10305   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10306   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10307
10308   CHECK(o0->SetPrototype(o1));
10309   // If setting the prototype leads to the cycle, SetPrototype should
10310   // return false and keep VM in sane state.
10311   v8::TryCatch try_catch;
10312   CHECK(!o1->SetPrototype(o0));
10313   CHECK(!try_catch.HasCaught());
10314   ASSERT(!CcTest::i_isolate()->has_pending_exception());
10315
10316   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10317 }
10318
10319
10320 THREADED_TEST(FunctionRemovePrototype) {
10321   LocalContext context;
10322   v8::Isolate* isolate = context->GetIsolate();
10323   v8::HandleScope handle_scope(isolate);
10324
10325   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10326   t1->RemovePrototype();
10327   Local<v8::Function> fun = t1->GetFunction();
10328   context->Global()->Set(v8_str("fun"), fun);
10329   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10330
10331   v8::TryCatch try_catch;
10332   CompileRun("new fun()");
10333   CHECK(try_catch.HasCaught());
10334
10335   try_catch.Reset();
10336   fun->NewInstance();
10337   CHECK(try_catch.HasCaught());
10338 }
10339
10340
10341 THREADED_TEST(GetterSetterExceptions) {
10342   LocalContext context;
10343   v8::Isolate* isolate = context->GetIsolate();
10344   v8::HandleScope handle_scope(isolate);
10345   CompileRun(
10346     "function Foo() { };"
10347     "function Throw() { throw 5; };"
10348     "var x = { };"
10349     "x.__defineSetter__('set', Throw);"
10350     "x.__defineGetter__('get', Throw);");
10351   Local<v8::Object> x =
10352       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10353   v8::TryCatch try_catch;
10354   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10355   x->Get(v8_str("get"));
10356   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10357   x->Get(v8_str("get"));
10358   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10359   x->Get(v8_str("get"));
10360   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10361   x->Get(v8_str("get"));
10362 }
10363
10364
10365 THREADED_TEST(Constructor) {
10366   LocalContext context;
10367   v8::Isolate* isolate = context->GetIsolate();
10368   v8::HandleScope handle_scope(isolate);
10369   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10370   templ->SetClassName(v8_str("Fun"));
10371   Local<Function> cons = templ->GetFunction();
10372   context->Global()->Set(v8_str("Fun"), cons);
10373   Local<v8::Object> inst = cons->NewInstance();
10374   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10375   CHECK(obj->IsJSObject());
10376   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10377   CHECK(value->BooleanValue());
10378 }
10379
10380
10381 static void ConstructorCallback(
10382     const v8::FunctionCallbackInfo<v8::Value>& args) {
10383   ApiTestFuzzer::Fuzz();
10384   Local<Object> This;
10385
10386   if (args.IsConstructCall()) {
10387     Local<Object> Holder = args.Holder();
10388     This = Object::New(args.GetIsolate());
10389     Local<Value> proto = Holder->GetPrototype();
10390     if (proto->IsObject()) {
10391       This->SetPrototype(proto);
10392     }
10393   } else {
10394     This = args.This();
10395   }
10396
10397   This->Set(v8_str("a"), args[0]);
10398   args.GetReturnValue().Set(This);
10399 }
10400
10401
10402 static void FakeConstructorCallback(
10403     const v8::FunctionCallbackInfo<v8::Value>& args) {
10404   ApiTestFuzzer::Fuzz();
10405   args.GetReturnValue().Set(args[0]);
10406 }
10407
10408
10409 THREADED_TEST(ConstructorForObject) {
10410   LocalContext context;
10411   v8::Isolate* isolate = context->GetIsolate();
10412   v8::HandleScope handle_scope(isolate);
10413
10414   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10415     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10416     Local<Object> instance = instance_template->NewInstance();
10417     context->Global()->Set(v8_str("obj"), instance);
10418     v8::TryCatch try_catch;
10419     Local<Value> value;
10420     CHECK(!try_catch.HasCaught());
10421
10422     // Call the Object's constructor with a 32-bit signed integer.
10423     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10424     CHECK(!try_catch.HasCaught());
10425     CHECK(value->IsInt32());
10426     CHECK_EQ(28, value->Int32Value());
10427
10428     Local<Value> args1[] = { v8_num(28) };
10429     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10430     CHECK(value_obj1->IsObject());
10431     Local<Object> object1 = Local<Object>::Cast(value_obj1);
10432     value = object1->Get(v8_str("a"));
10433     CHECK(value->IsInt32());
10434     CHECK(!try_catch.HasCaught());
10435     CHECK_EQ(28, value->Int32Value());
10436
10437     // Call the Object's constructor with a String.
10438     value = CompileRun(
10439         "(function() { var o = new obj('tipli'); return o.a; })()");
10440     CHECK(!try_catch.HasCaught());
10441     CHECK(value->IsString());
10442     String::Utf8Value string_value1(value->ToString());
10443     CHECK_EQ("tipli", *string_value1);
10444
10445     Local<Value> args2[] = { v8_str("tipli") };
10446     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10447     CHECK(value_obj2->IsObject());
10448     Local<Object> object2 = Local<Object>::Cast(value_obj2);
10449     value = object2->Get(v8_str("a"));
10450     CHECK(!try_catch.HasCaught());
10451     CHECK(value->IsString());
10452     String::Utf8Value string_value2(value->ToString());
10453     CHECK_EQ("tipli", *string_value2);
10454
10455     // Call the Object's constructor with a Boolean.
10456     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10457     CHECK(!try_catch.HasCaught());
10458     CHECK(value->IsBoolean());
10459     CHECK_EQ(true, value->BooleanValue());
10460
10461     Handle<Value> args3[] = { v8::True(isolate) };
10462     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10463     CHECK(value_obj3->IsObject());
10464     Local<Object> object3 = Local<Object>::Cast(value_obj3);
10465     value = object3->Get(v8_str("a"));
10466     CHECK(!try_catch.HasCaught());
10467     CHECK(value->IsBoolean());
10468     CHECK_EQ(true, value->BooleanValue());
10469
10470     // Call the Object's constructor with undefined.
10471     Handle<Value> args4[] = { v8::Undefined(isolate) };
10472     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10473     CHECK(value_obj4->IsObject());
10474     Local<Object> object4 = Local<Object>::Cast(value_obj4);
10475     value = object4->Get(v8_str("a"));
10476     CHECK(!try_catch.HasCaught());
10477     CHECK(value->IsUndefined());
10478
10479     // Call the Object's constructor with null.
10480     Handle<Value> args5[] = { v8::Null(isolate) };
10481     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10482     CHECK(value_obj5->IsObject());
10483     Local<Object> object5 = Local<Object>::Cast(value_obj5);
10484     value = object5->Get(v8_str("a"));
10485     CHECK(!try_catch.HasCaught());
10486     CHECK(value->IsNull());
10487   }
10488
10489   // Check exception handling when there is no constructor set for the Object.
10490   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10491     Local<Object> instance = instance_template->NewInstance();
10492     context->Global()->Set(v8_str("obj2"), instance);
10493     v8::TryCatch try_catch;
10494     Local<Value> value;
10495     CHECK(!try_catch.HasCaught());
10496
10497     value = CompileRun("new obj2(28)");
10498     CHECK(try_catch.HasCaught());
10499     String::Utf8Value exception_value1(try_catch.Exception());
10500     CHECK_EQ("TypeError: object is not a function", *exception_value1);
10501     try_catch.Reset();
10502
10503     Local<Value> args[] = { v8_num(29) };
10504     value = instance->CallAsConstructor(1, args);
10505     CHECK(try_catch.HasCaught());
10506     String::Utf8Value exception_value2(try_catch.Exception());
10507     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10508     try_catch.Reset();
10509   }
10510
10511   // Check the case when constructor throws exception.
10512   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10513     instance_template->SetCallAsFunctionHandler(ThrowValue);
10514     Local<Object> instance = instance_template->NewInstance();
10515     context->Global()->Set(v8_str("obj3"), instance);
10516     v8::TryCatch try_catch;
10517     Local<Value> value;
10518     CHECK(!try_catch.HasCaught());
10519
10520     value = CompileRun("new obj3(22)");
10521     CHECK(try_catch.HasCaught());
10522     String::Utf8Value exception_value1(try_catch.Exception());
10523     CHECK_EQ("22", *exception_value1);
10524     try_catch.Reset();
10525
10526     Local<Value> args[] = { v8_num(23) };
10527     value = instance->CallAsConstructor(1, args);
10528     CHECK(try_catch.HasCaught());
10529     String::Utf8Value exception_value2(try_catch.Exception());
10530     CHECK_EQ("23", *exception_value2);
10531     try_catch.Reset();
10532   }
10533
10534   // Check whether constructor returns with an object or non-object.
10535   { Local<FunctionTemplate> function_template =
10536         FunctionTemplate::New(isolate, FakeConstructorCallback);
10537     Local<Function> function = function_template->GetFunction();
10538     Local<Object> instance1 = function;
10539     context->Global()->Set(v8_str("obj4"), instance1);
10540     v8::TryCatch try_catch;
10541     Local<Value> value;
10542     CHECK(!try_catch.HasCaught());
10543
10544     CHECK(instance1->IsObject());
10545     CHECK(instance1->IsFunction());
10546
10547     value = CompileRun("new obj4(28)");
10548     CHECK(!try_catch.HasCaught());
10549     CHECK(value->IsObject());
10550
10551     Local<Value> args1[] = { v8_num(28) };
10552     value = instance1->CallAsConstructor(1, args1);
10553     CHECK(!try_catch.HasCaught());
10554     CHECK(value->IsObject());
10555
10556     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10557     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10558     Local<Object> instance2 = instance_template->NewInstance();
10559     context->Global()->Set(v8_str("obj5"), instance2);
10560     CHECK(!try_catch.HasCaught());
10561
10562     CHECK(instance2->IsObject());
10563     CHECK(!instance2->IsFunction());
10564
10565     value = CompileRun("new obj5(28)");
10566     CHECK(!try_catch.HasCaught());
10567     CHECK(!value->IsObject());
10568
10569     Local<Value> args2[] = { v8_num(28) };
10570     value = instance2->CallAsConstructor(1, args2);
10571     CHECK(!try_catch.HasCaught());
10572     CHECK(!value->IsObject());
10573   }
10574 }
10575
10576
10577 THREADED_TEST(FunctionDescriptorException) {
10578   LocalContext context;
10579   v8::Isolate* isolate = context->GetIsolate();
10580   v8::HandleScope handle_scope(isolate);
10581   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10582   templ->SetClassName(v8_str("Fun"));
10583   Local<Function> cons = templ->GetFunction();
10584   context->Global()->Set(v8_str("Fun"), cons);
10585   Local<Value> value = CompileRun(
10586     "function test() {"
10587     "  try {"
10588     "    (new Fun()).blah()"
10589     "  } catch (e) {"
10590     "    var str = String(e);"
10591     // "    if (str.indexOf('TypeError') == -1) return 1;"
10592     // "    if (str.indexOf('[object Fun]') != -1) return 2;"
10593     // "    if (str.indexOf('#<Fun>') == -1) return 3;"
10594     "    return 0;"
10595     "  }"
10596     "  return 4;"
10597     "}"
10598     "test();");
10599   CHECK_EQ(0, value->Int32Value());
10600 }
10601
10602
10603 THREADED_TEST(EvalAliasedDynamic) {
10604   LocalContext current;
10605   v8::HandleScope scope(current->GetIsolate());
10606
10607   // Tests where aliased eval can only be resolved dynamically.
10608   Local<Script> script = v8_compile(
10609       "function f(x) { "
10610       "  var foo = 2;"
10611       "  with (x) { return eval('foo'); }"
10612       "}"
10613       "foo = 0;"
10614       "result1 = f(new Object());"
10615       "result2 = f(this);"
10616       "var x = new Object();"
10617       "x.eval = function(x) { return 1; };"
10618       "result3 = f(x);");
10619   script->Run();
10620   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10621   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10622   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10623
10624   v8::TryCatch try_catch;
10625   script = v8_compile(
10626       "function f(x) { "
10627       "  var bar = 2;"
10628       "  with (x) { return eval('bar'); }"
10629       "}"
10630       "result4 = f(this)");
10631   script->Run();
10632   CHECK(!try_catch.HasCaught());
10633   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10634
10635   try_catch.Reset();
10636 }
10637
10638
10639 THREADED_TEST(CrossEval) {
10640   v8::HandleScope scope(CcTest::isolate());
10641   LocalContext other;
10642   LocalContext current;
10643
10644   Local<String> token = v8_str("<security token>");
10645   other->SetSecurityToken(token);
10646   current->SetSecurityToken(token);
10647
10648   // Set up reference from current to other.
10649   current->Global()->Set(v8_str("other"), other->Global());
10650
10651   // Check that new variables are introduced in other context.
10652   Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10653   script->Run();
10654   Local<Value> foo = other->Global()->Get(v8_str("foo"));
10655   CHECK_EQ(1234, foo->Int32Value());
10656   CHECK(!current->Global()->Has(v8_str("foo")));
10657
10658   // Check that writing to non-existing properties introduces them in
10659   // the other context.
10660   script = v8_compile("other.eval('na = 1234')");
10661   script->Run();
10662   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10663   CHECK(!current->Global()->Has(v8_str("na")));
10664
10665   // Check that global variables in current context are not visible in other
10666   // context.
10667   v8::TryCatch try_catch;
10668   script = v8_compile("var bar = 42; other.eval('bar');");
10669   Local<Value> result = script->Run();
10670   CHECK(try_catch.HasCaught());
10671   try_catch.Reset();
10672
10673   // Check that local variables in current context are not visible in other
10674   // context.
10675   script = v8_compile(
10676       "(function() { "
10677       "  var baz = 87;"
10678       "  return other.eval('baz');"
10679       "})();");
10680   result = script->Run();
10681   CHECK(try_catch.HasCaught());
10682   try_catch.Reset();
10683
10684   // Check that global variables in the other environment are visible
10685   // when evaluting code.
10686   other->Global()->Set(v8_str("bis"), v8_num(1234));
10687   script = v8_compile("other.eval('bis')");
10688   CHECK_EQ(1234, script->Run()->Int32Value());
10689   CHECK(!try_catch.HasCaught());
10690
10691   // Check that the 'this' pointer points to the global object evaluating
10692   // code.
10693   other->Global()->Set(v8_str("t"), other->Global());
10694   script = v8_compile("other.eval('this == t')");
10695   result = script->Run();
10696   CHECK(result->IsTrue());
10697   CHECK(!try_catch.HasCaught());
10698
10699   // Check that variables introduced in with-statement are not visible in
10700   // other context.
10701   script = v8_compile("with({x:2}){other.eval('x')}");
10702   result = script->Run();
10703   CHECK(try_catch.HasCaught());
10704   try_catch.Reset();
10705
10706   // Check that you cannot use 'eval.call' with another object than the
10707   // current global object.
10708   script = v8_compile("other.y = 1; eval.call(other, 'y')");
10709   result = script->Run();
10710   CHECK(try_catch.HasCaught());
10711 }
10712
10713
10714 // Test that calling eval in a context which has been detached from
10715 // its global throws an exception.  This behavior is consistent with
10716 // other JavaScript implementations.
10717 THREADED_TEST(EvalInDetachedGlobal) {
10718   v8::Isolate* isolate = CcTest::isolate();
10719   v8::HandleScope scope(isolate);
10720
10721   v8::Local<Context> context0 = Context::New(isolate);
10722   v8::Local<Context> context1 = Context::New(isolate);
10723
10724   // Set up function in context0 that uses eval from context0.
10725   context0->Enter();
10726   v8::Handle<v8::Value> fun =
10727       CompileRun("var x = 42;"
10728                  "(function() {"
10729                  "  var e = eval;"
10730                  "  return function(s) { return e(s); }"
10731                  "})()");
10732   context0->Exit();
10733
10734   // Put the function into context1 and call it before and after
10735   // detaching the global.  Before detaching, the call succeeds and
10736   // after detaching and exception is thrown.
10737   context1->Enter();
10738   context1->Global()->Set(v8_str("fun"), fun);
10739   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10740   CHECK_EQ(42, x_value->Int32Value());
10741   context0->DetachGlobal();
10742   v8::TryCatch catcher;
10743   x_value = CompileRun("fun('x')");
10744   CHECK(x_value.IsEmpty());
10745   CHECK(catcher.HasCaught());
10746   context1->Exit();
10747 }
10748
10749
10750 THREADED_TEST(CrossLazyLoad) {
10751   v8::HandleScope scope(CcTest::isolate());
10752   LocalContext other;
10753   LocalContext current;
10754
10755   Local<String> token = v8_str("<security token>");
10756   other->SetSecurityToken(token);
10757   current->SetSecurityToken(token);
10758
10759   // Set up reference from current to other.
10760   current->Global()->Set(v8_str("other"), other->Global());
10761
10762   // Trigger lazy loading in other context.
10763   Local<Script> script = v8_compile("other.eval('new Date(42)')");
10764   Local<Value> value = script->Run();
10765   CHECK_EQ(42.0, value->NumberValue());
10766 }
10767
10768
10769 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10770   ApiTestFuzzer::Fuzz();
10771   if (args.IsConstructCall()) {
10772     if (args[0]->IsInt32()) {
10773       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10774       return;
10775     }
10776   }
10777
10778   args.GetReturnValue().Set(args[0]);
10779 }
10780
10781
10782 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10783   args.GetReturnValue().Set(args.This());
10784 }
10785
10786
10787 // Test that a call handler can be set for objects which will allow
10788 // non-function objects created through the API to be called as
10789 // functions.
10790 THREADED_TEST(CallAsFunction) {
10791   LocalContext context;
10792   v8::Isolate* isolate = context->GetIsolate();
10793   v8::HandleScope scope(isolate);
10794
10795   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10796     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10797     instance_template->SetCallAsFunctionHandler(call_as_function);
10798     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10799     context->Global()->Set(v8_str("obj"), instance);
10800     v8::TryCatch try_catch;
10801     Local<Value> value;
10802     CHECK(!try_catch.HasCaught());
10803
10804     value = CompileRun("obj(42)");
10805     CHECK(!try_catch.HasCaught());
10806     CHECK_EQ(42, value->Int32Value());
10807
10808     value = CompileRun("(function(o){return o(49)})(obj)");
10809     CHECK(!try_catch.HasCaught());
10810     CHECK_EQ(49, value->Int32Value());
10811
10812     // test special case of call as function
10813     value = CompileRun("[obj]['0'](45)");
10814     CHECK(!try_catch.HasCaught());
10815     CHECK_EQ(45, value->Int32Value());
10816
10817     value = CompileRun("obj.call = Function.prototype.call;"
10818                        "obj.call(null, 87)");
10819     CHECK(!try_catch.HasCaught());
10820     CHECK_EQ(87, value->Int32Value());
10821
10822     // Regression tests for bug #1116356: Calling call through call/apply
10823     // must work for non-function receivers.
10824     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10825     value = CompileRun(apply_99);
10826     CHECK(!try_catch.HasCaught());
10827     CHECK_EQ(99, value->Int32Value());
10828
10829     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10830     value = CompileRun(call_17);
10831     CHECK(!try_catch.HasCaught());
10832     CHECK_EQ(17, value->Int32Value());
10833
10834     // Check that the call-as-function handler can be called through
10835     // new.
10836     value = CompileRun("new obj(43)");
10837     CHECK(!try_catch.HasCaught());
10838     CHECK_EQ(-43, value->Int32Value());
10839
10840     // Check that the call-as-function handler can be called through
10841     // the API.
10842     v8::Handle<Value> args[] = { v8_num(28) };
10843     value = instance->CallAsFunction(instance, 1, args);
10844     CHECK(!try_catch.HasCaught());
10845     CHECK_EQ(28, value->Int32Value());
10846   }
10847
10848   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10849     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10850     USE(instance_template);
10851     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10852     context->Global()->Set(v8_str("obj2"), instance);
10853     v8::TryCatch try_catch;
10854     Local<Value> value;
10855     CHECK(!try_catch.HasCaught());
10856
10857     // Call an object without call-as-function handler through the JS
10858     value = CompileRun("obj2(28)");
10859     CHECK(value.IsEmpty());
10860     CHECK(try_catch.HasCaught());
10861     String::Utf8Value exception_value1(try_catch.Exception());
10862     // TODO(verwaest): Better message
10863     CHECK_EQ("TypeError: object is not a function",
10864              *exception_value1);
10865     try_catch.Reset();
10866
10867     // Call an object without call-as-function handler through the API
10868     value = CompileRun("obj2(28)");
10869     v8::Handle<Value> args[] = { v8_num(28) };
10870     value = instance->CallAsFunction(instance, 1, args);
10871     CHECK(value.IsEmpty());
10872     CHECK(try_catch.HasCaught());
10873     String::Utf8Value exception_value2(try_catch.Exception());
10874     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10875     try_catch.Reset();
10876   }
10877
10878   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10879     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10880     instance_template->SetCallAsFunctionHandler(ThrowValue);
10881     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10882     context->Global()->Set(v8_str("obj3"), instance);
10883     v8::TryCatch try_catch;
10884     Local<Value> value;
10885     CHECK(!try_catch.HasCaught());
10886
10887     // Catch the exception which is thrown by call-as-function handler
10888     value = CompileRun("obj3(22)");
10889     CHECK(try_catch.HasCaught());
10890     String::Utf8Value exception_value1(try_catch.Exception());
10891     CHECK_EQ("22", *exception_value1);
10892     try_catch.Reset();
10893
10894     v8::Handle<Value> args[] = { v8_num(23) };
10895     value = instance->CallAsFunction(instance, 1, args);
10896     CHECK(try_catch.HasCaught());
10897     String::Utf8Value exception_value2(try_catch.Exception());
10898     CHECK_EQ("23", *exception_value2);
10899     try_catch.Reset();
10900   }
10901
10902   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10903     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10904     instance_template->SetCallAsFunctionHandler(ReturnThis);
10905     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10906
10907     Local<v8::Value> a1 =
10908         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10909     CHECK(a1->StrictEquals(instance));
10910     Local<v8::Value> a2 =
10911         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10912     CHECK(a2->StrictEquals(instance));
10913     Local<v8::Value> a3 =
10914         instance->CallAsFunction(v8_num(42), 0, NULL);
10915     CHECK(a3->StrictEquals(instance));
10916     Local<v8::Value> a4 =
10917         instance->CallAsFunction(v8_str("hello"), 0, NULL);
10918     CHECK(a4->StrictEquals(instance));
10919     Local<v8::Value> a5 =
10920         instance->CallAsFunction(v8::True(isolate), 0, NULL);
10921     CHECK(a5->StrictEquals(instance));
10922   }
10923
10924   { CompileRun(
10925       "function ReturnThisSloppy() {"
10926       "  return this;"
10927       "}"
10928       "function ReturnThisStrict() {"
10929       "  'use strict';"
10930       "  return this;"
10931       "}");
10932     Local<Function> ReturnThisSloppy =
10933         Local<Function>::Cast(
10934             context->Global()->Get(v8_str("ReturnThisSloppy")));
10935     Local<Function> ReturnThisStrict =
10936         Local<Function>::Cast(
10937             context->Global()->Get(v8_str("ReturnThisStrict")));
10938
10939     Local<v8::Value> a1 =
10940         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10941     CHECK(a1->StrictEquals(context->Global()));
10942     Local<v8::Value> a2 =
10943         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
10944     CHECK(a2->StrictEquals(context->Global()));
10945     Local<v8::Value> a3 =
10946         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
10947     CHECK(a3->IsNumberObject());
10948     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
10949     Local<v8::Value> a4 =
10950         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
10951     CHECK(a4->IsStringObject());
10952     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
10953     Local<v8::Value> a5 =
10954         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
10955     CHECK(a5->IsBooleanObject());
10956     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
10957
10958     Local<v8::Value> a6 =
10959         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10960     CHECK(a6->IsUndefined());
10961     Local<v8::Value> a7 =
10962         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
10963     CHECK(a7->IsNull());
10964     Local<v8::Value> a8 =
10965         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
10966     CHECK(a8->StrictEquals(v8_num(42)));
10967     Local<v8::Value> a9 =
10968         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
10969     CHECK(a9->StrictEquals(v8_str("hello")));
10970     Local<v8::Value> a10 =
10971         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
10972     CHECK(a10->StrictEquals(v8::True(isolate)));
10973   }
10974 }
10975
10976
10977 // Check whether a non-function object is callable.
10978 THREADED_TEST(CallableObject) {
10979   LocalContext context;
10980   v8::Isolate* isolate = context->GetIsolate();
10981   v8::HandleScope scope(isolate);
10982
10983   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10984     instance_template->SetCallAsFunctionHandler(call_as_function);
10985     Local<Object> instance = instance_template->NewInstance();
10986     v8::TryCatch try_catch;
10987
10988     CHECK(instance->IsCallable());
10989     CHECK(!try_catch.HasCaught());
10990   }
10991
10992   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10993     Local<Object> instance = instance_template->NewInstance();
10994     v8::TryCatch try_catch;
10995
10996     CHECK(!instance->IsCallable());
10997     CHECK(!try_catch.HasCaught());
10998   }
10999
11000   { Local<FunctionTemplate> function_template =
11001         FunctionTemplate::New(isolate, call_as_function);
11002     Local<Function> function = function_template->GetFunction();
11003     Local<Object> instance = function;
11004     v8::TryCatch try_catch;
11005
11006     CHECK(instance->IsCallable());
11007     CHECK(!try_catch.HasCaught());
11008   }
11009
11010   { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11011     Local<Function> function = function_template->GetFunction();
11012     Local<Object> instance = function;
11013     v8::TryCatch try_catch;
11014
11015     CHECK(instance->IsCallable());
11016     CHECK(!try_catch.HasCaught());
11017   }
11018 }
11019
11020
11021 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11022   v8::HandleScope scope(isolate);
11023   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11024   for (int i = 0; i < iterations; i++) {
11025     Local<v8::Number> n(v8::Integer::New(isolate, 42));
11026   }
11027   return Recurse(isolate, depth - 1, iterations);
11028 }
11029
11030
11031 THREADED_TEST(HandleIteration) {
11032   static const int kIterations = 500;
11033   static const int kNesting = 200;
11034   LocalContext context;
11035   v8::Isolate* isolate = context->GetIsolate();
11036   v8::HandleScope scope0(isolate);
11037   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11038   {
11039     v8::HandleScope scope1(isolate);
11040     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11041     for (int i = 0; i < kIterations; i++) {
11042       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11043       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11044     }
11045
11046     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11047     {
11048       v8::HandleScope scope2(CcTest::isolate());
11049       for (int j = 0; j < kIterations; j++) {
11050         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11051         CHECK_EQ(j + 1 + kIterations,
11052                  v8::HandleScope::NumberOfHandles(isolate));
11053       }
11054     }
11055     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11056   }
11057   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11058   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11059 }
11060
11061
11062 static void InterceptorHasOwnPropertyGetter(
11063     Local<String> name,
11064     const v8::PropertyCallbackInfo<v8::Value>& info) {
11065   ApiTestFuzzer::Fuzz();
11066 }
11067
11068
11069 THREADED_TEST(InterceptorHasOwnProperty) {
11070   LocalContext context;
11071   v8::Isolate* isolate = context->GetIsolate();
11072   v8::HandleScope scope(isolate);
11073   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11074   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11075   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11076   Local<Function> function = fun_templ->GetFunction();
11077   context->Global()->Set(v8_str("constructor"), function);
11078   v8::Handle<Value> value = CompileRun(
11079       "var o = new constructor();"
11080       "o.hasOwnProperty('ostehaps');");
11081   CHECK_EQ(false, value->BooleanValue());
11082   value = CompileRun(
11083       "o.ostehaps = 42;"
11084       "o.hasOwnProperty('ostehaps');");
11085   CHECK_EQ(true, value->BooleanValue());
11086   value = CompileRun(
11087       "var p = new constructor();"
11088       "p.hasOwnProperty('ostehaps');");
11089   CHECK_EQ(false, value->BooleanValue());
11090 }
11091
11092
11093 static void InterceptorHasOwnPropertyGetterGC(
11094     Local<String> name,
11095     const v8::PropertyCallbackInfo<v8::Value>& info) {
11096   ApiTestFuzzer::Fuzz();
11097   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11098 }
11099
11100
11101 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11102   LocalContext context;
11103   v8::Isolate* isolate = context->GetIsolate();
11104   v8::HandleScope scope(isolate);
11105   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11106   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11107   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11108   Local<Function> function = fun_templ->GetFunction();
11109   context->Global()->Set(v8_str("constructor"), function);
11110   // Let's first make some stuff so we can be sure to get a good GC.
11111   CompileRun(
11112       "function makestr(size) {"
11113       "  switch (size) {"
11114       "    case 1: return 'f';"
11115       "    case 2: return 'fo';"
11116       "    case 3: return 'foo';"
11117       "  }"
11118       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
11119       "}"
11120       "var x = makestr(12345);"
11121       "x = makestr(31415);"
11122       "x = makestr(23456);");
11123   v8::Handle<Value> value = CompileRun(
11124       "var o = new constructor();"
11125       "o.__proto__ = new String(x);"
11126       "o.hasOwnProperty('ostehaps');");
11127   CHECK_EQ(false, value->BooleanValue());
11128 }
11129
11130
11131 typedef void (*NamedPropertyGetter)(
11132     Local<String> property,
11133     const v8::PropertyCallbackInfo<v8::Value>& info);
11134
11135
11136 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11137                                    const char* source,
11138                                    int expected) {
11139   v8::Isolate* isolate = CcTest::isolate();
11140   v8::HandleScope scope(isolate);
11141   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11142   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11143   LocalContext context;
11144   context->Global()->Set(v8_str("o"), templ->NewInstance());
11145   v8::Handle<Value> value = CompileRun(source);
11146   CHECK_EQ(expected, value->Int32Value());
11147 }
11148
11149
11150 static void InterceptorLoadICGetter(
11151     Local<String> name,
11152     const v8::PropertyCallbackInfo<v8::Value>& info) {
11153   ApiTestFuzzer::Fuzz();
11154   v8::Isolate* isolate = CcTest::isolate();
11155   CHECK_EQ(isolate, info.GetIsolate());
11156   CHECK_EQ(v8_str("data"), info.Data());
11157   CHECK_EQ(v8_str("x"), name);
11158   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11159 }
11160
11161
11162 // This test should hit the load IC for the interceptor case.
11163 THREADED_TEST(InterceptorLoadIC) {
11164   CheckInterceptorLoadIC(InterceptorLoadICGetter,
11165     "var result = 0;"
11166     "for (var i = 0; i < 1000; i++) {"
11167     "  result = o.x;"
11168     "}",
11169     42);
11170 }
11171
11172
11173 // Below go several tests which verify that JITing for various
11174 // configurations of interceptor and explicit fields works fine
11175 // (those cases are special cased to get better performance).
11176
11177 static void InterceptorLoadXICGetter(
11178     Local<String> name,
11179     const v8::PropertyCallbackInfo<v8::Value>& info) {
11180   ApiTestFuzzer::Fuzz();
11181   info.GetReturnValue().Set(
11182       v8_str("x")->Equals(name) ?
11183           v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11184           v8::Handle<v8::Value>());
11185 }
11186
11187
11188 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11189   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11190     "var result = 0;"
11191     "o.y = 239;"
11192     "for (var i = 0; i < 1000; i++) {"
11193     "  result = o.y;"
11194     "}",
11195     239);
11196 }
11197
11198
11199 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11200   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11201     "var result = 0;"
11202     "o.__proto__ = { 'y': 239 };"
11203     "for (var i = 0; i < 1000; i++) {"
11204     "  result = o.y + o.x;"
11205     "}",
11206     239 + 42);
11207 }
11208
11209
11210 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11211   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11212     "var result = 0;"
11213     "o.__proto__.y = 239;"
11214     "for (var i = 0; i < 1000; i++) {"
11215     "  result = o.y + o.x;"
11216     "}",
11217     239 + 42);
11218 }
11219
11220
11221 THREADED_TEST(InterceptorLoadICUndefined) {
11222   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11223     "var result = 0;"
11224     "for (var i = 0; i < 1000; i++) {"
11225     "  result = (o.y == undefined) ? 239 : 42;"
11226     "}",
11227     239);
11228 }
11229
11230
11231 THREADED_TEST(InterceptorLoadICWithOverride) {
11232   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11233     "fst = new Object();  fst.__proto__ = o;"
11234     "snd = new Object();  snd.__proto__ = fst;"
11235     "var result1 = 0;"
11236     "for (var i = 0; i < 1000;  i++) {"
11237     "  result1 = snd.x;"
11238     "}"
11239     "fst.x = 239;"
11240     "var result = 0;"
11241     "for (var i = 0; i < 1000; i++) {"
11242     "  result = snd.x;"
11243     "}"
11244     "result + result1",
11245     239 + 42);
11246 }
11247
11248
11249 // Test the case when we stored field into
11250 // a stub, but interceptor produced value on its own.
11251 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11252   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11253     "proto = new Object();"
11254     "o.__proto__ = proto;"
11255     "proto.x = 239;"
11256     "for (var i = 0; i < 1000; i++) {"
11257     "  o.x;"
11258     // Now it should be ICed and keep a reference to x defined on proto
11259     "}"
11260     "var result = 0;"
11261     "for (var i = 0; i < 1000; i++) {"
11262     "  result += o.x;"
11263     "}"
11264     "result;",
11265     42 * 1000);
11266 }
11267
11268
11269 // Test the case when we stored field into
11270 // a stub, but it got invalidated later on.
11271 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11272   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11273     "proto1 = new Object();"
11274     "proto2 = new Object();"
11275     "o.__proto__ = proto1;"
11276     "proto1.__proto__ = proto2;"
11277     "proto2.y = 239;"
11278     "for (var i = 0; i < 1000; i++) {"
11279     "  o.y;"
11280     // Now it should be ICed and keep a reference to y defined on proto2
11281     "}"
11282     "proto1.y = 42;"
11283     "var result = 0;"
11284     "for (var i = 0; i < 1000; i++) {"
11285     "  result += o.y;"
11286     "}"
11287     "result;",
11288     42 * 1000);
11289 }
11290
11291
11292 static int interceptor_load_not_handled_calls = 0;
11293 static void InterceptorLoadNotHandled(
11294     Local<String> name,
11295     const v8::PropertyCallbackInfo<v8::Value>& info) {
11296   ++interceptor_load_not_handled_calls;
11297 }
11298
11299
11300 // Test how post-interceptor lookups are done in the non-cacheable
11301 // case: the interceptor should not be invoked during this lookup.
11302 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11303   interceptor_load_not_handled_calls = 0;
11304   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11305     "receiver = new Object();"
11306     "receiver.__proto__ = o;"
11307     "proto = new Object();"
11308     "/* Make proto a slow-case object. */"
11309     "for (var i = 0; i < 1000; i++) {"
11310     "  proto[\"xxxxxxxx\" + i] = [];"
11311     "}"
11312     "proto.x = 17;"
11313     "o.__proto__ = proto;"
11314     "var result = 0;"
11315     "for (var i = 0; i < 1000; i++) {"
11316     "  result += receiver.x;"
11317     "}"
11318     "result;",
11319     17 * 1000);
11320   CHECK_EQ(1000, interceptor_load_not_handled_calls);
11321 }
11322
11323
11324 // Test the case when we stored field into
11325 // a stub, but it got invalidated later on due to override on
11326 // global object which is between interceptor and fields' holders.
11327 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11328   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11329     "o.__proto__ = this;"  // set a global to be a proto of o.
11330     "this.__proto__.y = 239;"
11331     "for (var i = 0; i < 10; i++) {"
11332     "  if (o.y != 239) throw 'oops: ' + o.y;"
11333     // Now it should be ICed and keep a reference to y defined on field_holder.
11334     "}"
11335     "this.y = 42;"  // Assign on a global.
11336     "var result = 0;"
11337     "for (var i = 0; i < 10; i++) {"
11338     "  result += o.y;"
11339     "}"
11340     "result;",
11341     42 * 10);
11342 }
11343
11344
11345 static void SetOnThis(Local<String> name,
11346                       Local<Value> value,
11347                       const v8::PropertyCallbackInfo<void>& info) {
11348   info.This()->ForceSet(name, value);
11349 }
11350
11351
11352 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11353   v8::Isolate* isolate = CcTest::isolate();
11354   v8::HandleScope scope(isolate);
11355   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11356   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11357   templ->SetAccessor(v8_str("y"), Return239Callback);
11358   LocalContext context;
11359   context->Global()->Set(v8_str("o"), templ->NewInstance());
11360
11361   // Check the case when receiver and interceptor's holder
11362   // are the same objects.
11363   v8::Handle<Value> value = CompileRun(
11364       "var result = 0;"
11365       "for (var i = 0; i < 7; i++) {"
11366       "  result = o.y;"
11367       "}");
11368   CHECK_EQ(239, value->Int32Value());
11369
11370   // Check the case when interceptor's holder is in proto chain
11371   // of receiver.
11372   value = CompileRun(
11373       "r = { __proto__: o };"
11374       "var result = 0;"
11375       "for (var i = 0; i < 7; i++) {"
11376       "  result = r.y;"
11377       "}");
11378   CHECK_EQ(239, value->Int32Value());
11379 }
11380
11381
11382 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11383   v8::Isolate* isolate = CcTest::isolate();
11384   v8::HandleScope scope(isolate);
11385   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11386   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11387   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11388   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11389
11390   LocalContext context;
11391   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11392   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11393
11394   // Check the case when receiver and interceptor's holder
11395   // are the same objects.
11396   v8::Handle<Value> value = CompileRun(
11397       "o.__proto__ = p;"
11398       "var result = 0;"
11399       "for (var i = 0; i < 7; i++) {"
11400       "  result = o.x + o.y;"
11401       "}");
11402   CHECK_EQ(239 + 42, value->Int32Value());
11403
11404   // Check the case when interceptor's holder is in proto chain
11405   // of receiver.
11406   value = CompileRun(
11407       "r = { __proto__: o };"
11408       "var result = 0;"
11409       "for (var i = 0; i < 7; i++) {"
11410       "  result = r.x + r.y;"
11411       "}");
11412   CHECK_EQ(239 + 42, value->Int32Value());
11413 }
11414
11415
11416 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11417   v8::Isolate* isolate = CcTest::isolate();
11418   v8::HandleScope scope(isolate);
11419   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11420   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11421   templ->SetAccessor(v8_str("y"), Return239Callback);
11422
11423   LocalContext context;
11424   context->Global()->Set(v8_str("o"), templ->NewInstance());
11425
11426   v8::Handle<Value> value = CompileRun(
11427     "fst = new Object();  fst.__proto__ = o;"
11428     "snd = new Object();  snd.__proto__ = fst;"
11429     "var result1 = 0;"
11430     "for (var i = 0; i < 7;  i++) {"
11431     "  result1 = snd.x;"
11432     "}"
11433     "fst.x = 239;"
11434     "var result = 0;"
11435     "for (var i = 0; i < 7; i++) {"
11436     "  result = snd.x;"
11437     "}"
11438     "result + result1");
11439   CHECK_EQ(239 + 42, value->Int32Value());
11440 }
11441
11442
11443 // Test the case when we stored callback into
11444 // a stub, but interceptor produced value on its own.
11445 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11446   v8::Isolate* isolate = CcTest::isolate();
11447   v8::HandleScope scope(isolate);
11448   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11449   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11450   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11451   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11452
11453   LocalContext context;
11454   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11455   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11456
11457   v8::Handle<Value> value = CompileRun(
11458     "o.__proto__ = p;"
11459     "for (var i = 0; i < 7; i++) {"
11460     "  o.x;"
11461     // Now it should be ICed and keep a reference to x defined on p
11462     "}"
11463     "var result = 0;"
11464     "for (var i = 0; i < 7; i++) {"
11465     "  result += o.x;"
11466     "}"
11467     "result");
11468   CHECK_EQ(42 * 7, value->Int32Value());
11469 }
11470
11471
11472 // Test the case when we stored callback into
11473 // a stub, but it got invalidated later on.
11474 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11475   v8::Isolate* isolate = CcTest::isolate();
11476   v8::HandleScope scope(isolate);
11477   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11478   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11479   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11480   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11481
11482   LocalContext context;
11483   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11484   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11485
11486   v8::Handle<Value> value = CompileRun(
11487     "inbetween = new Object();"
11488     "o.__proto__ = inbetween;"
11489     "inbetween.__proto__ = p;"
11490     "for (var i = 0; i < 10; i++) {"
11491     "  o.y;"
11492     // Now it should be ICed and keep a reference to y defined on p
11493     "}"
11494     "inbetween.y = 42;"
11495     "var result = 0;"
11496     "for (var i = 0; i < 10; i++) {"
11497     "  result += o.y;"
11498     "}"
11499     "result");
11500   CHECK_EQ(42 * 10, value->Int32Value());
11501 }
11502
11503
11504 // Test the case when we stored callback into
11505 // a stub, but it got invalidated later on due to override on
11506 // global object which is between interceptor and callbacks' holders.
11507 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11508   v8::Isolate* isolate = CcTest::isolate();
11509   v8::HandleScope scope(isolate);
11510   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11511   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11512   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11513   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11514
11515   LocalContext context;
11516   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11517   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11518
11519   v8::Handle<Value> value = CompileRun(
11520     "o.__proto__ = this;"
11521     "this.__proto__ = p;"
11522     "for (var i = 0; i < 10; i++) {"
11523     "  if (o.y != 239) throw 'oops: ' + o.y;"
11524     // Now it should be ICed and keep a reference to y defined on p
11525     "}"
11526     "this.y = 42;"
11527     "var result = 0;"
11528     "for (var i = 0; i < 10; i++) {"
11529     "  result += o.y;"
11530     "}"
11531     "result");
11532   CHECK_EQ(42 * 10, value->Int32Value());
11533 }
11534
11535
11536 static void InterceptorLoadICGetter0(
11537     Local<String> name,
11538     const v8::PropertyCallbackInfo<v8::Value>& info) {
11539   ApiTestFuzzer::Fuzz();
11540   CHECK(v8_str("x")->Equals(name));
11541   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11542 }
11543
11544
11545 THREADED_TEST(InterceptorReturningZero) {
11546   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11547      "o.x == undefined ? 1 : 0",
11548      0);
11549 }
11550
11551
11552 static void InterceptorStoreICSetter(
11553     Local<String> key,
11554     Local<Value> value,
11555     const v8::PropertyCallbackInfo<v8::Value>& info) {
11556   CHECK(v8_str("x")->Equals(key));
11557   CHECK_EQ(42, value->Int32Value());
11558   info.GetReturnValue().Set(value);
11559 }
11560
11561
11562 // This test should hit the store IC for the interceptor case.
11563 THREADED_TEST(InterceptorStoreIC) {
11564   v8::Isolate* isolate = CcTest::isolate();
11565   v8::HandleScope scope(isolate);
11566   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11567   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11568                                  InterceptorStoreICSetter,
11569                                  0, 0, 0, v8_str("data"));
11570   LocalContext context;
11571   context->Global()->Set(v8_str("o"), templ->NewInstance());
11572   CompileRun(
11573       "for (var i = 0; i < 1000; i++) {"
11574       "  o.x = 42;"
11575       "}");
11576 }
11577
11578
11579 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11580   v8::Isolate* isolate = CcTest::isolate();
11581   v8::HandleScope scope(isolate);
11582   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11583   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11584   LocalContext context;
11585   context->Global()->Set(v8_str("o"), templ->NewInstance());
11586   v8::Handle<Value> value = CompileRun(
11587     "for (var i = 0; i < 1000; i++) {"
11588     "  o.y = 239;"
11589     "}"
11590     "42 + o.y");
11591   CHECK_EQ(239 + 42, value->Int32Value());
11592 }
11593
11594
11595
11596
11597 v8::Handle<Value> call_ic_function;
11598 v8::Handle<Value> call_ic_function2;
11599 v8::Handle<Value> call_ic_function3;
11600
11601 static void InterceptorCallICGetter(
11602     Local<String> name,
11603     const v8::PropertyCallbackInfo<v8::Value>& info) {
11604   ApiTestFuzzer::Fuzz();
11605   CHECK(v8_str("x")->Equals(name));
11606   info.GetReturnValue().Set(call_ic_function);
11607 }
11608
11609
11610 // This test should hit the call IC for the interceptor case.
11611 THREADED_TEST(InterceptorCallIC) {
11612   v8::Isolate* isolate = CcTest::isolate();
11613   v8::HandleScope scope(isolate);
11614   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11615   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11616   LocalContext context;
11617   context->Global()->Set(v8_str("o"), templ->NewInstance());
11618   call_ic_function =
11619       v8_compile("function f(x) { return x + 1; }; f")->Run();
11620   v8::Handle<Value> value = CompileRun(
11621     "var result = 0;"
11622     "for (var i = 0; i < 1000; i++) {"
11623     "  result = o.x(41);"
11624     "}");
11625   CHECK_EQ(42, value->Int32Value());
11626 }
11627
11628
11629 // This test checks that if interceptor doesn't provide
11630 // a value, we can fetch regular value.
11631 THREADED_TEST(InterceptorCallICSeesOthers) {
11632   v8::Isolate* isolate = CcTest::isolate();
11633   v8::HandleScope scope(isolate);
11634   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11635   templ->SetNamedPropertyHandler(NoBlockGetterX);
11636   LocalContext context;
11637   context->Global()->Set(v8_str("o"), templ->NewInstance());
11638   v8::Handle<Value> value = CompileRun(
11639     "o.x = function f(x) { return x + 1; };"
11640     "var result = 0;"
11641     "for (var i = 0; i < 7; i++) {"
11642     "  result = o.x(41);"
11643     "}");
11644   CHECK_EQ(42, value->Int32Value());
11645 }
11646
11647
11648 static v8::Handle<Value> call_ic_function4;
11649 static void InterceptorCallICGetter4(
11650     Local<String> name,
11651     const v8::PropertyCallbackInfo<v8::Value>& info) {
11652   ApiTestFuzzer::Fuzz();
11653   CHECK(v8_str("x")->Equals(name));
11654   info.GetReturnValue().Set(call_ic_function4);
11655 }
11656
11657
11658 // This test checks that if interceptor provides a function,
11659 // even if we cached shadowed variant, interceptor's function
11660 // is invoked
11661 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11662   v8::Isolate* isolate = CcTest::isolate();
11663   v8::HandleScope scope(isolate);
11664   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11665   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11666   LocalContext context;
11667   context->Global()->Set(v8_str("o"), templ->NewInstance());
11668   call_ic_function4 =
11669       v8_compile("function f(x) { return x - 1; }; f")->Run();
11670   v8::Handle<Value> value = CompileRun(
11671     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11672     "var result = 0;"
11673     "for (var i = 0; i < 1000; i++) {"
11674     "  result = o.x(42);"
11675     "}");
11676   CHECK_EQ(41, value->Int32Value());
11677 }
11678
11679
11680 // Test the case when we stored cacheable lookup into
11681 // a stub, but it got invalidated later on
11682 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11683   v8::Isolate* isolate = CcTest::isolate();
11684   v8::HandleScope scope(isolate);
11685   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11686   templ->SetNamedPropertyHandler(NoBlockGetterX);
11687   LocalContext context;
11688   context->Global()->Set(v8_str("o"), templ->NewInstance());
11689   v8::Handle<Value> value = CompileRun(
11690     "proto1 = new Object();"
11691     "proto2 = new Object();"
11692     "o.__proto__ = proto1;"
11693     "proto1.__proto__ = proto2;"
11694     "proto2.y = function(x) { return x + 1; };"
11695     // Invoke it many times to compile a stub
11696     "for (var i = 0; i < 7; i++) {"
11697     "  o.y(42);"
11698     "}"
11699     "proto1.y = function(x) { return x - 1; };"
11700     "var result = 0;"
11701     "for (var i = 0; i < 7; i++) {"
11702     "  result += o.y(42);"
11703     "}");
11704   CHECK_EQ(41 * 7, value->Int32Value());
11705 }
11706
11707
11708 // This test checks that if interceptor doesn't provide a function,
11709 // cached constant function is used
11710 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11711   v8::Isolate* isolate = CcTest::isolate();
11712   v8::HandleScope scope(isolate);
11713   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11714   templ->SetNamedPropertyHandler(NoBlockGetterX);
11715   LocalContext context;
11716   context->Global()->Set(v8_str("o"), templ->NewInstance());
11717   v8::Handle<Value> value = CompileRun(
11718     "function inc(x) { return x + 1; };"
11719     "inc(1);"
11720     "o.x = inc;"
11721     "var result = 0;"
11722     "for (var i = 0; i < 1000; i++) {"
11723     "  result = o.x(42);"
11724     "}");
11725   CHECK_EQ(43, value->Int32Value());
11726 }
11727
11728
11729 static v8::Handle<Value> call_ic_function5;
11730 static void InterceptorCallICGetter5(
11731     Local<String> name,
11732     const v8::PropertyCallbackInfo<v8::Value>& info) {
11733   ApiTestFuzzer::Fuzz();
11734   if (v8_str("x")->Equals(name))
11735     info.GetReturnValue().Set(call_ic_function5);
11736 }
11737
11738
11739 // This test checks that if interceptor provides a function,
11740 // even if we cached constant function, interceptor's function
11741 // is invoked
11742 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11743   v8::Isolate* isolate = CcTest::isolate();
11744   v8::HandleScope scope(isolate);
11745   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11746   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11747   LocalContext context;
11748   context->Global()->Set(v8_str("o"), templ->NewInstance());
11749   call_ic_function5 =
11750       v8_compile("function f(x) { return x - 1; }; f")->Run();
11751   v8::Handle<Value> value = CompileRun(
11752     "function inc(x) { return x + 1; };"
11753     "inc(1);"
11754     "o.x = inc;"
11755     "var result = 0;"
11756     "for (var i = 0; i < 1000; i++) {"
11757     "  result = o.x(42);"
11758     "}");
11759   CHECK_EQ(41, value->Int32Value());
11760 }
11761
11762
11763 static v8::Handle<Value> call_ic_function6;
11764 static void InterceptorCallICGetter6(
11765     Local<String> name,
11766     const v8::PropertyCallbackInfo<v8::Value>& info) {
11767   ApiTestFuzzer::Fuzz();
11768   if (v8_str("x")->Equals(name))
11769     info.GetReturnValue().Set(call_ic_function6);
11770 }
11771
11772
11773 // Same test as above, except the code is wrapped in a function
11774 // to test the optimized compiler.
11775 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11776   i::FLAG_allow_natives_syntax = true;
11777   v8::Isolate* isolate = CcTest::isolate();
11778   v8::HandleScope scope(isolate);
11779   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11780   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11781   LocalContext context;
11782   context->Global()->Set(v8_str("o"), templ->NewInstance());
11783   call_ic_function6 =
11784       v8_compile("function f(x) { return x - 1; }; f")->Run();
11785   v8::Handle<Value> value = CompileRun(
11786     "function inc(x) { return x + 1; };"
11787     "inc(1);"
11788     "o.x = inc;"
11789     "function test() {"
11790     "  var result = 0;"
11791     "  for (var i = 0; i < 1000; i++) {"
11792     "    result = o.x(42);"
11793     "  }"
11794     "  return result;"
11795     "};"
11796     "test();"
11797     "test();"
11798     "test();"
11799     "%OptimizeFunctionOnNextCall(test);"
11800     "test()");
11801   CHECK_EQ(41, value->Int32Value());
11802 }
11803
11804
11805 // Test the case when we stored constant function into
11806 // a stub, but it got invalidated later on
11807 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11808   v8::Isolate* isolate = CcTest::isolate();
11809   v8::HandleScope scope(isolate);
11810   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11811   templ->SetNamedPropertyHandler(NoBlockGetterX);
11812   LocalContext context;
11813   context->Global()->Set(v8_str("o"), templ->NewInstance());
11814   v8::Handle<Value> value = CompileRun(
11815     "function inc(x) { return x + 1; };"
11816     "inc(1);"
11817     "proto1 = new Object();"
11818     "proto2 = new Object();"
11819     "o.__proto__ = proto1;"
11820     "proto1.__proto__ = proto2;"
11821     "proto2.y = inc;"
11822     // Invoke it many times to compile a stub
11823     "for (var i = 0; i < 7; i++) {"
11824     "  o.y(42);"
11825     "}"
11826     "proto1.y = function(x) { return x - 1; };"
11827     "var result = 0;"
11828     "for (var i = 0; i < 7; i++) {"
11829     "  result += o.y(42);"
11830     "}");
11831   CHECK_EQ(41 * 7, value->Int32Value());
11832 }
11833
11834
11835 // Test the case when we stored constant function into
11836 // a stub, but it got invalidated later on due to override on
11837 // global object which is between interceptor and constant function' holders.
11838 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11839   v8::Isolate* isolate = CcTest::isolate();
11840   v8::HandleScope scope(isolate);
11841   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11842   templ->SetNamedPropertyHandler(NoBlockGetterX);
11843   LocalContext context;
11844   context->Global()->Set(v8_str("o"), templ->NewInstance());
11845   v8::Handle<Value> value = CompileRun(
11846     "function inc(x) { return x + 1; };"
11847     "inc(1);"
11848     "o.__proto__ = this;"
11849     "this.__proto__.y = inc;"
11850     // Invoke it many times to compile a stub
11851     "for (var i = 0; i < 7; i++) {"
11852     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11853     "}"
11854     "this.y = function(x) { return x - 1; };"
11855     "var result = 0;"
11856     "for (var i = 0; i < 7; i++) {"
11857     "  result += o.y(42);"
11858     "}");
11859   CHECK_EQ(41 * 7, value->Int32Value());
11860 }
11861
11862
11863 // Test the case when actual function to call sits on global object.
11864 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11865   v8::Isolate* isolate = CcTest::isolate();
11866   v8::HandleScope scope(isolate);
11867   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11868   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11869
11870   LocalContext context;
11871   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11872
11873   v8::Handle<Value> value = CompileRun(
11874     "try {"
11875     "  o.__proto__ = this;"
11876     "  for (var i = 0; i < 10; i++) {"
11877     "    var v = o.parseFloat('239');"
11878     "    if (v != 239) throw v;"
11879       // Now it should be ICed and keep a reference to parseFloat.
11880     "  }"
11881     "  var result = 0;"
11882     "  for (var i = 0; i < 10; i++) {"
11883     "    result += o.parseFloat('239');"
11884     "  }"
11885     "  result"
11886     "} catch(e) {"
11887     "  e"
11888     "};");
11889   CHECK_EQ(239 * 10, value->Int32Value());
11890 }
11891
11892 static void InterceptorCallICFastApi(
11893     Local<String> name,
11894     const v8::PropertyCallbackInfo<v8::Value>& info) {
11895   ApiTestFuzzer::Fuzz();
11896   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
11897   int* call_count =
11898       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
11899   ++(*call_count);
11900   if ((*call_count) % 20 == 0) {
11901     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11902   }
11903 }
11904
11905 static void FastApiCallback_TrivialSignature(
11906     const v8::FunctionCallbackInfo<v8::Value>& args) {
11907   ApiTestFuzzer::Fuzz();
11908   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
11909   v8::Isolate* isolate = CcTest::isolate();
11910   CHECK_EQ(isolate, args.GetIsolate());
11911   CHECK_EQ(args.This(), args.Holder());
11912   CHECK(args.Data()->Equals(v8_str("method_data")));
11913   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11914 }
11915
11916 static void FastApiCallback_SimpleSignature(
11917     const v8::FunctionCallbackInfo<v8::Value>& args) {
11918   ApiTestFuzzer::Fuzz();
11919   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
11920   v8::Isolate* isolate = CcTest::isolate();
11921   CHECK_EQ(isolate, args.GetIsolate());
11922   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
11923   CHECK(args.Data()->Equals(v8_str("method_data")));
11924   // Note, we're using HasRealNamedProperty instead of Has to avoid
11925   // invoking the interceptor again.
11926   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
11927   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11928 }
11929
11930
11931 // Helper to maximize the odds of object moving.
11932 static void GenerateSomeGarbage() {
11933   CompileRun(
11934       "var garbage;"
11935       "for (var i = 0; i < 1000; i++) {"
11936       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
11937       "}"
11938       "garbage = undefined;");
11939 }
11940
11941
11942 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11943   static int count = 0;
11944   if (count++ % 3 == 0) {
11945     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11946         // This should move the stub
11947     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
11948   }
11949 }
11950
11951
11952 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
11953   LocalContext context;
11954   v8::Isolate* isolate = context->GetIsolate();
11955   v8::HandleScope scope(isolate);
11956   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
11957       v8::ObjectTemplate::New(isolate);
11958   nativeobject_templ->Set(isolate, "callback",
11959                           v8::FunctionTemplate::New(isolate,
11960                                                     DirectApiCallback));
11961   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11962   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11963   // call the api function multiple times to ensure direct call stub creation.
11964   CompileRun(
11965         "function f() {"
11966         "  for (var i = 1; i <= 30; i++) {"
11967         "    nativeobject.callback();"
11968         "  }"
11969         "}"
11970         "f();");
11971 }
11972
11973
11974 void ThrowingDirectApiCallback(
11975     const v8::FunctionCallbackInfo<v8::Value>& args) {
11976   args.GetIsolate()->ThrowException(v8_str("g"));
11977 }
11978
11979
11980 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
11981   LocalContext context;
11982   v8::Isolate* isolate = context->GetIsolate();
11983   v8::HandleScope scope(isolate);
11984   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
11985       v8::ObjectTemplate::New(isolate);
11986   nativeobject_templ->Set(isolate, "callback",
11987                           v8::FunctionTemplate::New(isolate,
11988                                                     ThrowingDirectApiCallback));
11989   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11990   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11991   // call the api function multiple times to ensure direct call stub creation.
11992   v8::Handle<Value> result = CompileRun(
11993       "var result = '';"
11994       "function f() {"
11995       "  for (var i = 1; i <= 5; i++) {"
11996       "    try { nativeobject.callback(); } catch (e) { result += e; }"
11997       "  }"
11998       "}"
11999       "f(); result;");
12000   CHECK_EQ(v8_str("ggggg"), result);
12001 }
12002
12003
12004 static Handle<Value> DoDirectGetter() {
12005   if (++p_getter_count % 3 == 0) {
12006     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12007     GenerateSomeGarbage();
12008   }
12009   return v8_str("Direct Getter Result");
12010 }
12011
12012 static void DirectGetterCallback(
12013     Local<String> name,
12014     const v8::PropertyCallbackInfo<v8::Value>& info) {
12015   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12016   info.GetReturnValue().Set(DoDirectGetter());
12017 }
12018
12019
12020 template<typename Accessor>
12021 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12022   LocalContext context;
12023   v8::Isolate* isolate = context->GetIsolate();
12024   v8::HandleScope scope(isolate);
12025   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12026   obj->SetAccessor(v8_str("p1"), accessor);
12027   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12028   p_getter_count = 0;
12029   v8::Handle<v8::Value> result = CompileRun(
12030       "function f() {"
12031       "  for (var i = 0; i < 30; i++) o1.p1;"
12032       "  return o1.p1"
12033       "}"
12034       "f();");
12035   CHECK_EQ(v8_str("Direct Getter Result"), result);
12036   CHECK_EQ(31, p_getter_count);
12037 }
12038
12039
12040 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12041   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12042 }
12043
12044
12045 void ThrowingDirectGetterCallback(
12046     Local<String> name,
12047     const v8::PropertyCallbackInfo<v8::Value>& info) {
12048   info.GetIsolate()->ThrowException(v8_str("g"));
12049 }
12050
12051
12052 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12053   LocalContext context;
12054   v8::Isolate* isolate = context->GetIsolate();
12055   v8::HandleScope scope(isolate);
12056   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12057   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12058   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12059   v8::Handle<Value> result = CompileRun(
12060       "var result = '';"
12061       "for (var i = 0; i < 5; i++) {"
12062       "    try { o1.p1; } catch (e) { result += e; }"
12063       "}"
12064       "result;");
12065   CHECK_EQ(v8_str("ggggg"), result);
12066 }
12067
12068
12069 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12070   int interceptor_call_count = 0;
12071   v8::Isolate* isolate = CcTest::isolate();
12072   v8::HandleScope scope(isolate);
12073   v8::Handle<v8::FunctionTemplate> fun_templ =
12074       v8::FunctionTemplate::New(isolate);
12075   v8::Handle<v8::FunctionTemplate> method_templ =
12076       v8::FunctionTemplate::New(isolate,
12077                                 FastApiCallback_TrivialSignature,
12078                                 v8_str("method_data"),
12079                                 v8::Handle<v8::Signature>());
12080   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12081   proto_templ->Set(v8_str("method"), method_templ);
12082   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12083   templ->SetNamedPropertyHandler(
12084       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12085       v8::External::New(isolate, &interceptor_call_count));
12086   LocalContext context;
12087   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12088   GenerateSomeGarbage();
12089   context->Global()->Set(v8_str("o"), fun->NewInstance());
12090   CompileRun(
12091       "var result = 0;"
12092       "for (var i = 0; i < 100; i++) {"
12093       "  result = o.method(41);"
12094       "}");
12095   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12096   CHECK_EQ(100, interceptor_call_count);
12097 }
12098
12099
12100 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12101   int interceptor_call_count = 0;
12102   v8::Isolate* isolate = CcTest::isolate();
12103   v8::HandleScope scope(isolate);
12104   v8::Handle<v8::FunctionTemplate> fun_templ =
12105       v8::FunctionTemplate::New(isolate);
12106   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12107       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12108       v8::Signature::New(isolate, fun_templ));
12109   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12110   proto_templ->Set(v8_str("method"), method_templ);
12111   fun_templ->SetHiddenPrototype(true);
12112   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12113   templ->SetNamedPropertyHandler(
12114       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12115       v8::External::New(isolate, &interceptor_call_count));
12116   LocalContext context;
12117   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12118   GenerateSomeGarbage();
12119   context->Global()->Set(v8_str("o"), fun->NewInstance());
12120   CompileRun(
12121       "o.foo = 17;"
12122       "var receiver = {};"
12123       "receiver.__proto__ = o;"
12124       "var result = 0;"
12125       "for (var i = 0; i < 100; i++) {"
12126       "  result = receiver.method(41);"
12127       "}");
12128   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12129   CHECK_EQ(100, interceptor_call_count);
12130 }
12131
12132
12133 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12134   int interceptor_call_count = 0;
12135   v8::Isolate* isolate = CcTest::isolate();
12136   v8::HandleScope scope(isolate);
12137   v8::Handle<v8::FunctionTemplate> fun_templ =
12138       v8::FunctionTemplate::New(isolate);
12139   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12140       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12141       v8::Signature::New(isolate, fun_templ));
12142   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12143   proto_templ->Set(v8_str("method"), method_templ);
12144   fun_templ->SetHiddenPrototype(true);
12145   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12146   templ->SetNamedPropertyHandler(
12147       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12148       v8::External::New(isolate, &interceptor_call_count));
12149   LocalContext context;
12150   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12151   GenerateSomeGarbage();
12152   context->Global()->Set(v8_str("o"), fun->NewInstance());
12153   CompileRun(
12154       "o.foo = 17;"
12155       "var receiver = {};"
12156       "receiver.__proto__ = o;"
12157       "var result = 0;"
12158       "var saved_result = 0;"
12159       "for (var i = 0; i < 100; i++) {"
12160       "  result = receiver.method(41);"
12161       "  if (i == 50) {"
12162       "    saved_result = result;"
12163       "    receiver = {method: function(x) { return x - 1 }};"
12164       "  }"
12165       "}");
12166   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12167   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12168   CHECK_GE(interceptor_call_count, 50);
12169 }
12170
12171
12172 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12173   int interceptor_call_count = 0;
12174   v8::Isolate* isolate = CcTest::isolate();
12175   v8::HandleScope scope(isolate);
12176   v8::Handle<v8::FunctionTemplate> fun_templ =
12177       v8::FunctionTemplate::New(isolate);
12178   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12179       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12180       v8::Signature::New(isolate, fun_templ));
12181   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12182   proto_templ->Set(v8_str("method"), method_templ);
12183   fun_templ->SetHiddenPrototype(true);
12184   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12185   templ->SetNamedPropertyHandler(
12186       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12187       v8::External::New(isolate, &interceptor_call_count));
12188   LocalContext context;
12189   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12190   GenerateSomeGarbage();
12191   context->Global()->Set(v8_str("o"), fun->NewInstance());
12192   CompileRun(
12193       "o.foo = 17;"
12194       "var receiver = {};"
12195       "receiver.__proto__ = o;"
12196       "var result = 0;"
12197       "var saved_result = 0;"
12198       "for (var i = 0; i < 100; i++) {"
12199       "  result = receiver.method(41);"
12200       "  if (i == 50) {"
12201       "    saved_result = result;"
12202       "    o.method = function(x) { return x - 1 };"
12203       "  }"
12204       "}");
12205   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12206   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12207   CHECK_GE(interceptor_call_count, 50);
12208 }
12209
12210
12211 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12212   int interceptor_call_count = 0;
12213   v8::Isolate* isolate = CcTest::isolate();
12214   v8::HandleScope scope(isolate);
12215   v8::Handle<v8::FunctionTemplate> fun_templ =
12216       v8::FunctionTemplate::New(isolate);
12217   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12218       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12219       v8::Signature::New(isolate, fun_templ));
12220   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12221   proto_templ->Set(v8_str("method"), method_templ);
12222   fun_templ->SetHiddenPrototype(true);
12223   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12224   templ->SetNamedPropertyHandler(
12225       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12226       v8::External::New(isolate, &interceptor_call_count));
12227   LocalContext context;
12228   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12229   GenerateSomeGarbage();
12230   context->Global()->Set(v8_str("o"), fun->NewInstance());
12231   v8::TryCatch try_catch;
12232   CompileRun(
12233       "o.foo = 17;"
12234       "var receiver = {};"
12235       "receiver.__proto__ = o;"
12236       "var result = 0;"
12237       "var saved_result = 0;"
12238       "for (var i = 0; i < 100; i++) {"
12239       "  result = receiver.method(41);"
12240       "  if (i == 50) {"
12241       "    saved_result = result;"
12242       "    receiver = 333;"
12243       "  }"
12244       "}");
12245   CHECK(try_catch.HasCaught());
12246   // TODO(verwaest): Adjust message.
12247   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12248            try_catch.Exception()->ToString());
12249   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12250   CHECK_GE(interceptor_call_count, 50);
12251 }
12252
12253
12254 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12255   int interceptor_call_count = 0;
12256   v8::Isolate* isolate = CcTest::isolate();
12257   v8::HandleScope scope(isolate);
12258   v8::Handle<v8::FunctionTemplate> fun_templ =
12259       v8::FunctionTemplate::New(isolate);
12260   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12261       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12262       v8::Signature::New(isolate, fun_templ));
12263   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12264   proto_templ->Set(v8_str("method"), method_templ);
12265   fun_templ->SetHiddenPrototype(true);
12266   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12267   templ->SetNamedPropertyHandler(
12268       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12269       v8::External::New(isolate, &interceptor_call_count));
12270   LocalContext context;
12271   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12272   GenerateSomeGarbage();
12273   context->Global()->Set(v8_str("o"), fun->NewInstance());
12274   v8::TryCatch try_catch;
12275   CompileRun(
12276       "o.foo = 17;"
12277       "var receiver = {};"
12278       "receiver.__proto__ = o;"
12279       "var result = 0;"
12280       "var saved_result = 0;"
12281       "for (var i = 0; i < 100; i++) {"
12282       "  result = receiver.method(41);"
12283       "  if (i == 50) {"
12284       "    saved_result = result;"
12285       "    receiver = {method: receiver.method};"
12286       "  }"
12287       "}");
12288   CHECK(try_catch.HasCaught());
12289   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12290            try_catch.Exception()->ToString());
12291   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12292   CHECK_GE(interceptor_call_count, 50);
12293 }
12294
12295
12296 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12297   v8::Isolate* isolate = CcTest::isolate();
12298   v8::HandleScope scope(isolate);
12299   v8::Handle<v8::FunctionTemplate> fun_templ =
12300       v8::FunctionTemplate::New(isolate);
12301   v8::Handle<v8::FunctionTemplate> method_templ =
12302       v8::FunctionTemplate::New(isolate,
12303                                 FastApiCallback_TrivialSignature,
12304                                 v8_str("method_data"),
12305                                 v8::Handle<v8::Signature>());
12306   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12307   proto_templ->Set(v8_str("method"), method_templ);
12308   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12309   USE(templ);
12310   LocalContext context;
12311   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12312   GenerateSomeGarbage();
12313   context->Global()->Set(v8_str("o"), fun->NewInstance());
12314   CompileRun(
12315       "var result = 0;"
12316       "for (var i = 0; i < 100; i++) {"
12317       "  result = o.method(41);"
12318       "}");
12319
12320   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12321 }
12322
12323
12324 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12325   v8::Isolate* isolate = CcTest::isolate();
12326   v8::HandleScope scope(isolate);
12327   v8::Handle<v8::FunctionTemplate> fun_templ =
12328       v8::FunctionTemplate::New(isolate);
12329   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12330       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12331       v8::Signature::New(isolate, fun_templ));
12332   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12333   proto_templ->Set(v8_str("method"), method_templ);
12334   fun_templ->SetHiddenPrototype(true);
12335   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12336   CHECK(!templ.IsEmpty());
12337   LocalContext context;
12338   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12339   GenerateSomeGarbage();
12340   context->Global()->Set(v8_str("o"), fun->NewInstance());
12341   CompileRun(
12342       "o.foo = 17;"
12343       "var receiver = {};"
12344       "receiver.__proto__ = o;"
12345       "var result = 0;"
12346       "for (var i = 0; i < 100; i++) {"
12347       "  result = receiver.method(41);"
12348       "}");
12349
12350   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12351 }
12352
12353
12354 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12355   v8::Isolate* isolate = CcTest::isolate();
12356   v8::HandleScope scope(isolate);
12357   v8::Handle<v8::FunctionTemplate> fun_templ =
12358       v8::FunctionTemplate::New(isolate);
12359   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12360       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12361       v8::Signature::New(isolate, fun_templ));
12362   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12363   proto_templ->Set(v8_str("method"), method_templ);
12364   fun_templ->SetHiddenPrototype(true);
12365   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12366   CHECK(!templ.IsEmpty());
12367   LocalContext context;
12368   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12369   GenerateSomeGarbage();
12370   context->Global()->Set(v8_str("o"), fun->NewInstance());
12371   CompileRun(
12372       "o.foo = 17;"
12373       "var receiver = {};"
12374       "receiver.__proto__ = o;"
12375       "var result = 0;"
12376       "var saved_result = 0;"
12377       "for (var i = 0; i < 100; i++) {"
12378       "  result = receiver.method(41);"
12379       "  if (i == 50) {"
12380       "    saved_result = result;"
12381       "    receiver = {method: function(x) { return x - 1 }};"
12382       "  }"
12383       "}");
12384   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12385   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12386 }
12387
12388
12389 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12390   v8::Isolate* isolate = CcTest::isolate();
12391   v8::HandleScope scope(isolate);
12392   v8::Handle<v8::FunctionTemplate> fun_templ =
12393       v8::FunctionTemplate::New(isolate);
12394   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12395       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12396       v8::Signature::New(isolate, fun_templ));
12397   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12398   proto_templ->Set(v8_str("method"), method_templ);
12399   fun_templ->SetHiddenPrototype(true);
12400   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12401   CHECK(!templ.IsEmpty());
12402   LocalContext context;
12403   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12404   GenerateSomeGarbage();
12405   context->Global()->Set(v8_str("o"), fun->NewInstance());
12406   v8::TryCatch try_catch;
12407   CompileRun(
12408       "o.foo = 17;"
12409       "var receiver = {};"
12410       "receiver.__proto__ = o;"
12411       "var result = 0;"
12412       "var saved_result = 0;"
12413       "for (var i = 0; i < 100; i++) {"
12414       "  result = receiver.method(41);"
12415       "  if (i == 50) {"
12416       "    saved_result = result;"
12417       "    receiver = 333;"
12418       "  }"
12419       "}");
12420   CHECK(try_catch.HasCaught());
12421   // TODO(verwaest): Adjust message.
12422   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12423            try_catch.Exception()->ToString());
12424   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12425 }
12426
12427
12428 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12429   v8::Isolate* isolate = CcTest::isolate();
12430   v8::HandleScope scope(isolate);
12431   v8::Handle<v8::FunctionTemplate> fun_templ =
12432       v8::FunctionTemplate::New(isolate);
12433   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12434       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12435       v8::Signature::New(isolate, fun_templ));
12436   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12437   proto_templ->Set(v8_str("method"), method_templ);
12438   fun_templ->SetHiddenPrototype(true);
12439   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12440   CHECK(!templ.IsEmpty());
12441   LocalContext context;
12442   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12443   GenerateSomeGarbage();
12444   context->Global()->Set(v8_str("o"), fun->NewInstance());
12445   v8::TryCatch try_catch;
12446   CompileRun(
12447       "o.foo = 17;"
12448       "var receiver = {};"
12449       "receiver.__proto__ = o;"
12450       "var result = 0;"
12451       "var saved_result = 0;"
12452       "for (var i = 0; i < 100; i++) {"
12453       "  result = receiver.method(41);"
12454       "  if (i == 50) {"
12455       "    saved_result = result;"
12456       "    receiver = Object.create(receiver);"
12457       "  }"
12458       "}");
12459   CHECK(try_catch.HasCaught());
12460   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12461            try_catch.Exception()->ToString());
12462   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12463 }
12464
12465
12466 v8::Handle<Value> keyed_call_ic_function;
12467
12468 static void InterceptorKeyedCallICGetter(
12469     Local<String> name,
12470     const v8::PropertyCallbackInfo<v8::Value>& info) {
12471   ApiTestFuzzer::Fuzz();
12472   if (v8_str("x")->Equals(name)) {
12473     info.GetReturnValue().Set(keyed_call_ic_function);
12474   }
12475 }
12476
12477
12478 // Test the case when we stored cacheable lookup into
12479 // a stub, but the function name changed (to another cacheable function).
12480 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12481   v8::Isolate* isolate = CcTest::isolate();
12482   v8::HandleScope scope(isolate);
12483   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12484   templ->SetNamedPropertyHandler(NoBlockGetterX);
12485   LocalContext context;
12486   context->Global()->Set(v8_str("o"), templ->NewInstance());
12487   CompileRun(
12488     "proto = new Object();"
12489     "proto.y = function(x) { return x + 1; };"
12490     "proto.z = function(x) { return x - 1; };"
12491     "o.__proto__ = proto;"
12492     "var result = 0;"
12493     "var method = 'y';"
12494     "for (var i = 0; i < 10; i++) {"
12495     "  if (i == 5) { method = 'z'; };"
12496     "  result += o[method](41);"
12497     "}");
12498   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12499 }
12500
12501
12502 // Test the case when we stored cacheable lookup into
12503 // a stub, but the function name changed (and the new function is present
12504 // both before and after the interceptor in the prototype chain).
12505 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12506   v8::Isolate* isolate = CcTest::isolate();
12507   v8::HandleScope scope(isolate);
12508   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12509   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12510   LocalContext context;
12511   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12512   keyed_call_ic_function =
12513       v8_compile("function f(x) { return x - 1; }; f")->Run();
12514   CompileRun(
12515     "o = new Object();"
12516     "proto2 = new Object();"
12517     "o.y = function(x) { return x + 1; };"
12518     "proto2.y = function(x) { return x + 2; };"
12519     "o.__proto__ = proto1;"
12520     "proto1.__proto__ = proto2;"
12521     "var result = 0;"
12522     "var method = 'x';"
12523     "for (var i = 0; i < 10; i++) {"
12524     "  if (i == 5) { method = 'y'; };"
12525     "  result += o[method](41);"
12526     "}");
12527   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12528 }
12529
12530
12531 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12532 // on the global object.
12533 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12534   v8::Isolate* isolate = CcTest::isolate();
12535   v8::HandleScope scope(isolate);
12536   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12537   templ->SetNamedPropertyHandler(NoBlockGetterX);
12538   LocalContext context;
12539   context->Global()->Set(v8_str("o"), templ->NewInstance());
12540   CompileRun(
12541     "function inc(x) { return x + 1; };"
12542     "inc(1);"
12543     "function dec(x) { return x - 1; };"
12544     "dec(1);"
12545     "o.__proto__ = this;"
12546     "this.__proto__.x = inc;"
12547     "this.__proto__.y = dec;"
12548     "var result = 0;"
12549     "var method = 'x';"
12550     "for (var i = 0; i < 10; i++) {"
12551     "  if (i == 5) { method = 'y'; };"
12552     "  result += o[method](41);"
12553     "}");
12554   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12555 }
12556
12557
12558 // Test the case when actual function to call sits on global object.
12559 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12560   v8::Isolate* isolate = CcTest::isolate();
12561   v8::HandleScope scope(isolate);
12562   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12563   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12564   LocalContext context;
12565   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12566
12567   CompileRun(
12568     "function len(x) { return x.length; };"
12569     "o.__proto__ = this;"
12570     "var m = 'parseFloat';"
12571     "var result = 0;"
12572     "for (var i = 0; i < 10; i++) {"
12573     "  if (i == 5) {"
12574     "    m = 'len';"
12575     "    saved_result = result;"
12576     "  };"
12577     "  result = o[m]('239');"
12578     "}");
12579   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12580   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12581 }
12582
12583
12584 // Test the map transition before the interceptor.
12585 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12586   v8::Isolate* isolate = CcTest::isolate();
12587   v8::HandleScope scope(isolate);
12588   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12589   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12590   LocalContext context;
12591   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12592
12593   CompileRun(
12594     "var o = new Object();"
12595     "o.__proto__ = proto;"
12596     "o.method = function(x) { return x + 1; };"
12597     "var m = 'method';"
12598     "var result = 0;"
12599     "for (var i = 0; i < 10; i++) {"
12600     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
12601     "  result += o[m](41);"
12602     "}");
12603   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12604 }
12605
12606
12607 // Test the map transition after the interceptor.
12608 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12609   v8::Isolate* isolate = CcTest::isolate();
12610   v8::HandleScope scope(isolate);
12611   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12612   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12613   LocalContext context;
12614   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12615
12616   CompileRun(
12617     "var proto = new Object();"
12618     "o.__proto__ = proto;"
12619     "proto.method = function(x) { return x + 1; };"
12620     "var m = 'method';"
12621     "var result = 0;"
12622     "for (var i = 0; i < 10; i++) {"
12623     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12624     "  result += o[m](41);"
12625     "}");
12626   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12627 }
12628
12629
12630 static int interceptor_call_count = 0;
12631
12632 static void InterceptorICRefErrorGetter(
12633     Local<String> name,
12634     const v8::PropertyCallbackInfo<v8::Value>& info) {
12635   ApiTestFuzzer::Fuzz();
12636   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12637     info.GetReturnValue().Set(call_ic_function2);
12638   }
12639 }
12640
12641
12642 // This test should hit load and call ICs for the interceptor case.
12643 // Once in a while, the interceptor will reply that a property was not
12644 // found in which case we should get a reference error.
12645 THREADED_TEST(InterceptorICReferenceErrors) {
12646   v8::Isolate* isolate = CcTest::isolate();
12647   v8::HandleScope scope(isolate);
12648   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12649   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12650   LocalContext context(0, templ, v8::Handle<Value>());
12651   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12652   v8::Handle<Value> value = CompileRun(
12653     "function f() {"
12654     "  for (var i = 0; i < 1000; i++) {"
12655     "    try { x; } catch(e) { return true; }"
12656     "  }"
12657     "  return false;"
12658     "};"
12659     "f();");
12660   CHECK_EQ(true, value->BooleanValue());
12661   interceptor_call_count = 0;
12662   value = CompileRun(
12663     "function g() {"
12664     "  for (var i = 0; i < 1000; i++) {"
12665     "    try { x(42); } catch(e) { return true; }"
12666     "  }"
12667     "  return false;"
12668     "};"
12669     "g();");
12670   CHECK_EQ(true, value->BooleanValue());
12671 }
12672
12673
12674 static int interceptor_ic_exception_get_count = 0;
12675
12676 static void InterceptorICExceptionGetter(
12677     Local<String> name,
12678     const v8::PropertyCallbackInfo<v8::Value>& info) {
12679   ApiTestFuzzer::Fuzz();
12680   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12681     info.GetReturnValue().Set(call_ic_function3);
12682   }
12683   if (interceptor_ic_exception_get_count == 20) {
12684     info.GetIsolate()->ThrowException(v8_num(42));
12685     return;
12686   }
12687 }
12688
12689
12690 // Test interceptor load/call IC where the interceptor throws an
12691 // exception once in a while.
12692 THREADED_TEST(InterceptorICGetterExceptions) {
12693   interceptor_ic_exception_get_count = 0;
12694   v8::Isolate* isolate = CcTest::isolate();
12695   v8::HandleScope scope(isolate);
12696   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12697   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12698   LocalContext context(0, templ, v8::Handle<Value>());
12699   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12700   v8::Handle<Value> value = CompileRun(
12701     "function f() {"
12702     "  for (var i = 0; i < 100; i++) {"
12703     "    try { x; } catch(e) { return true; }"
12704     "  }"
12705     "  return false;"
12706     "};"
12707     "f();");
12708   CHECK_EQ(true, value->BooleanValue());
12709   interceptor_ic_exception_get_count = 0;
12710   value = CompileRun(
12711     "function f() {"
12712     "  for (var i = 0; i < 100; i++) {"
12713     "    try { x(42); } catch(e) { return true; }"
12714     "  }"
12715     "  return false;"
12716     "};"
12717     "f();");
12718   CHECK_EQ(true, value->BooleanValue());
12719 }
12720
12721
12722 static int interceptor_ic_exception_set_count = 0;
12723
12724 static void InterceptorICExceptionSetter(
12725       Local<String> key,
12726       Local<Value> value,
12727       const v8::PropertyCallbackInfo<v8::Value>& info) {
12728   ApiTestFuzzer::Fuzz();
12729   if (++interceptor_ic_exception_set_count > 20) {
12730     info.GetIsolate()->ThrowException(v8_num(42));
12731   }
12732 }
12733
12734
12735 // Test interceptor store IC where the interceptor throws an exception
12736 // once in a while.
12737 THREADED_TEST(InterceptorICSetterExceptions) {
12738   interceptor_ic_exception_set_count = 0;
12739   v8::Isolate* isolate = CcTest::isolate();
12740   v8::HandleScope scope(isolate);
12741   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12742   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12743   LocalContext context(0, templ, v8::Handle<Value>());
12744   v8::Handle<Value> value = CompileRun(
12745     "function f() {"
12746     "  for (var i = 0; i < 100; i++) {"
12747     "    try { x = 42; } catch(e) { return true; }"
12748     "  }"
12749     "  return false;"
12750     "};"
12751     "f();");
12752   CHECK_EQ(true, value->BooleanValue());
12753 }
12754
12755
12756 // Test that we ignore null interceptors.
12757 THREADED_TEST(NullNamedInterceptor) {
12758   v8::Isolate* isolate = CcTest::isolate();
12759   v8::HandleScope scope(isolate);
12760   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12761   templ->SetNamedPropertyHandler(
12762       static_cast<v8::NamedPropertyGetterCallback>(0));
12763   LocalContext context;
12764   templ->Set(CcTest::isolate(), "x", v8_num(42));
12765   v8::Handle<v8::Object> obj = templ->NewInstance();
12766   context->Global()->Set(v8_str("obj"), obj);
12767   v8::Handle<Value> value = CompileRun("obj.x");
12768   CHECK(value->IsInt32());
12769   CHECK_EQ(42, value->Int32Value());
12770 }
12771
12772
12773 // Test that we ignore null interceptors.
12774 THREADED_TEST(NullIndexedInterceptor) {
12775   v8::Isolate* isolate = CcTest::isolate();
12776   v8::HandleScope scope(isolate);
12777   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12778   templ->SetIndexedPropertyHandler(
12779       static_cast<v8::IndexedPropertyGetterCallback>(0));
12780   LocalContext context;
12781   templ->Set(CcTest::isolate(), "42", v8_num(42));
12782   v8::Handle<v8::Object> obj = templ->NewInstance();
12783   context->Global()->Set(v8_str("obj"), obj);
12784   v8::Handle<Value> value = CompileRun("obj[42]");
12785   CHECK(value->IsInt32());
12786   CHECK_EQ(42, value->Int32Value());
12787 }
12788
12789
12790 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12791   v8::Isolate* isolate = CcTest::isolate();
12792   v8::HandleScope scope(isolate);
12793   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12794   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12795   LocalContext env;
12796   env->Global()->Set(v8_str("obj"),
12797                      templ->GetFunction()->NewInstance());
12798   ExpectTrue("obj.x === 42");
12799   ExpectTrue("!obj.propertyIsEnumerable('x')");
12800 }
12801
12802
12803 static void ThrowingGetter(Local<String> name,
12804                            const v8::PropertyCallbackInfo<v8::Value>& info) {
12805   ApiTestFuzzer::Fuzz();
12806   info.GetIsolate()->ThrowException(Handle<Value>());
12807   info.GetReturnValue().SetUndefined();
12808 }
12809
12810
12811 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12812   LocalContext context;
12813   HandleScope scope(context->GetIsolate());
12814
12815   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12816   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12817   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12818
12819   Local<Object> instance = templ->GetFunction()->NewInstance();
12820
12821   Local<Object> another = Object::New(context->GetIsolate());
12822   another->SetPrototype(instance);
12823
12824   Local<Object> with_js_getter = CompileRun(
12825       "o = {};\n"
12826       "o.__defineGetter__('f', function() { throw undefined; });\n"
12827       "o\n").As<Object>();
12828   CHECK(!with_js_getter.IsEmpty());
12829
12830   TryCatch try_catch;
12831
12832   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12833   CHECK(try_catch.HasCaught());
12834   try_catch.Reset();
12835   CHECK(result.IsEmpty());
12836
12837   result = another->GetRealNamedProperty(v8_str("f"));
12838   CHECK(try_catch.HasCaught());
12839   try_catch.Reset();
12840   CHECK(result.IsEmpty());
12841
12842   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12843   CHECK(try_catch.HasCaught());
12844   try_catch.Reset();
12845   CHECK(result.IsEmpty());
12846
12847   result = another->Get(v8_str("f"));
12848   CHECK(try_catch.HasCaught());
12849   try_catch.Reset();
12850   CHECK(result.IsEmpty());
12851
12852   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12853   CHECK(try_catch.HasCaught());
12854   try_catch.Reset();
12855   CHECK(result.IsEmpty());
12856
12857   result = with_js_getter->Get(v8_str("f"));
12858   CHECK(try_catch.HasCaught());
12859   try_catch.Reset();
12860   CHECK(result.IsEmpty());
12861 }
12862
12863
12864 static void ThrowingCallbackWithTryCatch(
12865     const v8::FunctionCallbackInfo<v8::Value>& args) {
12866   TryCatch try_catch;
12867   // Verboseness is important: it triggers message delivery which can call into
12868   // external code.
12869   try_catch.SetVerbose(true);
12870   CompileRun("throw 'from JS';");
12871   CHECK(try_catch.HasCaught());
12872   CHECK(!CcTest::i_isolate()->has_pending_exception());
12873   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12874 }
12875
12876
12877 static int call_depth;
12878
12879
12880 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
12881   TryCatch try_catch;
12882 }
12883
12884
12885 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
12886   if (--call_depth) CompileRun("throw 'ThrowInJS';");
12887 }
12888
12889
12890 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
12891   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12892 }
12893
12894
12895 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
12896   Handle<String> errorMessageString = message->Get();
12897   CHECK(!errorMessageString.IsEmpty());
12898   message->GetStackTrace();
12899   message->GetScriptResourceName();
12900 }
12901
12902
12903 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12904   LocalContext context;
12905   v8::Isolate* isolate = context->GetIsolate();
12906   HandleScope scope(isolate);
12907
12908   Local<Function> func =
12909       FunctionTemplate::New(isolate,
12910                             ThrowingCallbackWithTryCatch)->GetFunction();
12911   context->Global()->Set(v8_str("func"), func);
12912
12913   MessageCallback callbacks[] =
12914       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
12915   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12916     MessageCallback callback = callbacks[i];
12917     if (callback != NULL) {
12918       V8::AddMessageListener(callback);
12919     }
12920     // Some small number to control number of times message handler should
12921     // throw an exception.
12922     call_depth = 5;
12923     ExpectFalse(
12924         "var thrown = false;\n"
12925         "try { func(); } catch(e) { thrown = true; }\n"
12926         "thrown\n");
12927     if (callback != NULL) {
12928       V8::RemoveMessageListeners(callback);
12929     }
12930   }
12931 }
12932
12933
12934 static void ParentGetter(Local<String> name,
12935                          const v8::PropertyCallbackInfo<v8::Value>& info) {
12936   ApiTestFuzzer::Fuzz();
12937   info.GetReturnValue().Set(v8_num(1));
12938 }
12939
12940
12941 static void ChildGetter(Local<String> name,
12942                         const v8::PropertyCallbackInfo<v8::Value>& info) {
12943   ApiTestFuzzer::Fuzz();
12944   info.GetReturnValue().Set(v8_num(42));
12945 }
12946
12947
12948 THREADED_TEST(Overriding) {
12949   LocalContext context;
12950   v8::Isolate* isolate = context->GetIsolate();
12951   v8::HandleScope scope(isolate);
12952
12953   // Parent template.
12954   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
12955   Local<ObjectTemplate> parent_instance_templ =
12956       parent_templ->InstanceTemplate();
12957   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
12958
12959   // Template that inherits from the parent template.
12960   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
12961   Local<ObjectTemplate> child_instance_templ =
12962       child_templ->InstanceTemplate();
12963   child_templ->Inherit(parent_templ);
12964   // Override 'f'.  The child version of 'f' should get called for child
12965   // instances.
12966   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
12967   // Add 'g' twice.  The 'g' added last should get called for instances.
12968   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
12969   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
12970
12971   // Add 'h' as an accessor to the proto template with ReadOnly attributes
12972   // so 'h' can be shadowed on the instance object.
12973   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
12974   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
12975       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12976
12977   // Add 'i' as an accessor to the instance template with ReadOnly attributes
12978   // but the attribute does not have effect because it is duplicated with
12979   // NULL setter.
12980   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
12981       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12982
12983
12984
12985   // Instantiate the child template.
12986   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
12987
12988   // Check that the child function overrides the parent one.
12989   context->Global()->Set(v8_str("o"), instance);
12990   Local<Value> value = v8_compile("o.f")->Run();
12991   // Check that the 'g' that was added last is hit.
12992   CHECK_EQ(42, value->Int32Value());
12993   value = v8_compile("o.g")->Run();
12994   CHECK_EQ(42, value->Int32Value());
12995
12996   // Check that 'h' cannot be shadowed.
12997   value = v8_compile("o.h = 3; o.h")->Run();
12998   CHECK_EQ(1, value->Int32Value());
12999
13000   // Check that 'i' cannot be shadowed or changed.
13001   value = v8_compile("o.i = 3; o.i")->Run();
13002   CHECK_EQ(42, value->Int32Value());
13003 }
13004
13005
13006 static void IsConstructHandler(
13007     const v8::FunctionCallbackInfo<v8::Value>& args) {
13008   ApiTestFuzzer::Fuzz();
13009   args.GetReturnValue().Set(args.IsConstructCall());
13010 }
13011
13012
13013 THREADED_TEST(IsConstructCall) {
13014   v8::Isolate* isolate = CcTest::isolate();
13015   v8::HandleScope scope(isolate);
13016
13017   // Function template with call handler.
13018   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13019   templ->SetCallHandler(IsConstructHandler);
13020
13021   LocalContext context;
13022
13023   context->Global()->Set(v8_str("f"), templ->GetFunction());
13024   Local<Value> value = v8_compile("f()")->Run();
13025   CHECK(!value->BooleanValue());
13026   value = v8_compile("new f()")->Run();
13027   CHECK(value->BooleanValue());
13028 }
13029
13030
13031 THREADED_TEST(ObjectProtoToString) {
13032   v8::Isolate* isolate = CcTest::isolate();
13033   v8::HandleScope scope(isolate);
13034   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13035   templ->SetClassName(v8_str("MyClass"));
13036
13037   LocalContext context;
13038
13039   Local<String> customized_tostring = v8_str("customized toString");
13040
13041   // Replace Object.prototype.toString
13042   v8_compile("Object.prototype.toString = function() {"
13043                   "  return 'customized toString';"
13044                   "}")->Run();
13045
13046   // Normal ToString call should call replaced Object.prototype.toString
13047   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13048   Local<String> value = instance->ToString();
13049   CHECK(value->IsString() && value->Equals(customized_tostring));
13050
13051   // ObjectProtoToString should not call replace toString function.
13052   value = instance->ObjectProtoToString();
13053   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13054
13055   // Check global
13056   value = context->Global()->ObjectProtoToString();
13057   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13058
13059   // Check ordinary object
13060   Local<Value> object = v8_compile("new Object()")->Run();
13061   value = object.As<v8::Object>()->ObjectProtoToString();
13062   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13063 }
13064
13065
13066 THREADED_TEST(ObjectGetConstructorName) {
13067   LocalContext context;
13068   v8::HandleScope scope(context->GetIsolate());
13069   v8_compile("function Parent() {};"
13070              "function Child() {};"
13071              "Child.prototype = new Parent();"
13072              "var outer = { inner: function() { } };"
13073              "var p = new Parent();"
13074              "var c = new Child();"
13075              "var x = new outer.inner();")->Run();
13076
13077   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13078   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13079       v8_str("Parent")));
13080
13081   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13082   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13083       v8_str("Child")));
13084
13085   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13086   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13087       v8_str("outer.inner")));
13088 }
13089
13090
13091 bool ApiTestFuzzer::fuzzing_ = false;
13092 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13093 int ApiTestFuzzer::active_tests_;
13094 int ApiTestFuzzer::tests_being_run_;
13095 int ApiTestFuzzer::current_;
13096
13097
13098 // We are in a callback and want to switch to another thread (if we
13099 // are currently running the thread fuzzing test).
13100 void ApiTestFuzzer::Fuzz() {
13101   if (!fuzzing_) return;
13102   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13103   test->ContextSwitch();
13104 }
13105
13106
13107 // Let the next thread go.  Since it is also waiting on the V8 lock it may
13108 // not start immediately.
13109 bool ApiTestFuzzer::NextThread() {
13110   int test_position = GetNextTestNumber();
13111   const char* test_name = RegisterThreadedTest::nth(current_)->name();
13112   if (test_position == current_) {
13113     if (kLogThreading)
13114       printf("Stay with %s\n", test_name);
13115     return false;
13116   }
13117   if (kLogThreading) {
13118     printf("Switch from %s to %s\n",
13119            test_name,
13120            RegisterThreadedTest::nth(test_position)->name());
13121   }
13122   current_ = test_position;
13123   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13124   return true;
13125 }
13126
13127
13128 void ApiTestFuzzer::Run() {
13129   // When it is our turn...
13130   gate_.Wait();
13131   {
13132     // ... get the V8 lock and start running the test.
13133     v8::Locker locker(CcTest::isolate());
13134     CallTest();
13135   }
13136   // This test finished.
13137   active_ = false;
13138   active_tests_--;
13139   // If it was the last then signal that fact.
13140   if (active_tests_ == 0) {
13141     all_tests_done_.Signal();
13142   } else {
13143     // Otherwise select a new test and start that.
13144     NextThread();
13145   }
13146 }
13147
13148
13149 static unsigned linear_congruential_generator;
13150
13151
13152 void ApiTestFuzzer::SetUp(PartOfTest part) {
13153   linear_congruential_generator = i::FLAG_testing_prng_seed;
13154   fuzzing_ = true;
13155   int count = RegisterThreadedTest::count();
13156   int start =  count * part / (LAST_PART + 1);
13157   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13158   active_tests_ = tests_being_run_ = end - start + 1;
13159   for (int i = 0; i < tests_being_run_; i++) {
13160     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13161   }
13162   for (int i = 0; i < active_tests_; i++) {
13163     RegisterThreadedTest::nth(i)->fuzzer_->Start();
13164   }
13165 }
13166
13167
13168 static void CallTestNumber(int test_number) {
13169   (RegisterThreadedTest::nth(test_number)->callback())();
13170 }
13171
13172
13173 void ApiTestFuzzer::RunAllTests() {
13174   // Set off the first test.
13175   current_ = -1;
13176   NextThread();
13177   // Wait till they are all done.
13178   all_tests_done_.Wait();
13179 }
13180
13181
13182 int ApiTestFuzzer::GetNextTestNumber() {
13183   int next_test;
13184   do {
13185     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13186     linear_congruential_generator *= 1664525u;
13187     linear_congruential_generator += 1013904223u;
13188   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13189   return next_test;
13190 }
13191
13192
13193 void ApiTestFuzzer::ContextSwitch() {
13194   // If the new thread is the same as the current thread there is nothing to do.
13195   if (NextThread()) {
13196     // Now it can start.
13197     v8::Unlocker unlocker(CcTest::isolate());
13198     // Wait till someone starts us again.
13199     gate_.Wait();
13200     // And we're off.
13201   }
13202 }
13203
13204
13205 void ApiTestFuzzer::TearDown() {
13206   fuzzing_ = false;
13207   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13208     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13209     if (fuzzer != NULL) fuzzer->Join();
13210   }
13211 }
13212
13213
13214 // Lets not be needlessly self-referential.
13215 TEST(Threading1) {
13216   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13217   ApiTestFuzzer::RunAllTests();
13218   ApiTestFuzzer::TearDown();
13219 }
13220
13221
13222 TEST(Threading2) {
13223   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13224   ApiTestFuzzer::RunAllTests();
13225   ApiTestFuzzer::TearDown();
13226 }
13227
13228
13229 TEST(Threading3) {
13230   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13231   ApiTestFuzzer::RunAllTests();
13232   ApiTestFuzzer::TearDown();
13233 }
13234
13235
13236 TEST(Threading4) {
13237   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13238   ApiTestFuzzer::RunAllTests();
13239   ApiTestFuzzer::TearDown();
13240 }
13241
13242
13243 void ApiTestFuzzer::CallTest() {
13244   v8::Isolate::Scope scope(CcTest::isolate());
13245   if (kLogThreading)
13246     printf("Start test %d\n", test_number_);
13247   CallTestNumber(test_number_);
13248   if (kLogThreading)
13249     printf("End test %d\n", test_number_);
13250 }
13251
13252
13253 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13254   v8::Isolate* isolate = args.GetIsolate();
13255   CHECK(v8::Locker::IsLocked(isolate));
13256   ApiTestFuzzer::Fuzz();
13257   v8::Unlocker unlocker(isolate);
13258   const char* code = "throw 7;";
13259   {
13260     v8::Locker nested_locker(isolate);
13261     v8::HandleScope scope(isolate);
13262     v8::Handle<Value> exception;
13263     { v8::TryCatch try_catch;
13264       v8::Handle<Value> value = CompileRun(code);
13265       CHECK(value.IsEmpty());
13266       CHECK(try_catch.HasCaught());
13267       // Make sure to wrap the exception in a new handle because
13268       // the handle returned from the TryCatch is destroyed
13269       // when the TryCatch is destroyed.
13270       exception = Local<Value>::New(isolate, try_catch.Exception());
13271     }
13272     args.GetIsolate()->ThrowException(exception);
13273   }
13274 }
13275
13276
13277 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13278   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13279   ApiTestFuzzer::Fuzz();
13280   v8::Unlocker unlocker(CcTest::isolate());
13281   const char* code = "throw 7;";
13282   {
13283     v8::Locker nested_locker(CcTest::isolate());
13284     v8::HandleScope scope(args.GetIsolate());
13285     v8::Handle<Value> value = CompileRun(code);
13286     CHECK(value.IsEmpty());
13287     args.GetReturnValue().Set(v8_str("foo"));
13288   }
13289 }
13290
13291
13292 // These are locking tests that don't need to be run again
13293 // as part of the locking aggregation tests.
13294 TEST(NestedLockers) {
13295   v8::Isolate* isolate = CcTest::isolate();
13296   v8::Locker locker(isolate);
13297   CHECK(v8::Locker::IsLocked(isolate));
13298   LocalContext env;
13299   v8::HandleScope scope(env->GetIsolate());
13300   Local<v8::FunctionTemplate> fun_templ =
13301       v8::FunctionTemplate::New(isolate, ThrowInJS);
13302   Local<Function> fun = fun_templ->GetFunction();
13303   env->Global()->Set(v8_str("throw_in_js"), fun);
13304   Local<Script> script = v8_compile("(function () {"
13305                                     "  try {"
13306                                     "    throw_in_js();"
13307                                     "    return 42;"
13308                                     "  } catch (e) {"
13309                                     "    return e * 13;"
13310                                     "  }"
13311                                     "})();");
13312   CHECK_EQ(91, script->Run()->Int32Value());
13313 }
13314
13315
13316 // These are locking tests that don't need to be run again
13317 // as part of the locking aggregation tests.
13318 TEST(NestedLockersNoTryCatch) {
13319   v8::Locker locker(CcTest::isolate());
13320   LocalContext env;
13321   v8::HandleScope scope(env->GetIsolate());
13322   Local<v8::FunctionTemplate> fun_templ =
13323       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13324   Local<Function> fun = fun_templ->GetFunction();
13325   env->Global()->Set(v8_str("throw_in_js"), fun);
13326   Local<Script> script = v8_compile("(function () {"
13327                                     "  try {"
13328                                     "    throw_in_js();"
13329                                     "    return 42;"
13330                                     "  } catch (e) {"
13331                                     "    return e * 13;"
13332                                     "  }"
13333                                     "})();");
13334   CHECK_EQ(91, script->Run()->Int32Value());
13335 }
13336
13337
13338 THREADED_TEST(RecursiveLocking) {
13339   v8::Locker locker(CcTest::isolate());
13340   {
13341     v8::Locker locker2(CcTest::isolate());
13342     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13343   }
13344 }
13345
13346
13347 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13348   ApiTestFuzzer::Fuzz();
13349   v8::Unlocker unlocker(CcTest::isolate());
13350 }
13351
13352
13353 THREADED_TEST(LockUnlockLock) {
13354   {
13355     v8::Locker locker(CcTest::isolate());
13356     v8::HandleScope scope(CcTest::isolate());
13357     LocalContext env;
13358     Local<v8::FunctionTemplate> fun_templ =
13359         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13360     Local<Function> fun = fun_templ->GetFunction();
13361     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13362     Local<Script> script = v8_compile("(function () {"
13363                                       "  unlock_for_a_moment();"
13364                                       "  return 42;"
13365                                       "})();");
13366     CHECK_EQ(42, script->Run()->Int32Value());
13367   }
13368   {
13369     v8::Locker locker(CcTest::isolate());
13370     v8::HandleScope scope(CcTest::isolate());
13371     LocalContext env;
13372     Local<v8::FunctionTemplate> fun_templ =
13373         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13374     Local<Function> fun = fun_templ->GetFunction();
13375     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13376     Local<Script> script = v8_compile("(function () {"
13377                                       "  unlock_for_a_moment();"
13378                                       "  return 42;"
13379                                       "})();");
13380     CHECK_EQ(42, script->Run()->Int32Value());
13381   }
13382 }
13383
13384
13385 static int GetGlobalObjectsCount() {
13386   CcTest::heap()->EnsureHeapIsIterable();
13387   int count = 0;
13388   i::HeapIterator it(CcTest::heap());
13389   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13390     if (object->IsJSGlobalObject()) count++;
13391   return count;
13392 }
13393
13394
13395 static void CheckSurvivingGlobalObjectsCount(int expected) {
13396   // We need to collect all garbage twice to be sure that everything
13397   // has been collected.  This is because inline caches are cleared in
13398   // the first garbage collection but some of the maps have already
13399   // been marked at that point.  Therefore some of the maps are not
13400   // collected until the second garbage collection.
13401   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13402   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13403   int count = GetGlobalObjectsCount();
13404 #ifdef DEBUG
13405   if (count != expected) CcTest::heap()->TracePathToGlobal();
13406 #endif
13407   CHECK_EQ(expected, count);
13408 }
13409
13410
13411 TEST(DontLeakGlobalObjects) {
13412   // Regression test for issues 1139850 and 1174891.
13413
13414   i::FLAG_expose_gc = true;
13415   v8::V8::Initialize();
13416
13417   for (int i = 0; i < 5; i++) {
13418     { v8::HandleScope scope(CcTest::isolate());
13419       LocalContext context;
13420     }
13421     v8::V8::ContextDisposedNotification();
13422     CheckSurvivingGlobalObjectsCount(0);
13423
13424     { v8::HandleScope scope(CcTest::isolate());
13425       LocalContext context;
13426       v8_compile("Date")->Run();
13427     }
13428     v8::V8::ContextDisposedNotification();
13429     CheckSurvivingGlobalObjectsCount(0);
13430
13431     { v8::HandleScope scope(CcTest::isolate());
13432       LocalContext context;
13433       v8_compile("/aaa/")->Run();
13434     }
13435     v8::V8::ContextDisposedNotification();
13436     CheckSurvivingGlobalObjectsCount(0);
13437
13438     { v8::HandleScope scope(CcTest::isolate());
13439       const char* extension_list[] = { "v8/gc" };
13440       v8::ExtensionConfiguration extensions(1, extension_list);
13441       LocalContext context(&extensions);
13442       v8_compile("gc();")->Run();
13443     }
13444     v8::V8::ContextDisposedNotification();
13445     CheckSurvivingGlobalObjectsCount(0);
13446   }
13447 }
13448
13449
13450 TEST(CopyablePersistent) {
13451   LocalContext context;
13452   v8::Isolate* isolate = context->GetIsolate();
13453   i::GlobalHandles* globals =
13454       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13455   int initial_handles = globals->global_handles_count();
13456   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13457       CopyableObject;
13458   {
13459     CopyableObject handle1;
13460     {
13461       v8::HandleScope scope(isolate);
13462       handle1.Reset(isolate, v8::Object::New(isolate));
13463     }
13464     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13465     CopyableObject  handle2;
13466     handle2 = handle1;
13467     CHECK(handle1 == handle2);
13468     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13469     CopyableObject handle3(handle2);
13470     CHECK(handle1 == handle3);
13471     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13472   }
13473   // Verify autodispose
13474   CHECK_EQ(initial_handles, globals->global_handles_count());
13475 }
13476
13477
13478 static void WeakApiCallback(
13479     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13480   Local<Value> value = data.GetValue()->Get(v8_str("key"));
13481   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13482   data.GetParameter()->Reset();
13483   delete data.GetParameter();
13484 }
13485
13486
13487 TEST(WeakCallbackApi) {
13488   LocalContext context;
13489   v8::Isolate* isolate = context->GetIsolate();
13490   i::GlobalHandles* globals =
13491       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13492   int initial_handles = globals->global_handles_count();
13493   {
13494     v8::HandleScope scope(isolate);
13495     v8::Local<v8::Object> obj = v8::Object::New(isolate);
13496     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13497     v8::Persistent<v8::Object>* handle =
13498         new v8::Persistent<v8::Object>(isolate, obj);
13499     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13500                                                              WeakApiCallback);
13501   }
13502   reinterpret_cast<i::Isolate*>(isolate)->heap()->
13503       CollectAllGarbage(i::Heap::kNoGCFlags);
13504   // Verify disposed.
13505   CHECK_EQ(initial_handles, globals->global_handles_count());
13506 }
13507
13508
13509 v8::Persistent<v8::Object> some_object;
13510 v8::Persistent<v8::Object> bad_handle;
13511
13512 void NewPersistentHandleCallback(
13513     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13514   v8::HandleScope scope(data.GetIsolate());
13515   bad_handle.Reset(data.GetIsolate(), some_object);
13516   data.GetParameter()->Reset();
13517 }
13518
13519
13520 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13521   LocalContext context;
13522   v8::Isolate* isolate = context->GetIsolate();
13523
13524   v8::Persistent<v8::Object> handle1, handle2;
13525   {
13526     v8::HandleScope scope(isolate);
13527     some_object.Reset(isolate, v8::Object::New(isolate));
13528     handle1.Reset(isolate, v8::Object::New(isolate));
13529     handle2.Reset(isolate, v8::Object::New(isolate));
13530   }
13531   // Note: order is implementation dependent alas: currently
13532   // global handle nodes are processed by PostGarbageCollectionProcessing
13533   // in reverse allocation order, so if second allocated handle is deleted,
13534   // weak callback of the first handle would be able to 'reallocate' it.
13535   handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13536   handle2.Reset();
13537   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13538 }
13539
13540
13541 v8::Persistent<v8::Object> to_be_disposed;
13542
13543 void DisposeAndForceGcCallback(
13544     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13545   to_be_disposed.Reset();
13546   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13547   data.GetParameter()->Reset();
13548 }
13549
13550
13551 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13552   LocalContext context;
13553   v8::Isolate* isolate = context->GetIsolate();
13554
13555   v8::Persistent<v8::Object> handle1, handle2;
13556   {
13557     v8::HandleScope scope(isolate);
13558     handle1.Reset(isolate, v8::Object::New(isolate));
13559     handle2.Reset(isolate, v8::Object::New(isolate));
13560   }
13561   handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13562   to_be_disposed.Reset(isolate, handle2);
13563   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13564 }
13565
13566 void DisposingCallback(
13567     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13568   data.GetParameter()->Reset();
13569 }
13570
13571 void HandleCreatingCallback(
13572     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13573   v8::HandleScope scope(data.GetIsolate());
13574   v8::Persistent<v8::Object>(data.GetIsolate(),
13575                              v8::Object::New(data.GetIsolate()));
13576   data.GetParameter()->Reset();
13577 }
13578
13579
13580 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13581   LocalContext context;
13582   v8::Isolate* isolate = context->GetIsolate();
13583
13584   v8::Persistent<v8::Object> handle1, handle2, handle3;
13585   {
13586     v8::HandleScope scope(isolate);
13587     handle3.Reset(isolate, v8::Object::New(isolate));
13588     handle2.Reset(isolate, v8::Object::New(isolate));
13589     handle1.Reset(isolate, v8::Object::New(isolate));
13590   }
13591   handle2.SetWeak(&handle2, DisposingCallback);
13592   handle3.SetWeak(&handle3, HandleCreatingCallback);
13593   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13594 }
13595
13596
13597 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13598   v8::V8::Initialize();
13599
13600   const int nof = 2;
13601   const char* sources[nof] = {
13602     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13603     "Object()"
13604   };
13605
13606   for (int i = 0; i < nof; i++) {
13607     const char* source = sources[i];
13608     { v8::HandleScope scope(CcTest::isolate());
13609       LocalContext context;
13610       CompileRun(source);
13611     }
13612     { v8::HandleScope scope(CcTest::isolate());
13613       LocalContext context;
13614       CompileRun(source);
13615     }
13616   }
13617 }
13618
13619
13620 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13621   v8::EscapableHandleScope inner(env->GetIsolate());
13622   env->Enter();
13623   v8::Local<Value> three = v8_num(3);
13624   v8::Local<Value> value = inner.Escape(three);
13625   env->Exit();
13626   return value;
13627 }
13628
13629
13630 THREADED_TEST(NestedHandleScopeAndContexts) {
13631   v8::Isolate* isolate = CcTest::isolate();
13632   v8::HandleScope outer(isolate);
13633   v8::Local<Context> env = Context::New(isolate);
13634   env->Enter();
13635   v8::Handle<Value> value = NestedScope(env);
13636   v8::Handle<String> str(value->ToString());
13637   CHECK(!str.IsEmpty());
13638   env->Exit();
13639 }
13640
13641
13642 static bool MatchPointers(void* key1, void* key2) {
13643   return key1 == key2;
13644 }
13645
13646
13647 struct SymbolInfo {
13648   size_t id;
13649   size_t size;
13650   std::string name;
13651 };
13652
13653
13654 class SetFunctionEntryHookTest {
13655  public:
13656   SetFunctionEntryHookTest() {
13657     CHECK(instance_ == NULL);
13658     instance_ = this;
13659   }
13660   ~SetFunctionEntryHookTest() {
13661     CHECK(instance_ == this);
13662     instance_ = NULL;
13663   }
13664   void Reset() {
13665     symbols_.clear();
13666     symbol_locations_.clear();
13667     invocations_.clear();
13668   }
13669   void RunTest();
13670   void OnJitEvent(const v8::JitCodeEvent* event);
13671   static void JitEvent(const v8::JitCodeEvent* event) {
13672     CHECK(instance_ != NULL);
13673     instance_->OnJitEvent(event);
13674   }
13675
13676   void OnEntryHook(uintptr_t function,
13677                    uintptr_t return_addr_location);
13678   static void EntryHook(uintptr_t function,
13679                         uintptr_t return_addr_location) {
13680     CHECK(instance_ != NULL);
13681     instance_->OnEntryHook(function, return_addr_location);
13682   }
13683
13684   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13685     CHECK(instance_ != NULL);
13686     args.GetReturnValue().Set(v8_num(42));
13687   }
13688   void RunLoopInNewEnv(v8::Isolate* isolate);
13689
13690   // Records addr as location of symbol.
13691   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13692
13693   // Finds the symbol containing addr
13694   SymbolInfo* FindSymbolForAddr(i::Address addr);
13695   // Returns the number of invocations where the caller name contains
13696   // \p caller_name and the function name contains \p function_name.
13697   int CountInvocations(const char* caller_name,
13698                        const char* function_name);
13699
13700   i::Handle<i::JSFunction> foo_func_;
13701   i::Handle<i::JSFunction> bar_func_;
13702
13703   typedef std::map<size_t, SymbolInfo> SymbolMap;
13704   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13705   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13706   SymbolMap symbols_;
13707   SymbolLocationMap symbol_locations_;
13708   InvocationMap invocations_;
13709
13710   static SetFunctionEntryHookTest* instance_;
13711 };
13712 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13713
13714
13715 // Returns true if addr is in the range [start, start+len).
13716 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13717   if (start <= addr && start + len > addr)
13718     return true;
13719
13720   return false;
13721 }
13722
13723 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13724                                               SymbolInfo* symbol) {
13725   // Insert the symbol at the new location.
13726   SymbolLocationMap::iterator it =
13727       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13728   // Now erase symbols to the left and right that overlap this one.
13729   while (it != symbol_locations_.begin()) {
13730     SymbolLocationMap::iterator left = it;
13731     --left;
13732     if (!Overlaps(left->first, left->second->size, addr))
13733       break;
13734     symbol_locations_.erase(left);
13735   }
13736
13737   // Now erase symbols to the left and right that overlap this one.
13738   while (true) {
13739     SymbolLocationMap::iterator right = it;
13740     ++right;
13741     if (right == symbol_locations_.end())
13742         break;
13743     if (!Overlaps(addr, symbol->size, right->first))
13744       break;
13745     symbol_locations_.erase(right);
13746   }
13747 }
13748
13749
13750 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13751   switch (event->type) {
13752     case v8::JitCodeEvent::CODE_ADDED: {
13753         CHECK(event->code_start != NULL);
13754         CHECK_NE(0, static_cast<int>(event->code_len));
13755         CHECK(event->name.str != NULL);
13756         size_t symbol_id = symbols_.size();
13757
13758         // Record the new symbol.
13759         SymbolInfo& info = symbols_[symbol_id];
13760         info.id = symbol_id;
13761         info.size = event->code_len;
13762         info.name.assign(event->name.str, event->name.str + event->name.len);
13763
13764         // And record it's location.
13765         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13766       }
13767       break;
13768
13769     case v8::JitCodeEvent::CODE_MOVED: {
13770         // We would like to never see code move that we haven't seen before,
13771         // but the code creation event does not happen until the line endings
13772         // have been calculated (this is so that we can report the line in the
13773         // script at which the function source is found, see
13774         // Compiler::RecordFunctionCompilation) and the line endings
13775         // calculations can cause a GC, which can move the newly created code
13776         // before its existence can be logged.
13777         SymbolLocationMap::iterator it(
13778             symbol_locations_.find(
13779                 reinterpret_cast<i::Address>(event->code_start)));
13780         if (it != symbol_locations_.end()) {
13781           // Found a symbol at this location, move it.
13782           SymbolInfo* info = it->second;
13783           symbol_locations_.erase(it);
13784           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13785                          info);
13786         }
13787       }
13788     default:
13789       break;
13790   }
13791 }
13792
13793 void SetFunctionEntryHookTest::OnEntryHook(
13794     uintptr_t function, uintptr_t return_addr_location) {
13795   // Get the function's code object.
13796   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13797       reinterpret_cast<i::Address>(function));
13798   CHECK(function_code != NULL);
13799
13800   // Then try and look up the caller's code object.
13801   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13802
13803   // Count the invocation.
13804   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13805   SymbolInfo* function_symbol =
13806       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13807   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13808
13809   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13810     // Check that we have a symbol for the "bar" function at the right location.
13811     SymbolLocationMap::iterator it(
13812         symbol_locations_.find(function_code->instruction_start()));
13813     CHECK(it != symbol_locations_.end());
13814   }
13815
13816   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13817     // Check that we have a symbol for "foo" at the right location.
13818     SymbolLocationMap::iterator it(
13819         symbol_locations_.find(function_code->instruction_start()));
13820     CHECK(it != symbol_locations_.end());
13821   }
13822 }
13823
13824
13825 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13826   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13827   // Do we have a direct hit on a symbol?
13828   if (it != symbol_locations_.end()) {
13829     if (it->first == addr)
13830       return it->second;
13831   }
13832
13833   // If not a direct hit, it'll have to be the previous symbol.
13834   if (it == symbol_locations_.begin())
13835     return NULL;
13836
13837   --it;
13838   size_t offs = addr - it->first;
13839   if (offs < it->second->size)
13840     return it->second;
13841
13842   return NULL;
13843 }
13844
13845
13846 int SetFunctionEntryHookTest::CountInvocations(
13847     const char* caller_name, const char* function_name) {
13848   InvocationMap::iterator it(invocations_.begin());
13849   int invocations = 0;
13850   for (; it != invocations_.end(); ++it) {
13851     SymbolInfo* caller = it->first.first;
13852     SymbolInfo* function = it->first.second;
13853
13854     // Filter out non-matching functions.
13855     if (function_name != NULL) {
13856       if (function->name.find(function_name) == std::string::npos)
13857         continue;
13858     }
13859
13860     // Filter out non-matching callers.
13861     if (caller_name != NULL) {
13862       if (caller == NULL)
13863         continue;
13864       if (caller->name.find(caller_name) == std::string::npos)
13865         continue;
13866     }
13867
13868     // It matches add the invocation count to the tally.
13869     invocations += it->second;
13870   }
13871
13872   return invocations;
13873 }
13874
13875
13876 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13877   v8::HandleScope outer(isolate);
13878   v8::Local<Context> env = Context::New(isolate);
13879   env->Enter();
13880
13881   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
13882   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
13883   env->Global()->Set(v8_str("obj"), t->NewInstance());
13884
13885   const char* script =
13886       "function bar() {\n"
13887       "  var sum = 0;\n"
13888       "  for (i = 0; i < 100; ++i)\n"
13889       "    sum = foo(i);\n"
13890       "  return sum;\n"
13891       "}\n"
13892       "function foo(i) { return i * i; }\n"
13893       "// Invoke on the runtime function.\n"
13894       "obj.asdf()";
13895   CompileRun(script);
13896   bar_func_ = i::Handle<i::JSFunction>::cast(
13897           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
13898   ASSERT(!bar_func_.is_null());
13899
13900   foo_func_ =
13901       i::Handle<i::JSFunction>::cast(
13902            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
13903   ASSERT(!foo_func_.is_null());
13904
13905   v8::Handle<v8::Value> value = CompileRun("bar();");
13906   CHECK(value->IsNumber());
13907   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13908
13909   // Test the optimized codegen path.
13910   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
13911                      "bar();");
13912   CHECK(value->IsNumber());
13913   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13914
13915   env->Exit();
13916 }
13917
13918
13919 void SetFunctionEntryHookTest::RunTest() {
13920   // Work in a new isolate throughout.
13921   v8::Isolate* isolate = v8::Isolate::New();
13922
13923   // Test setting the entry hook on the new isolate.
13924   CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13925
13926   // Replacing the hook, once set should fail.
13927   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13928
13929   {
13930     v8::Isolate::Scope scope(isolate);
13931
13932     v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
13933
13934     RunLoopInNewEnv(isolate);
13935
13936     // Check the exepected invocation counts.
13937     CHECK_EQ(2, CountInvocations(NULL, "bar"));
13938     CHECK_EQ(200, CountInvocations("bar", "foo"));
13939     CHECK_EQ(200, CountInvocations(NULL, "foo"));
13940
13941     // Verify that we have an entry hook on some specific stubs.
13942     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
13943     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
13944     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
13945   }
13946   isolate->Dispose();
13947
13948   Reset();
13949
13950   // Make sure a second isolate is unaffected by the previous entry hook.
13951   isolate = v8::Isolate::New();
13952   {
13953     v8::Isolate::Scope scope(isolate);
13954
13955     // Reset the entry count to zero and set the entry hook.
13956     RunLoopInNewEnv(isolate);
13957
13958     // We should record no invocations in this isolate.
13959     CHECK_EQ(0, static_cast<int>(invocations_.size()));
13960   }
13961   // Since the isolate has been used, we shouldn't be able to set an entry
13962   // hook anymore.
13963   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13964
13965   isolate->Dispose();
13966 }
13967
13968
13969 TEST(SetFunctionEntryHook) {
13970   // FunctionEntryHook does not work well with experimental natives.
13971   // Experimental natives are compiled during snapshot deserialization.
13972   // This test breaks because InstallGetter (function from snapshot that
13973   // only gets called from experimental natives) is compiled with entry hooks.
13974   i::FLAG_allow_natives_syntax = true;
13975   i::FLAG_use_inlining = false;
13976
13977   SetFunctionEntryHookTest test;
13978   test.RunTest();
13979 }
13980
13981
13982 static i::HashMap* code_map = NULL;
13983 static i::HashMap* jitcode_line_info = NULL;
13984 static int saw_bar = 0;
13985 static int move_events = 0;
13986
13987
13988 static bool FunctionNameIs(const char* expected,
13989                            const v8::JitCodeEvent* event) {
13990   // Log lines for functions are of the general form:
13991   // "LazyCompile:<type><function_name>", where the type is one of
13992   // "*", "~" or "".
13993   static const char kPreamble[] = "LazyCompile:";
13994   static size_t kPreambleLen = sizeof(kPreamble) - 1;
13995
13996   if (event->name.len < sizeof(kPreamble) - 1 ||
13997       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
13998     return false;
13999   }
14000
14001   const char* tail = event->name.str + kPreambleLen;
14002   size_t tail_len = event->name.len - kPreambleLen;
14003   size_t expected_len = strlen(expected);
14004   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14005     --tail_len;
14006     ++tail;
14007   }
14008
14009   // Check for tails like 'bar :1'.
14010   if (tail_len > expected_len + 2 &&
14011       tail[expected_len] == ' ' &&
14012       tail[expected_len + 1] == ':' &&
14013       tail[expected_len + 2] &&
14014       !strncmp(tail, expected, expected_len)) {
14015     return true;
14016   }
14017
14018   if (tail_len != expected_len)
14019     return false;
14020
14021   return strncmp(tail, expected, expected_len) == 0;
14022 }
14023
14024
14025 static void event_handler(const v8::JitCodeEvent* event) {
14026   CHECK(event != NULL);
14027   CHECK(code_map != NULL);
14028   CHECK(jitcode_line_info != NULL);
14029
14030   class DummyJitCodeLineInfo {
14031   };
14032
14033   switch (event->type) {
14034     case v8::JitCodeEvent::CODE_ADDED: {
14035         CHECK(event->code_start != NULL);
14036         CHECK_NE(0, static_cast<int>(event->code_len));
14037         CHECK(event->name.str != NULL);
14038         i::HashMap::Entry* entry =
14039             code_map->Lookup(event->code_start,
14040                              i::ComputePointerHash(event->code_start),
14041                              true);
14042         entry->value = reinterpret_cast<void*>(event->code_len);
14043
14044         if (FunctionNameIs("bar", event)) {
14045           ++saw_bar;
14046         }
14047       }
14048       break;
14049
14050     case v8::JitCodeEvent::CODE_MOVED: {
14051         uint32_t hash = i::ComputePointerHash(event->code_start);
14052         // We would like to never see code move that we haven't seen before,
14053         // but the code creation event does not happen until the line endings
14054         // have been calculated (this is so that we can report the line in the
14055         // script at which the function source is found, see
14056         // Compiler::RecordFunctionCompilation) and the line endings
14057         // calculations can cause a GC, which can move the newly created code
14058         // before its existence can be logged.
14059         i::HashMap::Entry* entry =
14060             code_map->Lookup(event->code_start, hash, false);
14061         if (entry != NULL) {
14062           ++move_events;
14063
14064           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14065           code_map->Remove(event->code_start, hash);
14066
14067           entry = code_map->Lookup(event->new_code_start,
14068                                    i::ComputePointerHash(event->new_code_start),
14069                                    true);
14070           CHECK(entry != NULL);
14071           entry->value = reinterpret_cast<void*>(event->code_len);
14072         }
14073       }
14074       break;
14075
14076     case v8::JitCodeEvent::CODE_REMOVED:
14077       // Object/code removal events are currently not dispatched from the GC.
14078       CHECK(false);
14079       break;
14080
14081     // For CODE_START_LINE_INFO_RECORDING event, we will create one
14082     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14083     // record it in jitcode_line_info.
14084     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14085         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14086         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14087         temp_event->user_data = line_info;
14088         i::HashMap::Entry* entry =
14089             jitcode_line_info->Lookup(line_info,
14090                                       i::ComputePointerHash(line_info),
14091                                       true);
14092         entry->value = reinterpret_cast<void*>(line_info);
14093       }
14094       break;
14095     // For these two events, we will check whether the event->user_data
14096     // data structure is created before during CODE_START_LINE_INFO_RECORDING
14097     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14098     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14099         CHECK(event->user_data != NULL);
14100         uint32_t hash = i::ComputePointerHash(event->user_data);
14101         i::HashMap::Entry* entry =
14102             jitcode_line_info->Lookup(event->user_data, hash, false);
14103         CHECK(entry != NULL);
14104         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14105       }
14106       break;
14107
14108     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14109         CHECK(event->user_data != NULL);
14110         uint32_t hash = i::ComputePointerHash(event->user_data);
14111         i::HashMap::Entry* entry =
14112             jitcode_line_info->Lookup(event->user_data, hash, false);
14113         CHECK(entry != NULL);
14114       }
14115       break;
14116
14117     default:
14118       // Impossible event.
14119       CHECK(false);
14120       break;
14121   }
14122 }
14123
14124
14125 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14126   i::FLAG_stress_compaction = true;
14127   i::FLAG_incremental_marking = false;
14128   const char* script =
14129     "function bar() {"
14130     "  var sum = 0;"
14131     "  for (i = 0; i < 100; ++i)"
14132     "    sum = foo(i);"
14133     "  return sum;"
14134     "}"
14135     "function foo(i) { return i * i; };"
14136     "bar();";
14137
14138   // Run this test in a new isolate to make sure we don't
14139   // have remnants of state from other code.
14140   v8::Isolate* isolate = v8::Isolate::New();
14141   isolate->Enter();
14142   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14143   i::Heap* heap = i_isolate->heap();
14144
14145   {
14146     v8::HandleScope scope(isolate);
14147     i::HashMap code(MatchPointers);
14148     code_map = &code;
14149
14150     i::HashMap lineinfo(MatchPointers);
14151     jitcode_line_info = &lineinfo;
14152
14153     saw_bar = 0;
14154     move_events = 0;
14155
14156     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14157
14158     // Generate new code objects sparsely distributed across several
14159     // different fragmented code-space pages.
14160     const int kIterations = 10;
14161     for (int i = 0; i < kIterations; ++i) {
14162       LocalContext env(isolate);
14163       i::AlwaysAllocateScope always_allocate(i_isolate);
14164       SimulateFullSpace(heap->code_space());
14165       CompileRun(script);
14166
14167       // Keep a strong reference to the code object in the handle scope.
14168       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14169           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14170       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14171           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14172
14173       // Clear the compilation cache to get more wastage.
14174       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14175     }
14176
14177     // Force code movement.
14178     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14179
14180     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14181
14182     CHECK_LE(kIterations, saw_bar);
14183     CHECK_LT(0, move_events);
14184
14185     code_map = NULL;
14186     jitcode_line_info = NULL;
14187   }
14188
14189   isolate->Exit();
14190   isolate->Dispose();
14191
14192   // Do this in a new isolate.
14193   isolate = v8::Isolate::New();
14194   isolate->Enter();
14195
14196   // Verify that we get callbacks for existing code objects when we
14197   // request enumeration of existing code.
14198   {
14199     v8::HandleScope scope(isolate);
14200     LocalContext env(isolate);
14201     CompileRun(script);
14202
14203     // Now get code through initial iteration.
14204     i::HashMap code(MatchPointers);
14205     code_map = &code;
14206
14207     i::HashMap lineinfo(MatchPointers);
14208     jitcode_line_info = &lineinfo;
14209
14210     V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14211     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14212
14213     jitcode_line_info = NULL;
14214     // We expect that we got some events. Note that if we could get code removal
14215     // notifications, we could compare two collections, one created by listening
14216     // from the time of creation of an isolate, and the other by subscribing
14217     // with EnumExisting.
14218     CHECK_LT(0, code.occupancy());
14219
14220     code_map = NULL;
14221   }
14222
14223   isolate->Exit();
14224   isolate->Dispose();
14225 }
14226
14227
14228 THREADED_TEST(ExternalAllocatedMemory) {
14229   v8::Isolate* isolate = CcTest::isolate();
14230   v8::HandleScope outer(isolate);
14231   v8::Local<Context> env(Context::New(isolate));
14232   CHECK(!env.IsEmpty());
14233   const int64_t kSize = 1024*1024;
14234   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14235   CHECK_EQ(baseline + kSize,
14236            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14237   CHECK_EQ(baseline,
14238            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14239 }
14240
14241
14242 // Regression test for issue 54, object templates with internal fields
14243 // but no accessors or interceptors did not get their internal field
14244 // count set on instances.
14245 THREADED_TEST(Regress54) {
14246   LocalContext context;
14247   v8::Isolate* isolate = context->GetIsolate();
14248   v8::HandleScope outer(isolate);
14249   static v8::Persistent<v8::ObjectTemplate> templ;
14250   if (templ.IsEmpty()) {
14251     v8::EscapableHandleScope inner(isolate);
14252     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14253     local->SetInternalFieldCount(1);
14254     templ.Reset(isolate, inner.Escape(local));
14255   }
14256   v8::Handle<v8::Object> result =
14257       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14258   CHECK_EQ(1, result->InternalFieldCount());
14259 }
14260
14261
14262 // If part of the threaded tests, this test makes ThreadingTest fail
14263 // on mac.
14264 TEST(CatchStackOverflow) {
14265   LocalContext context;
14266   v8::HandleScope scope(context->GetIsolate());
14267   v8::TryCatch try_catch;
14268   v8::Handle<v8::Value> result = CompileRun(
14269     "function f() {"
14270     "  return f();"
14271     "}"
14272     ""
14273     "f();");
14274   CHECK(result.IsEmpty());
14275 }
14276
14277
14278 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14279                                     const char* resource_name,
14280                                     int line_offset) {
14281   v8::HandleScope scope(CcTest::isolate());
14282   v8::TryCatch try_catch;
14283   v8::Handle<v8::Value> result = script->Run();
14284   CHECK(result.IsEmpty());
14285   CHECK(try_catch.HasCaught());
14286   v8::Handle<v8::Message> message = try_catch.Message();
14287   CHECK(!message.IsEmpty());
14288   CHECK_EQ(10 + line_offset, message->GetLineNumber());
14289   CHECK_EQ(91, message->GetStartPosition());
14290   CHECK_EQ(92, message->GetEndPosition());
14291   CHECK_EQ(2, message->GetStartColumn());
14292   CHECK_EQ(3, message->GetEndColumn());
14293   v8::String::Utf8Value line(message->GetSourceLine());
14294   CHECK_EQ("  throw 'nirk';", *line);
14295   v8::String::Utf8Value name(message->GetScriptResourceName());
14296   CHECK_EQ(resource_name, *name);
14297 }
14298
14299
14300 THREADED_TEST(TryCatchSourceInfo) {
14301   LocalContext context;
14302   v8::HandleScope scope(context->GetIsolate());
14303   v8::Local<v8::String> source = v8_str(
14304       "function Foo() {\n"
14305       "  return Bar();\n"
14306       "}\n"
14307       "\n"
14308       "function Bar() {\n"
14309       "  return Baz();\n"
14310       "}\n"
14311       "\n"
14312       "function Baz() {\n"
14313       "  throw 'nirk';\n"
14314       "}\n"
14315       "\n"
14316       "Foo();\n");
14317
14318   const char* resource_name;
14319   v8::Handle<v8::Script> script;
14320   resource_name = "test.js";
14321   script = CompileWithOrigin(source, resource_name);
14322   CheckTryCatchSourceInfo(script, resource_name, 0);
14323
14324   resource_name = "test1.js";
14325   v8::ScriptOrigin origin1(
14326       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14327   script = v8::Script::Compile(source, &origin1);
14328   CheckTryCatchSourceInfo(script, resource_name, 0);
14329
14330   resource_name = "test2.js";
14331   v8::ScriptOrigin origin2(
14332       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14333       v8::Integer::New(context->GetIsolate(), 7));
14334   script = v8::Script::Compile(source, &origin2);
14335   CheckTryCatchSourceInfo(script, resource_name, 7);
14336 }
14337
14338
14339 THREADED_TEST(CompilationCache) {
14340   LocalContext context;
14341   v8::HandleScope scope(context->GetIsolate());
14342   v8::Handle<v8::String> source0 =
14343       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14344   v8::Handle<v8::String> source1 =
14345       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14346   v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14347   v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14348   v8::Handle<v8::Script> script2 =
14349       v8::Script::Compile(source0);  // different origin
14350   CHECK_EQ(1234, script0->Run()->Int32Value());
14351   CHECK_EQ(1234, script1->Run()->Int32Value());
14352   CHECK_EQ(1234, script2->Run()->Int32Value());
14353 }
14354
14355
14356 static void FunctionNameCallback(
14357     const v8::FunctionCallbackInfo<v8::Value>& args) {
14358   ApiTestFuzzer::Fuzz();
14359   args.GetReturnValue().Set(v8_num(42));
14360 }
14361
14362
14363 THREADED_TEST(CallbackFunctionName) {
14364   LocalContext context;
14365   v8::Isolate* isolate = context->GetIsolate();
14366   v8::HandleScope scope(isolate);
14367   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14368   t->Set(v8_str("asdf"),
14369          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14370   context->Global()->Set(v8_str("obj"), t->NewInstance());
14371   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14372   CHECK(value->IsString());
14373   v8::String::Utf8Value name(value);
14374   CHECK_EQ("asdf", *name);
14375 }
14376
14377
14378 THREADED_TEST(DateAccess) {
14379   LocalContext context;
14380   v8::HandleScope scope(context->GetIsolate());
14381   v8::Handle<v8::Value> date =
14382       v8::Date::New(context->GetIsolate(), 1224744689038.0);
14383   CHECK(date->IsDate());
14384   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14385 }
14386
14387
14388 void CheckProperties(v8::Isolate* isolate,
14389                      v8::Handle<v8::Value> val,
14390                      int elmc,
14391                      const char* elmv[]) {
14392   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14393   v8::Handle<v8::Array> props = obj->GetPropertyNames();
14394   CHECK_EQ(elmc, props->Length());
14395   for (int i = 0; i < elmc; i++) {
14396     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14397     CHECK_EQ(elmv[i], *elm);
14398   }
14399 }
14400
14401
14402 void CheckOwnProperties(v8::Isolate* isolate,
14403                         v8::Handle<v8::Value> val,
14404                         int elmc,
14405                         const char* elmv[]) {
14406   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14407   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14408   CHECK_EQ(elmc, props->Length());
14409   for (int i = 0; i < elmc; i++) {
14410     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14411     CHECK_EQ(elmv[i], *elm);
14412   }
14413 }
14414
14415
14416 THREADED_TEST(PropertyEnumeration) {
14417   LocalContext context;
14418   v8::Isolate* isolate = context->GetIsolate();
14419   v8::HandleScope scope(isolate);
14420   v8::Handle<v8::Value> obj = CompileRun(
14421       "var result = [];"
14422       "result[0] = {};"
14423       "result[1] = {a: 1, b: 2};"
14424       "result[2] = [1, 2, 3];"
14425       "var proto = {x: 1, y: 2, z: 3};"
14426       "var x = { __proto__: proto, w: 0, z: 1 };"
14427       "result[3] = x;"
14428       "result;");
14429   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14430   CHECK_EQ(4, elms->Length());
14431   int elmc0 = 0;
14432   const char** elmv0 = NULL;
14433   CheckProperties(
14434       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14435   CheckOwnProperties(
14436       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14437   int elmc1 = 2;
14438   const char* elmv1[] = {"a", "b"};
14439   CheckProperties(
14440       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14441   CheckOwnProperties(
14442       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14443   int elmc2 = 3;
14444   const char* elmv2[] = {"0", "1", "2"};
14445   CheckProperties(
14446       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14447   CheckOwnProperties(
14448       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14449   int elmc3 = 4;
14450   const char* elmv3[] = {"w", "z", "x", "y"};
14451   CheckProperties(
14452       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14453   int elmc4 = 2;
14454   const char* elmv4[] = {"w", "z"};
14455   CheckOwnProperties(
14456       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14457 }
14458
14459
14460 THREADED_TEST(PropertyEnumeration2) {
14461   LocalContext context;
14462   v8::Isolate* isolate = context->GetIsolate();
14463   v8::HandleScope scope(isolate);
14464   v8::Handle<v8::Value> obj = CompileRun(
14465       "var result = [];"
14466       "result[0] = {};"
14467       "result[1] = {a: 1, b: 2};"
14468       "result[2] = [1, 2, 3];"
14469       "var proto = {x: 1, y: 2, z: 3};"
14470       "var x = { __proto__: proto, w: 0, z: 1 };"
14471       "result[3] = x;"
14472       "result;");
14473   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14474   CHECK_EQ(4, elms->Length());
14475   int elmc0 = 0;
14476   const char** elmv0 = NULL;
14477   CheckProperties(isolate,
14478                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14479
14480   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14481   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14482   CHECK_EQ(0, props->Length());
14483   for (uint32_t i = 0; i < props->Length(); i++) {
14484     printf("p[%d]\n", i);
14485   }
14486 }
14487
14488 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14489                                   Local<Value> name,
14490                                   v8::AccessType type,
14491                                   Local<Value> data) {
14492   return type != v8::ACCESS_SET;
14493 }
14494
14495
14496 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14497                                     uint32_t key,
14498                                     v8::AccessType type,
14499                                     Local<Value> data) {
14500   return type != v8::ACCESS_SET;
14501 }
14502
14503
14504 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14505   LocalContext context;
14506   v8::Isolate* isolate = context->GetIsolate();
14507   v8::HandleScope scope(isolate);
14508   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14509   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14510                                  IndexedSetAccessBlocker);
14511   templ->Set(v8_str("x"), v8::True(isolate));
14512   Local<v8::Object> instance = templ->NewInstance();
14513   context->Global()->Set(v8_str("obj"), instance);
14514   Local<Value> value = CompileRun("obj.x");
14515   CHECK(value->BooleanValue());
14516 }
14517
14518
14519 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14520                                   Local<Value> name,
14521                                   v8::AccessType type,
14522                                   Local<Value> data) {
14523   return false;
14524 }
14525
14526
14527 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14528                                     uint32_t key,
14529                                     v8::AccessType type,
14530                                     Local<Value> data) {
14531   return false;
14532 }
14533
14534
14535
14536 THREADED_TEST(AccessChecksReenabledCorrectly) {
14537   LocalContext context;
14538   v8::Isolate* isolate = context->GetIsolate();
14539   v8::HandleScope scope(isolate);
14540   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14541   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14542                                  IndexedGetAccessBlocker);
14543   templ->Set(v8_str("a"), v8_str("a"));
14544   // Add more than 8 (see kMaxFastProperties) properties
14545   // so that the constructor will force copying map.
14546   // Cannot sprintf, gcc complains unsafety.
14547   char buf[4];
14548   for (char i = '0'; i <= '9' ; i++) {
14549     buf[0] = i;
14550     for (char j = '0'; j <= '9'; j++) {
14551       buf[1] = j;
14552       for (char k = '0'; k <= '9'; k++) {
14553         buf[2] = k;
14554         buf[3] = 0;
14555         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14556       }
14557     }
14558   }
14559
14560   Local<v8::Object> instance_1 = templ->NewInstance();
14561   context->Global()->Set(v8_str("obj_1"), instance_1);
14562
14563   Local<Value> value_1 = CompileRun("obj_1.a");
14564   CHECK(value_1->IsUndefined());
14565
14566   Local<v8::Object> instance_2 = templ->NewInstance();
14567   context->Global()->Set(v8_str("obj_2"), instance_2);
14568
14569   Local<Value> value_2 = CompileRun("obj_2.a");
14570   CHECK(value_2->IsUndefined());
14571 }
14572
14573
14574 // This tests that access check information remains on the global
14575 // object template when creating contexts.
14576 THREADED_TEST(AccessControlRepeatedContextCreation) {
14577   v8::Isolate* isolate = CcTest::isolate();
14578   v8::HandleScope handle_scope(isolate);
14579   v8::Handle<v8::ObjectTemplate> global_template =
14580       v8::ObjectTemplate::New(isolate);
14581   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14582                                            IndexedSetAccessBlocker);
14583   i::Handle<i::ObjectTemplateInfo> internal_template =
14584       v8::Utils::OpenHandle(*global_template);
14585   CHECK(!internal_template->constructor()->IsUndefined());
14586   i::Handle<i::FunctionTemplateInfo> constructor(
14587       i::FunctionTemplateInfo::cast(internal_template->constructor()));
14588   CHECK(!constructor->access_check_info()->IsUndefined());
14589   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14590   CHECK(!context0.IsEmpty());
14591   CHECK(!constructor->access_check_info()->IsUndefined());
14592 }
14593
14594
14595 THREADED_TEST(TurnOnAccessCheck) {
14596   v8::Isolate* isolate = CcTest::isolate();
14597   v8::HandleScope handle_scope(isolate);
14598
14599   // Create an environment with access check to the global object disabled by
14600   // default.
14601   v8::Handle<v8::ObjectTemplate> global_template =
14602       v8::ObjectTemplate::New(isolate);
14603   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14604                                            IndexedGetAccessBlocker,
14605                                            v8::Handle<v8::Value>(),
14606                                            false);
14607   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14608   Context::Scope context_scope(context);
14609
14610   // Set up a property and a number of functions.
14611   context->Global()->Set(v8_str("a"), v8_num(1));
14612   CompileRun("function f1() {return a;}"
14613              "function f2() {return a;}"
14614              "function g1() {return h();}"
14615              "function g2() {return h();}"
14616              "function h() {return 1;}");
14617   Local<Function> f1 =
14618       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14619   Local<Function> f2 =
14620       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14621   Local<Function> g1 =
14622       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14623   Local<Function> g2 =
14624       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14625   Local<Function> h =
14626       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14627
14628   // Get the global object.
14629   v8::Handle<v8::Object> global = context->Global();
14630
14631   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14632   // uses the runtime system to retreive property a whereas f2 uses global load
14633   // inline cache.
14634   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14635   for (int i = 0; i < 4; i++) {
14636     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14637   }
14638
14639   // Same for g1 and g2.
14640   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14641   for (int i = 0; i < 4; i++) {
14642     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14643   }
14644
14645   // Detach the global and turn on access check.
14646   Local<Object> hidden_global = Local<Object>::Cast(
14647       context->Global()->GetPrototype());
14648   context->DetachGlobal();
14649   hidden_global->TurnOnAccessCheck();
14650
14651   // Failing access check to property get results in undefined.
14652   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14653   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14654
14655   // Failing access check to function call results in exception.
14656   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14657   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14658
14659   // No failing access check when just returning a constant.
14660   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14661 }
14662
14663
14664 static const char* kPropertyA = "a";
14665 static const char* kPropertyH = "h";
14666
14667 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14668                                        Local<Value> name,
14669                                        v8::AccessType type,
14670                                        Local<Value> data) {
14671   if (!name->IsString()) return false;
14672   i::Handle<i::String> name_handle =
14673       v8::Utils::OpenHandle(String::Cast(*name));
14674   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14675       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14676 }
14677
14678
14679 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14680   v8::Isolate* isolate = CcTest::isolate();
14681   v8::HandleScope handle_scope(isolate);
14682
14683   // Create an environment with access check to the global object disabled by
14684   // default. When the registered access checker will block access to properties
14685   // a and h.
14686   v8::Handle<v8::ObjectTemplate> global_template =
14687      v8::ObjectTemplate::New(isolate);
14688   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14689                                            IndexedGetAccessBlocker,
14690                                            v8::Handle<v8::Value>(),
14691                                            false);
14692   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14693   Context::Scope context_scope(context);
14694
14695   // Set up a property and a number of functions.
14696   context->Global()->Set(v8_str("a"), v8_num(1));
14697   static const char* source = "function f1() {return a;}"
14698                               "function f2() {return a;}"
14699                               "function g1() {return h();}"
14700                               "function g2() {return h();}"
14701                               "function h() {return 1;}";
14702
14703   CompileRun(source);
14704   Local<Function> f1;
14705   Local<Function> f2;
14706   Local<Function> g1;
14707   Local<Function> g2;
14708   Local<Function> h;
14709   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14710   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14711   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14712   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14713   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14714
14715   // Get the global object.
14716   v8::Handle<v8::Object> global = context->Global();
14717
14718   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14719   // uses the runtime system to retreive property a whereas f2 uses global load
14720   // inline cache.
14721   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14722   for (int i = 0; i < 4; i++) {
14723     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14724   }
14725
14726   // Same for g1 and g2.
14727   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14728   for (int i = 0; i < 4; i++) {
14729     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14730   }
14731
14732   // Detach the global and turn on access check now blocking access to property
14733   // a and function h.
14734   Local<Object> hidden_global = Local<Object>::Cast(
14735       context->Global()->GetPrototype());
14736   context->DetachGlobal();
14737   hidden_global->TurnOnAccessCheck();
14738
14739   // Failing access check to property get results in undefined.
14740   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14741   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14742
14743   // Failing access check to function call results in exception.
14744   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14745   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14746
14747   // No failing access check when just returning a constant.
14748   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14749
14750   // Now compile the source again. And get the newly compiled functions, except
14751   // for h for which access is blocked.
14752   CompileRun(source);
14753   f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14754   f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14755   g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14756   g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14757   CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
14758
14759   // Failing access check to property get results in undefined.
14760   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14761   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14762
14763   // Failing access check to function call results in exception.
14764   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14765   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14766 }
14767
14768
14769 // This test verifies that pre-compilation (aka preparsing) can be called
14770 // without initializing the whole VM. Thus we cannot run this test in a
14771 // multi-threaded setup.
14772 TEST(PreCompile) {
14773   // TODO(155): This test would break without the initialization of V8. This is
14774   // a workaround for now to make this test not fail.
14775   v8::V8::Initialize();
14776   v8::Isolate* isolate = CcTest::isolate();
14777   HandleScope handle_scope(isolate);
14778   const char* script = "function foo(a) { return a+1; }";
14779   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14780       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14781   CHECK_NE(sd->Length(), 0);
14782   CHECK_NE(sd->Data(), NULL);
14783   CHECK(!sd->HasError());
14784   delete sd;
14785 }
14786
14787
14788 TEST(PreCompileWithError) {
14789   v8::V8::Initialize();
14790   v8::Isolate* isolate = CcTest::isolate();
14791   HandleScope handle_scope(isolate);
14792   const char* script = "function foo(a) { return 1 * * 2; }";
14793   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14794       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14795   CHECK(sd->HasError());
14796   delete sd;
14797 }
14798
14799
14800 TEST(Regress31661) {
14801   v8::V8::Initialize();
14802   v8::Isolate* isolate = CcTest::isolate();
14803   HandleScope handle_scope(isolate);
14804   const char* script = " The Definintive Guide";
14805   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14806       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14807   CHECK(sd->HasError());
14808   delete sd;
14809 }
14810
14811
14812 // Tests that ScriptData can be serialized and deserialized.
14813 TEST(PreCompileSerialization) {
14814   v8::V8::Initialize();
14815   v8::Isolate* isolate = CcTest::isolate();
14816   HandleScope handle_scope(isolate);
14817   const char* script = "function foo(a) { return a+1; }";
14818   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14819       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14820
14821   // Serialize.
14822   int serialized_data_length = sd->Length();
14823   char* serialized_data = i::NewArray<char>(serialized_data_length);
14824   i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
14825
14826   // Deserialize.
14827   v8::ScriptData* deserialized_sd =
14828       v8::ScriptData::New(serialized_data, serialized_data_length);
14829
14830   // Verify that the original is the same as the deserialized.
14831   CHECK_EQ(sd->Length(), deserialized_sd->Length());
14832   CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
14833   CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
14834
14835   delete sd;
14836   delete deserialized_sd;
14837   i::DeleteArray(serialized_data);
14838 }
14839
14840
14841 // Attempts to deserialize bad data.
14842 TEST(PreCompileDeserializationError) {
14843   v8::V8::Initialize();
14844   const char* data = "DONT CARE";
14845   int invalid_size = 3;
14846   v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
14847
14848   CHECK_EQ(0, sd->Length());
14849
14850   delete sd;
14851 }
14852
14853
14854 // Attempts to deserialize bad data.
14855 TEST(PreCompileInvalidPreparseDataError) {
14856   v8::V8::Initialize();
14857   v8::Isolate* isolate = CcTest::isolate();
14858   LocalContext context;
14859   v8::HandleScope scope(context->GetIsolate());
14860
14861   const char* script = "function foo(){ return 5;}\n"
14862       "function bar(){ return 6 + 7;}  foo();";
14863   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14864       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14865   CHECK(!sd->HasError());
14866   // ScriptDataImpl private implementation details
14867   const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14868   const int kFunctionEntrySize = i::FunctionEntry::kSize;
14869   const int kFunctionEntryStartOffset = 0;
14870   const int kFunctionEntryEndOffset = 1;
14871   unsigned* sd_data =
14872       reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14873
14874   // Overwrite function bar's end position with 0.
14875   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14876   v8::TryCatch try_catch;
14877
14878   v8::ScriptCompiler::Source script_source(
14879       String::NewFromUtf8(isolate, script),
14880       new v8::ScriptCompiler::CachedData(
14881           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
14882   Local<v8::UnboundScript> compiled_script =
14883       v8::ScriptCompiler::CompileUnbound(isolate, &script_source);
14884
14885   CHECK(try_catch.HasCaught());
14886   String::Utf8Value exception_value(try_catch.Message()->Get());
14887   CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
14888            *exception_value);
14889
14890   try_catch.Reset();
14891   delete sd;
14892
14893   // Overwrite function bar's start position with 200.  The function entry
14894   // will not be found when searching for it by position and we should fall
14895   // back on eager compilation.
14896   sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14897       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14898   sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14899   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
14900       200;
14901   v8::ScriptCompiler::Source script_source2(
14902       String::NewFromUtf8(isolate, script),
14903       new v8::ScriptCompiler::CachedData(
14904           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
14905   compiled_script =
14906       v8::ScriptCompiler::CompileUnbound(isolate, &script_source2);
14907   CHECK(!try_catch.HasCaught());
14908
14909   delete sd;
14910 }
14911
14912
14913 // This tests that we do not allow dictionary load/call inline caches
14914 // to use functions that have not yet been compiled.  The potential
14915 // problem of loading a function that has not yet been compiled can
14916 // arise because we share code between contexts via the compilation
14917 // cache.
14918 THREADED_TEST(DictionaryICLoadedFunction) {
14919   v8::HandleScope scope(CcTest::isolate());
14920   // Test LoadIC.
14921   for (int i = 0; i < 2; i++) {
14922     LocalContext context;
14923     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14924     context->Global()->Delete(v8_str("tmp"));
14925     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14926   }
14927   // Test CallIC.
14928   for (int i = 0; i < 2; i++) {
14929     LocalContext context;
14930     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14931     context->Global()->Delete(v8_str("tmp"));
14932     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14933   }
14934 }
14935
14936
14937 // Test that cross-context new calls use the context of the callee to
14938 // create the new JavaScript object.
14939 THREADED_TEST(CrossContextNew) {
14940   v8::Isolate* isolate = CcTest::isolate();
14941   v8::HandleScope scope(isolate);
14942   v8::Local<Context> context0 = Context::New(isolate);
14943   v8::Local<Context> context1 = Context::New(isolate);
14944
14945   // Allow cross-domain access.
14946   Local<String> token = v8_str("<security token>");
14947   context0->SetSecurityToken(token);
14948   context1->SetSecurityToken(token);
14949
14950   // Set an 'x' property on the Object prototype and define a
14951   // constructor function in context0.
14952   context0->Enter();
14953   CompileRun("Object.prototype.x = 42; function C() {};");
14954   context0->Exit();
14955
14956   // Call the constructor function from context0 and check that the
14957   // result has the 'x' property.
14958   context1->Enter();
14959   context1->Global()->Set(v8_str("other"), context0->Global());
14960   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14961   CHECK(value->IsInt32());
14962   CHECK_EQ(42, value->Int32Value());
14963   context1->Exit();
14964 }
14965
14966
14967 // Verify that we can clone an object
14968 TEST(ObjectClone) {
14969   LocalContext env;
14970   v8::Isolate* isolate = env->GetIsolate();
14971   v8::HandleScope scope(isolate);
14972
14973   const char* sample =
14974     "var rv = {};"      \
14975     "rv.alpha = 'hello';" \
14976     "rv.beta = 123;"     \
14977     "rv;";
14978
14979   // Create an object, verify basics.
14980   Local<Value> val = CompileRun(sample);
14981   CHECK(val->IsObject());
14982   Local<v8::Object> obj = val.As<v8::Object>();
14983   obj->Set(v8_str("gamma"), v8_str("cloneme"));
14984
14985   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
14986   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
14987   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
14988
14989   // Clone it.
14990   Local<v8::Object> clone = obj->Clone();
14991   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
14992   CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
14993   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
14994
14995   // Set a property on the clone, verify each object.
14996   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
14997   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
14998   CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
14999 }
15000
15001
15002 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
15003  public:
15004   explicit AsciiVectorResource(i::Vector<const char> vector)
15005       : data_(vector) {}
15006   virtual ~AsciiVectorResource() {}
15007   virtual size_t length() const { return data_.length(); }
15008   virtual const char* data() const { return data_.start(); }
15009  private:
15010   i::Vector<const char> data_;
15011 };
15012
15013
15014 class UC16VectorResource : public v8::String::ExternalStringResource {
15015  public:
15016   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15017       : data_(vector) {}
15018   virtual ~UC16VectorResource() {}
15019   virtual size_t length() const { return data_.length(); }
15020   virtual const i::uc16* data() const { return data_.start(); }
15021  private:
15022   i::Vector<const i::uc16> data_;
15023 };
15024
15025
15026 static void MorphAString(i::String* string,
15027                          AsciiVectorResource* ascii_resource,
15028                          UC16VectorResource* uc16_resource) {
15029   CHECK(i::StringShape(string).IsExternal());
15030   if (string->IsOneByteRepresentation()) {
15031     // Check old map is not internalized or long.
15032     CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15033     // Morph external string to be TwoByte string.
15034     string->set_map(CcTest::heap()->external_string_map());
15035     i::ExternalTwoByteString* morphed =
15036          i::ExternalTwoByteString::cast(string);
15037     morphed->set_resource(uc16_resource);
15038   } else {
15039     // Check old map is not internalized or long.
15040     CHECK(string->map() == CcTest::heap()->external_string_map());
15041     // Morph external string to be ASCII string.
15042     string->set_map(CcTest::heap()->external_ascii_string_map());
15043     i::ExternalAsciiString* morphed =
15044          i::ExternalAsciiString::cast(string);
15045     morphed->set_resource(ascii_resource);
15046   }
15047 }
15048
15049
15050 // Test that we can still flatten a string if the components it is built up
15051 // from have been turned into 16 bit strings in the mean time.
15052 THREADED_TEST(MorphCompositeStringTest) {
15053   char utf_buffer[129];
15054   const char* c_string = "Now is the time for all good men"
15055                          " to come to the aid of the party";
15056   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15057   {
15058     LocalContext env;
15059     i::Factory* factory = CcTest::i_isolate()->factory();
15060     v8::HandleScope scope(env->GetIsolate());
15061     AsciiVectorResource ascii_resource(
15062         i::Vector<const char>(c_string, i::StrLength(c_string)));
15063     UC16VectorResource uc16_resource(
15064         i::Vector<const uint16_t>(two_byte_string,
15065                                   i::StrLength(c_string)));
15066
15067     Local<String> lhs(v8::Utils::ToLocal(
15068         factory->NewExternalStringFromAscii(&ascii_resource)));
15069     Local<String> rhs(v8::Utils::ToLocal(
15070         factory->NewExternalStringFromAscii(&ascii_resource)));
15071
15072     env->Global()->Set(v8_str("lhs"), lhs);
15073     env->Global()->Set(v8_str("rhs"), rhs);
15074
15075     CompileRun(
15076         "var cons = lhs + rhs;"
15077         "var slice = lhs.substring(1, lhs.length - 1);"
15078         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15079
15080     CHECK(lhs->IsOneByte());
15081     CHECK(rhs->IsOneByte());
15082
15083     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15084     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15085
15086     // This should UTF-8 without flattening, since everything is ASCII.
15087     Handle<String> cons = v8_compile("cons")->Run().As<String>();
15088     CHECK_EQ(128, cons->Utf8Length());
15089     int nchars = -1;
15090     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15091     CHECK_EQ(128, nchars);
15092     CHECK_EQ(0, strcmp(
15093         utf_buffer,
15094         "Now is the time for all good men to come to the aid of the party"
15095         "Now is the time for all good men to come to the aid of the party"));
15096
15097     // Now do some stuff to make sure the strings are flattened, etc.
15098     CompileRun(
15099         "/[^a-z]/.test(cons);"
15100         "/[^a-z]/.test(slice);"
15101         "/[^a-z]/.test(slice_on_cons);");
15102     const char* expected_cons =
15103         "Now is the time for all good men to come to the aid of the party"
15104         "Now is the time for all good men to come to the aid of the party";
15105     const char* expected_slice =
15106         "ow is the time for all good men to come to the aid of the part";
15107     const char* expected_slice_on_cons =
15108         "ow is the time for all good men to come to the aid of the party"
15109         "Now is the time for all good men to come to the aid of the part";
15110     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15111              env->Global()->Get(v8_str("cons")));
15112     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15113              env->Global()->Get(v8_str("slice")));
15114     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15115              env->Global()->Get(v8_str("slice_on_cons")));
15116   }
15117   i::DeleteArray(two_byte_string);
15118 }
15119
15120
15121 TEST(CompileExternalTwoByteSource) {
15122   LocalContext context;
15123   v8::HandleScope scope(context->GetIsolate());
15124
15125   // This is a very short list of sources, which currently is to check for a
15126   // regression caused by r2703.
15127   const char* ascii_sources[] = {
15128     "0.5",
15129     "-0.5",   // This mainly testes PushBack in the Scanner.
15130     "--0.5",  // This mainly testes PushBack in the Scanner.
15131     NULL
15132   };
15133
15134   // Compile the sources as external two byte strings.
15135   for (int i = 0; ascii_sources[i] != NULL; i++) {
15136     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15137     TestResource* uc16_resource = new TestResource(two_byte_string);
15138     v8::Local<v8::String> source =
15139         v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15140     v8::Script::Compile(source);
15141   }
15142 }
15143
15144
15145 #ifndef V8_INTERPRETED_REGEXP
15146
15147 struct RegExpInterruptionData {
15148   int loop_count;
15149   UC16VectorResource* string_resource;
15150   v8::Persistent<v8::String> string;
15151 } regexp_interruption_data;
15152
15153
15154 class RegExpInterruptionThread : public i::Thread {
15155  public:
15156   explicit RegExpInterruptionThread(v8::Isolate* isolate)
15157       : Thread("TimeoutThread"), isolate_(isolate) {}
15158
15159   virtual void Run() {
15160     for (regexp_interruption_data.loop_count = 0;
15161          regexp_interruption_data.loop_count < 7;
15162          regexp_interruption_data.loop_count++) {
15163       i::OS::Sleep(50);  // Wait a bit before requesting GC.
15164       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15165     }
15166     i::OS::Sleep(50);  // Wait a bit before terminating.
15167     v8::V8::TerminateExecution(isolate_);
15168   }
15169
15170  private:
15171   v8::Isolate* isolate_;
15172 };
15173
15174
15175 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15176   if (regexp_interruption_data.loop_count != 2) return;
15177   v8::HandleScope scope(CcTest::isolate());
15178   v8::Local<v8::String> string = v8::Local<v8::String>::New(
15179       CcTest::isolate(), regexp_interruption_data.string);
15180   string->MakeExternal(regexp_interruption_data.string_resource);
15181 }
15182
15183
15184 // Test that RegExp execution can be interrupted.  Specifically, we test
15185 // * interrupting with GC
15186 // * turn the subject string from one-byte internal to two-byte external string
15187 // * force termination
15188 TEST(RegExpInterruption) {
15189   v8::HandleScope scope(CcTest::isolate());
15190   LocalContext env;
15191
15192   RegExpInterruptionThread timeout_thread(CcTest::isolate());
15193
15194   v8::V8::AddGCPrologueCallback(RunBeforeGC);
15195   static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15196   i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15197   v8::Local<v8::String> string = v8_str(ascii_content);
15198
15199   CcTest::global()->Set(v8_str("a"), string);
15200   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15201   regexp_interruption_data.string_resource = new UC16VectorResource(
15202       i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15203
15204   v8::TryCatch try_catch;
15205   timeout_thread.Start();
15206
15207   CompileRun("/((a*)*)*b/.exec(a)");
15208   CHECK(try_catch.HasTerminated());
15209
15210   timeout_thread.Join();
15211
15212   regexp_interruption_data.string.Reset();
15213   i::DeleteArray(uc16_content);
15214 }
15215
15216 #endif  // V8_INTERPRETED_REGEXP
15217
15218
15219 // Test that we cannot set a property on the global object if there
15220 // is a read-only property in the prototype chain.
15221 TEST(ReadOnlyPropertyInGlobalProto) {
15222   v8::Isolate* isolate = CcTest::isolate();
15223   v8::HandleScope scope(isolate);
15224   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15225   LocalContext context(0, templ);
15226   v8::Handle<v8::Object> global = context->Global();
15227   v8::Handle<v8::Object> global_proto =
15228       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15229   global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15230   global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15231   // Check without 'eval' or 'with'.
15232   v8::Handle<v8::Value> res =
15233       CompileRun("function f() { x = 42; return x; }; f()");
15234   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15235   // Check with 'eval'.
15236   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15237   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15238   // Check with 'with'.
15239   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15240   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15241 }
15242
15243 static int force_set_set_count = 0;
15244 static int force_set_get_count = 0;
15245 bool pass_on_get = false;
15246
15247 static void ForceSetGetter(v8::Local<v8::String> name,
15248                            const v8::PropertyCallbackInfo<v8::Value>& info) {
15249   force_set_get_count++;
15250   if (pass_on_get) {
15251     return;
15252   }
15253   info.GetReturnValue().Set(3);
15254 }
15255
15256 static void ForceSetSetter(v8::Local<v8::String> name,
15257                            v8::Local<v8::Value> value,
15258                            const v8::PropertyCallbackInfo<void>& info) {
15259   force_set_set_count++;
15260 }
15261
15262 static void ForceSetInterceptSetter(
15263     v8::Local<v8::String> name,
15264     v8::Local<v8::Value> value,
15265     const v8::PropertyCallbackInfo<v8::Value>& info) {
15266   force_set_set_count++;
15267   info.GetReturnValue().SetUndefined();
15268 }
15269
15270
15271 TEST(ForceSet) {
15272   force_set_get_count = 0;
15273   force_set_set_count = 0;
15274   pass_on_get = false;
15275
15276   v8::Isolate* isolate = CcTest::isolate();
15277   v8::HandleScope scope(isolate);
15278   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15279   v8::Handle<v8::String> access_property =
15280       v8::String::NewFromUtf8(isolate, "a");
15281   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15282   LocalContext context(NULL, templ);
15283   v8::Handle<v8::Object> global = context->Global();
15284
15285   // Ordinary properties
15286   v8::Handle<v8::String> simple_property =
15287       v8::String::NewFromUtf8(isolate, "p");
15288   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15289   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15290   // This should fail because the property is read-only
15291   global->Set(simple_property, v8::Int32::New(isolate, 5));
15292   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15293   // This should succeed even though the property is read-only
15294   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15295   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15296
15297   // Accessors
15298   CHECK_EQ(0, force_set_set_count);
15299   CHECK_EQ(0, force_set_get_count);
15300   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15301   // CHECK_EQ the property shouldn't override it, just call the setter
15302   // which in this case does nothing.
15303   global->Set(access_property, v8::Int32::New(isolate, 7));
15304   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15305   CHECK_EQ(1, force_set_set_count);
15306   CHECK_EQ(2, force_set_get_count);
15307   // Forcing the property to be set should override the accessor without
15308   // calling it
15309   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15310   CHECK_EQ(8, global->Get(access_property)->Int32Value());
15311   CHECK_EQ(1, force_set_set_count);
15312   CHECK_EQ(2, force_set_get_count);
15313 }
15314
15315
15316 TEST(ForceSetWithInterceptor) {
15317   force_set_get_count = 0;
15318   force_set_set_count = 0;
15319   pass_on_get = false;
15320
15321   v8::Isolate* isolate = CcTest::isolate();
15322   v8::HandleScope scope(isolate);
15323   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15324   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15325   LocalContext context(NULL, templ);
15326   v8::Handle<v8::Object> global = context->Global();
15327
15328   v8::Handle<v8::String> some_property =
15329       v8::String::NewFromUtf8(isolate, "a");
15330   CHECK_EQ(0, force_set_set_count);
15331   CHECK_EQ(0, force_set_get_count);
15332   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15333   // Setting the property shouldn't override it, just call the setter
15334   // which in this case does nothing.
15335   global->Set(some_property, v8::Int32::New(isolate, 7));
15336   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15337   CHECK_EQ(1, force_set_set_count);
15338   CHECK_EQ(2, force_set_get_count);
15339   // Getting the property when the interceptor returns an empty handle
15340   // should yield undefined, since the property isn't present on the
15341   // object itself yet.
15342   pass_on_get = true;
15343   CHECK(global->Get(some_property)->IsUndefined());
15344   CHECK_EQ(1, force_set_set_count);
15345   CHECK_EQ(3, force_set_get_count);
15346   // Forcing the property to be set should cause the value to be
15347   // set locally without calling the interceptor.
15348   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15349   CHECK_EQ(8, global->Get(some_property)->Int32Value());
15350   CHECK_EQ(1, force_set_set_count);
15351   CHECK_EQ(4, force_set_get_count);
15352   // Reenabling the interceptor should cause it to take precedence over
15353   // the property
15354   pass_on_get = false;
15355   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15356   CHECK_EQ(1, force_set_set_count);
15357   CHECK_EQ(5, force_set_get_count);
15358   // The interceptor should also work for other properties
15359   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15360                   ->Int32Value());
15361   CHECK_EQ(1, force_set_set_count);
15362   CHECK_EQ(6, force_set_get_count);
15363 }
15364
15365
15366 THREADED_TEST(ForceDelete) {
15367   v8::Isolate* isolate = CcTest::isolate();
15368   v8::HandleScope scope(isolate);
15369   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15370   LocalContext context(NULL, templ);
15371   v8::Handle<v8::Object> global = context->Global();
15372
15373   // Ordinary properties
15374   v8::Handle<v8::String> simple_property =
15375       v8::String::NewFromUtf8(isolate, "p");
15376   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15377   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15378   // This should fail because the property is dont-delete.
15379   CHECK(!global->Delete(simple_property));
15380   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15381   // This should succeed even though the property is dont-delete.
15382   CHECK(global->ForceDelete(simple_property));
15383   CHECK(global->Get(simple_property)->IsUndefined());
15384 }
15385
15386
15387 static int force_delete_interceptor_count = 0;
15388 static bool pass_on_delete = false;
15389
15390
15391 static void ForceDeleteDeleter(
15392     v8::Local<v8::String> name,
15393     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15394   force_delete_interceptor_count++;
15395   if (pass_on_delete) return;
15396   info.GetReturnValue().Set(true);
15397 }
15398
15399
15400 THREADED_TEST(ForceDeleteWithInterceptor) {
15401   force_delete_interceptor_count = 0;
15402   pass_on_delete = false;
15403
15404   v8::Isolate* isolate = CcTest::isolate();
15405   v8::HandleScope scope(isolate);
15406   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15407   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15408   LocalContext context(NULL, templ);
15409   v8::Handle<v8::Object> global = context->Global();
15410
15411   v8::Handle<v8::String> some_property =
15412       v8::String::NewFromUtf8(isolate, "a");
15413   global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete);
15414
15415   // Deleting a property should get intercepted and nothing should
15416   // happen.
15417   CHECK_EQ(0, force_delete_interceptor_count);
15418   CHECK(global->Delete(some_property));
15419   CHECK_EQ(1, force_delete_interceptor_count);
15420   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15421   // Deleting the property when the interceptor returns an empty
15422   // handle should not delete the property since it is DontDelete.
15423   pass_on_delete = true;
15424   CHECK(!global->Delete(some_property));
15425   CHECK_EQ(2, force_delete_interceptor_count);
15426   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15427   // Forcing the property to be deleted should delete the value
15428   // without calling the interceptor.
15429   CHECK(global->ForceDelete(some_property));
15430   CHECK(global->Get(some_property)->IsUndefined());
15431   CHECK_EQ(2, force_delete_interceptor_count);
15432 }
15433
15434
15435 // Make sure that forcing a delete invalidates any IC stubs, so we
15436 // don't read the hole value.
15437 THREADED_TEST(ForceDeleteIC) {
15438   LocalContext context;
15439   v8::HandleScope scope(context->GetIsolate());
15440   // Create a DontDelete variable on the global object.
15441   CompileRun("this.__proto__ = { foo: 'horse' };"
15442              "var foo = 'fish';"
15443              "function f() { return foo.length; }");
15444   // Initialize the IC for foo in f.
15445   CompileRun("for (var i = 0; i < 4; i++) f();");
15446   // Make sure the value of foo is correct before the deletion.
15447   CHECK_EQ(4, CompileRun("f()")->Int32Value());
15448   // Force the deletion of foo.
15449   CHECK(context->Global()->ForceDelete(v8_str("foo")));
15450   // Make sure the value for foo is read from the prototype, and that
15451   // we don't get in trouble with reading the deleted cell value
15452   // sentinel.
15453   CHECK_EQ(5, CompileRun("f()")->Int32Value());
15454 }
15455
15456
15457 TEST(InlinedFunctionAcrossContexts) {
15458   i::FLAG_allow_natives_syntax = true;
15459   v8::Isolate* isolate = CcTest::isolate();
15460   v8::HandleScope outer_scope(isolate);
15461   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15462   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15463   ctx1->Enter();
15464
15465   {
15466     v8::HandleScope inner_scope(CcTest::isolate());
15467     CompileRun("var G = 42; function foo() { return G; }");
15468     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15469     ctx2->Enter();
15470     ctx2->Global()->Set(v8_str("o"), foo);
15471     v8::Local<v8::Value> res = CompileRun(
15472         "function f() { return o(); }"
15473         "for (var i = 0; i < 10; ++i) f();"
15474         "%OptimizeFunctionOnNextCall(f);"
15475         "f();");
15476     CHECK_EQ(42, res->Int32Value());
15477     ctx2->Exit();
15478     v8::Handle<v8::String> G_property =
15479         v8::String::NewFromUtf8(CcTest::isolate(), "G");
15480     CHECK(ctx1->Global()->ForceDelete(G_property));
15481     ctx2->Enter();
15482     ExpectString(
15483         "(function() {"
15484         "  try {"
15485         "    return f();"
15486         "  } catch(e) {"
15487         "    return e.toString();"
15488         "  }"
15489         " })()",
15490         "ReferenceError: G is not defined");
15491     ctx2->Exit();
15492     ctx1->Exit();
15493   }
15494 }
15495
15496
15497 static v8::Local<Context> calling_context0;
15498 static v8::Local<Context> calling_context1;
15499 static v8::Local<Context> calling_context2;
15500
15501
15502 // Check that the call to the callback is initiated in
15503 // calling_context2, the directly calling context is calling_context1
15504 // and the callback itself is in calling_context0.
15505 static void GetCallingContextCallback(
15506     const v8::FunctionCallbackInfo<v8::Value>& args) {
15507   ApiTestFuzzer::Fuzz();
15508   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15509   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15510   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15511   args.GetReturnValue().Set(42);
15512 }
15513
15514
15515 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15516   i::Isolate* isolate = CcTest::i_isolate();
15517   CHECK(isolate != NULL);
15518   CHECK(isolate->context() == NULL);
15519   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15520   v8::HandleScope scope(v8_isolate);
15521   // The following should not crash, but return an empty handle.
15522   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15523   CHECK(current.IsEmpty());
15524 }
15525
15526
15527 THREADED_TEST(GetCallingContext) {
15528   v8::Isolate* isolate = CcTest::isolate();
15529   v8::HandleScope scope(isolate);
15530
15531   Local<Context> calling_context0(Context::New(isolate));
15532   Local<Context> calling_context1(Context::New(isolate));
15533   Local<Context> calling_context2(Context::New(isolate));
15534   ::calling_context0 = calling_context0;
15535   ::calling_context1 = calling_context1;
15536   ::calling_context2 = calling_context2;
15537
15538   // Allow cross-domain access.
15539   Local<String> token = v8_str("<security token>");
15540   calling_context0->SetSecurityToken(token);
15541   calling_context1->SetSecurityToken(token);
15542   calling_context2->SetSecurityToken(token);
15543
15544   // Create an object with a C++ callback in context0.
15545   calling_context0->Enter();
15546   Local<v8::FunctionTemplate> callback_templ =
15547       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15548   calling_context0->Global()->Set(v8_str("callback"),
15549                                   callback_templ->GetFunction());
15550   calling_context0->Exit();
15551
15552   // Expose context0 in context1 and set up a function that calls the
15553   // callback function.
15554   calling_context1->Enter();
15555   calling_context1->Global()->Set(v8_str("context0"),
15556                                   calling_context0->Global());
15557   CompileRun("function f() { context0.callback() }");
15558   calling_context1->Exit();
15559
15560   // Expose context1 in context2 and call the callback function in
15561   // context0 indirectly through f in context1.
15562   calling_context2->Enter();
15563   calling_context2->Global()->Set(v8_str("context1"),
15564                                   calling_context1->Global());
15565   CompileRun("context1.f()");
15566   calling_context2->Exit();
15567   ::calling_context0.Clear();
15568   ::calling_context1.Clear();
15569   ::calling_context2.Clear();
15570 }
15571
15572
15573 // Check that a variable declaration with no explicit initialization
15574 // value does shadow an existing property in the prototype chain.
15575 THREADED_TEST(InitGlobalVarInProtoChain) {
15576   LocalContext context;
15577   v8::HandleScope scope(context->GetIsolate());
15578   // Introduce a variable in the prototype chain.
15579   CompileRun("__proto__.x = 42");
15580   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15581   CHECK(!result->IsUndefined());
15582   CHECK_EQ(43, result->Int32Value());
15583 }
15584
15585
15586 // Regression test for issue 398.
15587 // If a function is added to an object, creating a constant function
15588 // field, and the result is cloned, replacing the constant function on the
15589 // original should not affect the clone.
15590 // See http://code.google.com/p/v8/issues/detail?id=398
15591 THREADED_TEST(ReplaceConstantFunction) {
15592   LocalContext context;
15593   v8::Isolate* isolate = context->GetIsolate();
15594   v8::HandleScope scope(isolate);
15595   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15596   v8::Handle<v8::FunctionTemplate> func_templ =
15597       v8::FunctionTemplate::New(isolate);
15598   v8::Handle<v8::String> foo_string =
15599       v8::String::NewFromUtf8(isolate, "foo");
15600   obj->Set(foo_string, func_templ->GetFunction());
15601   v8::Handle<v8::Object> obj_clone = obj->Clone();
15602   obj_clone->Set(foo_string,
15603                  v8::String::NewFromUtf8(isolate, "Hello"));
15604   CHECK(!obj->Get(foo_string)->IsUndefined());
15605 }
15606
15607
15608 static void CheckElementValue(i::Isolate* isolate,
15609                               int expected,
15610                               i::Handle<i::Object> obj,
15611                               int offset) {
15612   i::Object* element = *i::Object::GetElement(isolate, obj, offset);
15613   CHECK_EQ(expected, i::Smi::cast(element)->value());
15614 }
15615
15616
15617 THREADED_TEST(PixelArray) {
15618   LocalContext context;
15619   i::Isolate* isolate = CcTest::i_isolate();
15620   i::Factory* factory = isolate->factory();
15621   v8::HandleScope scope(context->GetIsolate());
15622   const int kElementCount = 260;
15623   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15624   i::Handle<i::ExternalUint8ClampedArray> pixels =
15625       i::Handle<i::ExternalUint8ClampedArray>::cast(
15626           factory->NewExternalArray(kElementCount,
15627                                     v8::kExternalUint8ClampedArray,
15628                                     pixel_data));
15629   // Force GC to trigger verification.
15630   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15631   for (int i = 0; i < kElementCount; i++) {
15632     pixels->set(i, i % 256);
15633   }
15634   // Force GC to trigger verification.
15635   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15636   for (int i = 0; i < kElementCount; i++) {
15637     CHECK_EQ(i % 256, pixels->get_scalar(i));
15638     CHECK_EQ(i % 256, pixel_data[i]);
15639   }
15640
15641   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15642   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15643   // Set the elements to be the pixels.
15644   // jsobj->set_elements(*pixels);
15645   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15646   CheckElementValue(isolate, 1, jsobj, 1);
15647   obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15648   context->Global()->Set(v8_str("pixels"), obj);
15649   v8::Handle<v8::Value> result = CompileRun("pixels.field");
15650   CHECK_EQ(1503, result->Int32Value());
15651   result = CompileRun("pixels[1]");
15652   CHECK_EQ(1, result->Int32Value());
15653
15654   result = CompileRun("var sum = 0;"
15655                       "for (var i = 0; i < 8; i++) {"
15656                       "  sum += pixels[i] = pixels[i] = -i;"
15657                       "}"
15658                       "sum;");
15659   CHECK_EQ(-28, result->Int32Value());
15660
15661   result = CompileRun("var sum = 0;"
15662                       "for (var i = 0; i < 8; i++) {"
15663                       "  sum += pixels[i] = pixels[i] = 0;"
15664                       "}"
15665                       "sum;");
15666   CHECK_EQ(0, result->Int32Value());
15667
15668   result = CompileRun("var sum = 0;"
15669                       "for (var i = 0; i < 8; i++) {"
15670                       "  sum += pixels[i] = pixels[i] = 255;"
15671                       "}"
15672                       "sum;");
15673   CHECK_EQ(8 * 255, result->Int32Value());
15674
15675   result = CompileRun("var sum = 0;"
15676                       "for (var i = 0; i < 8; i++) {"
15677                       "  sum += pixels[i] = pixels[i] = 256 + i;"
15678                       "}"
15679                       "sum;");
15680   CHECK_EQ(2076, result->Int32Value());
15681
15682   result = CompileRun("var sum = 0;"
15683                       "for (var i = 0; i < 8; i++) {"
15684                       "  sum += pixels[i] = pixels[i] = i;"
15685                       "}"
15686                       "sum;");
15687   CHECK_EQ(28, result->Int32Value());
15688
15689   result = CompileRun("var sum = 0;"
15690                       "for (var i = 0; i < 8; i++) {"
15691                       "  sum += pixels[i];"
15692                       "}"
15693                       "sum;");
15694   CHECK_EQ(28, result->Int32Value());
15695
15696   i::Handle<i::Smi> value(i::Smi::FromInt(2),
15697                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15698   i::Handle<i::Object> no_failure;
15699   no_failure = i::JSObject::SetElement(jsobj, 1, value, NONE, i::SLOPPY);
15700   ASSERT(!no_failure.is_null());
15701   i::USE(no_failure);
15702   CheckElementValue(isolate, 2, jsobj, 1);
15703   *value.location() = i::Smi::FromInt(256);
15704   no_failure = i::JSObject::SetElement(jsobj, 1, value, NONE, i::SLOPPY);
15705   ASSERT(!no_failure.is_null());
15706   i::USE(no_failure);
15707   CheckElementValue(isolate, 255, jsobj, 1);
15708   *value.location() = i::Smi::FromInt(-1);
15709   no_failure = i::JSObject::SetElement(jsobj, 1, value, NONE, i::SLOPPY);
15710   ASSERT(!no_failure.is_null());
15711   i::USE(no_failure);
15712   CheckElementValue(isolate, 0, jsobj, 1);
15713
15714   result = CompileRun("for (var i = 0; i < 8; i++) {"
15715                       "  pixels[i] = (i * 65) - 109;"
15716                       "}"
15717                       "pixels[1] + pixels[6];");
15718   CHECK_EQ(255, result->Int32Value());
15719   CheckElementValue(isolate, 0, jsobj, 0);
15720   CheckElementValue(isolate, 0, jsobj, 1);
15721   CheckElementValue(isolate, 21, jsobj, 2);
15722   CheckElementValue(isolate, 86, jsobj, 3);
15723   CheckElementValue(isolate, 151, jsobj, 4);
15724   CheckElementValue(isolate, 216, jsobj, 5);
15725   CheckElementValue(isolate, 255, jsobj, 6);
15726   CheckElementValue(isolate, 255, jsobj, 7);
15727   result = CompileRun("var sum = 0;"
15728                       "for (var i = 0; i < 8; i++) {"
15729                       "  sum += pixels[i];"
15730                       "}"
15731                       "sum;");
15732   CHECK_EQ(984, result->Int32Value());
15733
15734   result = CompileRun("for (var i = 0; i < 8; i++) {"
15735                       "  pixels[i] = (i * 1.1);"
15736                       "}"
15737                       "pixels[1] + pixels[6];");
15738   CHECK_EQ(8, result->Int32Value());
15739   CheckElementValue(isolate, 0, jsobj, 0);
15740   CheckElementValue(isolate, 1, jsobj, 1);
15741   CheckElementValue(isolate, 2, jsobj, 2);
15742   CheckElementValue(isolate, 3, jsobj, 3);
15743   CheckElementValue(isolate, 4, jsobj, 4);
15744   CheckElementValue(isolate, 6, jsobj, 5);
15745   CheckElementValue(isolate, 7, jsobj, 6);
15746   CheckElementValue(isolate, 8, jsobj, 7);
15747
15748   result = CompileRun("for (var i = 0; i < 8; i++) {"
15749                       "  pixels[7] = undefined;"
15750                       "}"
15751                       "pixels[7];");
15752   CHECK_EQ(0, result->Int32Value());
15753   CheckElementValue(isolate, 0, jsobj, 7);
15754
15755   result = CompileRun("for (var i = 0; i < 8; i++) {"
15756                       "  pixels[6] = '2.3';"
15757                       "}"
15758                       "pixels[6];");
15759   CHECK_EQ(2, result->Int32Value());
15760   CheckElementValue(isolate, 2, jsobj, 6);
15761
15762   result = CompileRun("for (var i = 0; i < 8; i++) {"
15763                       "  pixels[5] = NaN;"
15764                       "}"
15765                       "pixels[5];");
15766   CHECK_EQ(0, result->Int32Value());
15767   CheckElementValue(isolate, 0, jsobj, 5);
15768
15769   result = CompileRun("for (var i = 0; i < 8; i++) {"
15770                       "  pixels[8] = Infinity;"
15771                       "}"
15772                       "pixels[8];");
15773   CHECK_EQ(255, result->Int32Value());
15774   CheckElementValue(isolate, 255, jsobj, 8);
15775
15776   result = CompileRun("for (var i = 0; i < 8; i++) {"
15777                       "  pixels[9] = -Infinity;"
15778                       "}"
15779                       "pixels[9];");
15780   CHECK_EQ(0, result->Int32Value());
15781   CheckElementValue(isolate, 0, jsobj, 9);
15782
15783   result = CompileRun("pixels[3] = 33;"
15784                       "delete pixels[3];"
15785                       "pixels[3];");
15786   CHECK_EQ(33, result->Int32Value());
15787
15788   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15789                       "pixels[2] = 12; pixels[3] = 13;"
15790                       "pixels.__defineGetter__('2',"
15791                       "function() { return 120; });"
15792                       "pixels[2];");
15793   CHECK_EQ(12, result->Int32Value());
15794
15795   result = CompileRun("var js_array = new Array(40);"
15796                       "js_array[0] = 77;"
15797                       "js_array;");
15798   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15799
15800   result = CompileRun("pixels[1] = 23;"
15801                       "pixels.__proto__ = [];"
15802                       "js_array.__proto__ = pixels;"
15803                       "js_array.concat(pixels);");
15804   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15805   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15806
15807   result = CompileRun("pixels[1] = 23;");
15808   CHECK_EQ(23, result->Int32Value());
15809
15810   // Test for index greater than 255.  Regression test for:
15811   // http://code.google.com/p/chromium/issues/detail?id=26337.
15812   result = CompileRun("pixels[256] = 255;");
15813   CHECK_EQ(255, result->Int32Value());
15814   result = CompileRun("var i = 0;"
15815                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15816                       "i");
15817   CHECK_EQ(255, result->Int32Value());
15818
15819   // Make sure that pixel array ICs recognize when a non-pixel array
15820   // is passed to it.
15821   result = CompileRun("function pa_load(p) {"
15822                       "  var sum = 0;"
15823                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15824                       "  return sum;"
15825                       "}"
15826                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15827                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15828                       "just_ints = new Object();"
15829                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15830                       "for (var i = 0; i < 10; ++i) {"
15831                       "  result = pa_load(just_ints);"
15832                       "}"
15833                       "result");
15834   CHECK_EQ(32640, result->Int32Value());
15835
15836   // Make sure that pixel array ICs recognize out-of-bound accesses.
15837   result = CompileRun("function pa_load(p, start) {"
15838                       "  var sum = 0;"
15839                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15840                       "  return sum;"
15841                       "}"
15842                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15843                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15844                       "for (var i = 0; i < 10; ++i) {"
15845                       "  result = pa_load(pixels,-10);"
15846                       "}"
15847                       "result");
15848   CHECK_EQ(0, result->Int32Value());
15849
15850   // Make sure that generic ICs properly handles a pixel array.
15851   result = CompileRun("function pa_load(p) {"
15852                       "  var sum = 0;"
15853                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15854                       "  return sum;"
15855                       "}"
15856                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15857                       "just_ints = new Object();"
15858                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15859                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15860                       "for (var i = 0; i < 10; ++i) {"
15861                       "  result = pa_load(pixels);"
15862                       "}"
15863                       "result");
15864   CHECK_EQ(32640, result->Int32Value());
15865
15866   // Make sure that generic load ICs recognize out-of-bound accesses in
15867   // pixel arrays.
15868   result = CompileRun("function pa_load(p, start) {"
15869                       "  var sum = 0;"
15870                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15871                       "  return sum;"
15872                       "}"
15873                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15874                       "just_ints = new Object();"
15875                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15876                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15877                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15878                       "for (var i = 0; i < 10; ++i) {"
15879                       "  result = pa_load(pixels,-10);"
15880                       "}"
15881                       "result");
15882   CHECK_EQ(0, result->Int32Value());
15883
15884   // Make sure that generic ICs properly handles other types than pixel
15885   // arrays (that the inlined fast pixel array test leaves the right information
15886   // in the right registers).
15887   result = CompileRun("function pa_load(p) {"
15888                       "  var sum = 0;"
15889                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15890                       "  return sum;"
15891                       "}"
15892                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15893                       "just_ints = new Object();"
15894                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15895                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15896                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15897                       "sparse_array = new Object();"
15898                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15899                       "sparse_array[1000000] = 3;"
15900                       "for (var i = 0; i < 10; ++i) {"
15901                       "  result = pa_load(sparse_array);"
15902                       "}"
15903                       "result");
15904   CHECK_EQ(32640, result->Int32Value());
15905
15906   // Make sure that pixel array store ICs clamp values correctly.
15907   result = CompileRun("function pa_store(p) {"
15908                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15909                       "}"
15910                       "pa_store(pixels);"
15911                       "var sum = 0;"
15912                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15913                       "sum");
15914   CHECK_EQ(48896, result->Int32Value());
15915
15916   // Make sure that pixel array stores correctly handle accesses outside
15917   // of the pixel array..
15918   result = CompileRun("function pa_store(p,start) {"
15919                       "  for (var j = 0; j < 256; j++) {"
15920                       "    p[j+start] = j * 2;"
15921                       "  }"
15922                       "}"
15923                       "pa_store(pixels,0);"
15924                       "pa_store(pixels,-128);"
15925                       "var sum = 0;"
15926                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15927                       "sum");
15928   CHECK_EQ(65280, result->Int32Value());
15929
15930   // Make sure that the generic store stub correctly handle accesses outside
15931   // of the pixel array..
15932   result = CompileRun("function pa_store(p,start) {"
15933                       "  for (var j = 0; j < 256; j++) {"
15934                       "    p[j+start] = j * 2;"
15935                       "  }"
15936                       "}"
15937                       "pa_store(pixels,0);"
15938                       "just_ints = new Object();"
15939                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15940                       "pa_store(just_ints, 0);"
15941                       "pa_store(pixels,-128);"
15942                       "var sum = 0;"
15943                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15944                       "sum");
15945   CHECK_EQ(65280, result->Int32Value());
15946
15947   // Make sure that the generic keyed store stub clamps pixel array values
15948   // correctly.
15949   result = CompileRun("function pa_store(p) {"
15950                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15951                       "}"
15952                       "pa_store(pixels);"
15953                       "just_ints = new Object();"
15954                       "pa_store(just_ints);"
15955                       "pa_store(pixels);"
15956                       "var sum = 0;"
15957                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15958                       "sum");
15959   CHECK_EQ(48896, result->Int32Value());
15960
15961   // Make sure that pixel array loads are optimized by crankshaft.
15962   result = CompileRun("function pa_load(p) {"
15963                       "  var sum = 0;"
15964                       "  for (var i=0; i<256; ++i) {"
15965                       "    sum += p[i];"
15966                       "  }"
15967                       "  return sum; "
15968                       "}"
15969                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15970                       "for (var i = 0; i < 5000; ++i) {"
15971                       "  result = pa_load(pixels);"
15972                       "}"
15973                       "result");
15974   CHECK_EQ(32640, result->Int32Value());
15975
15976   // Make sure that pixel array stores are optimized by crankshaft.
15977   result = CompileRun("function pa_init(p) {"
15978                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
15979                       "}"
15980                       "function pa_load(p) {"
15981                       "  var sum = 0;"
15982                       "  for (var i=0; i<256; ++i) {"
15983                       "    sum += p[i];"
15984                       "  }"
15985                       "  return sum; "
15986                       "}"
15987                       "for (var i = 0; i < 5000; ++i) {"
15988                       "  pa_init(pixels);"
15989                       "}"
15990                       "result = pa_load(pixels);"
15991                       "result");
15992   CHECK_EQ(32640, result->Int32Value());
15993
15994   free(pixel_data);
15995 }
15996
15997
15998 THREADED_TEST(PixelArrayInfo) {
15999   LocalContext context;
16000   v8::HandleScope scope(context->GetIsolate());
16001   for (int size = 0; size < 100; size += 10) {
16002     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16003     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16004     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16005     CHECK(obj->HasIndexedPropertiesInPixelData());
16006     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16007     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16008     free(pixel_data);
16009   }
16010 }
16011
16012
16013 static void NotHandledIndexedPropertyGetter(
16014     uint32_t index,
16015     const v8::PropertyCallbackInfo<v8::Value>& info) {
16016   ApiTestFuzzer::Fuzz();
16017 }
16018
16019
16020 static void NotHandledIndexedPropertySetter(
16021     uint32_t index,
16022     Local<Value> value,
16023     const v8::PropertyCallbackInfo<v8::Value>& info) {
16024   ApiTestFuzzer::Fuzz();
16025 }
16026
16027
16028 THREADED_TEST(PixelArrayWithInterceptor) {
16029   LocalContext context;
16030   i::Factory* factory = CcTest::i_isolate()->factory();
16031   v8::Isolate* isolate = context->GetIsolate();
16032   v8::HandleScope scope(isolate);
16033   const int kElementCount = 260;
16034   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16035   i::Handle<i::ExternalUint8ClampedArray> pixels =
16036       i::Handle<i::ExternalUint8ClampedArray>::cast(
16037           factory->NewExternalArray(kElementCount,
16038                                     v8::kExternalUint8ClampedArray,
16039                                     pixel_data));
16040   for (int i = 0; i < kElementCount; i++) {
16041     pixels->set(i, i % 256);
16042   }
16043   v8::Handle<v8::ObjectTemplate> templ =
16044       v8::ObjectTemplate::New(context->GetIsolate());
16045   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16046                                    NotHandledIndexedPropertySetter);
16047   v8::Handle<v8::Object> obj = templ->NewInstance();
16048   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16049   context->Global()->Set(v8_str("pixels"), obj);
16050   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16051   CHECK_EQ(1, result->Int32Value());
16052   result = CompileRun("var sum = 0;"
16053                       "for (var i = 0; i < 8; i++) {"
16054                       "  sum += pixels[i] = pixels[i] = -i;"
16055                       "}"
16056                       "sum;");
16057   CHECK_EQ(-28, result->Int32Value());
16058   result = CompileRun("pixels.hasOwnProperty('1')");
16059   CHECK(result->BooleanValue());
16060   free(pixel_data);
16061 }
16062
16063
16064 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16065   switch (array_type) {
16066     case v8::kExternalInt8Array:
16067     case v8::kExternalUint8Array:
16068     case v8::kExternalUint8ClampedArray:
16069       return 1;
16070       break;
16071     case v8::kExternalInt16Array:
16072     case v8::kExternalUint16Array:
16073       return 2;
16074       break;
16075     case v8::kExternalInt32Array:
16076     case v8::kExternalUint32Array:
16077     case v8::kExternalFloat32Array:
16078       return 4;
16079       break;
16080     case v8::kExternalFloat64Array:
16081       return 8;
16082       break;
16083     default:
16084       UNREACHABLE();
16085       return -1;
16086   }
16087   UNREACHABLE();
16088   return -1;
16089 }
16090
16091
16092 template <class ExternalArrayClass, class ElementType>
16093 static void ObjectWithExternalArrayTestHelper(
16094     Handle<Context> context,
16095     v8::Handle<Object> obj,
16096     int element_count,
16097     v8::ExternalArrayType array_type,
16098     int64_t low, int64_t high) {
16099   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16100   i::Isolate* isolate = jsobj->GetIsolate();
16101   obj->Set(v8_str("field"),
16102            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16103   context->Global()->Set(v8_str("ext_array"), obj);
16104   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16105   CHECK_EQ(1503, result->Int32Value());
16106   result = CompileRun("ext_array[1]");
16107   CHECK_EQ(1, result->Int32Value());
16108
16109   // Check assigned smis
16110   result = CompileRun("for (var i = 0; i < 8; i++) {"
16111                       "  ext_array[i] = i;"
16112                       "}"
16113                       "var sum = 0;"
16114                       "for (var i = 0; i < 8; i++) {"
16115                       "  sum += ext_array[i];"
16116                       "}"
16117                       "sum;");
16118
16119   CHECK_EQ(28, result->Int32Value());
16120   // Check pass through of assigned smis
16121   result = CompileRun("var sum = 0;"
16122                       "for (var i = 0; i < 8; i++) {"
16123                       "  sum += ext_array[i] = ext_array[i] = -i;"
16124                       "}"
16125                       "sum;");
16126   CHECK_EQ(-28, result->Int32Value());
16127
16128
16129   // Check assigned smis in reverse order
16130   result = CompileRun("for (var i = 8; --i >= 0; ) {"
16131                       "  ext_array[i] = i;"
16132                       "}"
16133                       "var sum = 0;"
16134                       "for (var i = 0; i < 8; i++) {"
16135                       "  sum += ext_array[i];"
16136                       "}"
16137                       "sum;");
16138   CHECK_EQ(28, result->Int32Value());
16139
16140   // Check pass through of assigned HeapNumbers
16141   result = CompileRun("var sum = 0;"
16142                       "for (var i = 0; i < 16; i+=2) {"
16143                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16144                       "}"
16145                       "sum;");
16146   CHECK_EQ(-28, result->Int32Value());
16147
16148   // Check assigned HeapNumbers
16149   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16150                       "  ext_array[i] = (i * 0.5);"
16151                       "}"
16152                       "var sum = 0;"
16153                       "for (var i = 0; i < 16; i+=2) {"
16154                       "  sum += ext_array[i];"
16155                       "}"
16156                       "sum;");
16157   CHECK_EQ(28, result->Int32Value());
16158
16159   // Check assigned HeapNumbers in reverse order
16160   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16161                       "  ext_array[i] = (i * 0.5);"
16162                       "}"
16163                       "var sum = 0;"
16164                       "for (var i = 0; i < 16; i+=2) {"
16165                       "  sum += ext_array[i];"
16166                       "}"
16167                       "sum;");
16168   CHECK_EQ(28, result->Int32Value());
16169
16170   i::ScopedVector<char> test_buf(1024);
16171
16172   // Check legal boundary conditions.
16173   // The repeated loads and stores ensure the ICs are exercised.
16174   const char* boundary_program =
16175       "var res = 0;"
16176       "for (var i = 0; i < 16; i++) {"
16177       "  ext_array[i] = %lld;"
16178       "  if (i > 8) {"
16179       "    res = ext_array[i];"
16180       "  }"
16181       "}"
16182       "res;";
16183   i::OS::SNPrintF(test_buf,
16184                   boundary_program,
16185                   low);
16186   result = CompileRun(test_buf.start());
16187   CHECK_EQ(low, result->IntegerValue());
16188
16189   i::OS::SNPrintF(test_buf,
16190                   boundary_program,
16191                   high);
16192   result = CompileRun(test_buf.start());
16193   CHECK_EQ(high, result->IntegerValue());
16194
16195   // Check misprediction of type in IC.
16196   result = CompileRun("var tmp_array = ext_array;"
16197                       "var sum = 0;"
16198                       "for (var i = 0; i < 8; i++) {"
16199                       "  tmp_array[i] = i;"
16200                       "  sum += tmp_array[i];"
16201                       "  if (i == 4) {"
16202                       "    tmp_array = {};"
16203                       "  }"
16204                       "}"
16205                       "sum;");
16206   // Force GC to trigger verification.
16207   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16208   CHECK_EQ(28, result->Int32Value());
16209
16210   // Make sure out-of-range loads do not throw.
16211   i::OS::SNPrintF(test_buf,
16212                   "var caught_exception = false;"
16213                   "try {"
16214                   "  ext_array[%d];"
16215                   "} catch (e) {"
16216                   "  caught_exception = true;"
16217                   "}"
16218                   "caught_exception;",
16219                   element_count);
16220   result = CompileRun(test_buf.start());
16221   CHECK_EQ(false, result->BooleanValue());
16222
16223   // Make sure out-of-range stores do not throw.
16224   i::OS::SNPrintF(test_buf,
16225                   "var caught_exception = false;"
16226                   "try {"
16227                   "  ext_array[%d] = 1;"
16228                   "} catch (e) {"
16229                   "  caught_exception = true;"
16230                   "}"
16231                   "caught_exception;",
16232                   element_count);
16233   result = CompileRun(test_buf.start());
16234   CHECK_EQ(false, result->BooleanValue());
16235
16236   // Check other boundary conditions, values and operations.
16237   result = CompileRun("for (var i = 0; i < 8; i++) {"
16238                       "  ext_array[7] = undefined;"
16239                       "}"
16240                       "ext_array[7];");
16241   CHECK_EQ(0, result->Int32Value());
16242   if (array_type == v8::kExternalFloat64Array ||
16243       array_type == v8::kExternalFloat32Array) {
16244     CHECK_EQ(static_cast<int>(i::OS::nan_value()),
16245              static_cast<int>(
16246                  i::Object::GetElement(isolate, jsobj, 7)->Number()));
16247   } else {
16248     CheckElementValue(isolate, 0, jsobj, 7);
16249   }
16250
16251   result = CompileRun("for (var i = 0; i < 8; i++) {"
16252                       "  ext_array[6] = '2.3';"
16253                       "}"
16254                       "ext_array[6];");
16255   CHECK_EQ(2, result->Int32Value());
16256   CHECK_EQ(2,
16257            static_cast<int>(
16258                i::Object::GetElement(isolate, jsobj, 6)->Number()));
16259
16260   if (array_type != v8::kExternalFloat32Array &&
16261       array_type != v8::kExternalFloat64Array) {
16262     // Though the specification doesn't state it, be explicit about
16263     // converting NaNs and +/-Infinity to zero.
16264     result = CompileRun("for (var i = 0; i < 8; i++) {"
16265                         "  ext_array[i] = 5;"
16266                         "}"
16267                         "for (var i = 0; i < 8; i++) {"
16268                         "  ext_array[i] = NaN;"
16269                         "}"
16270                         "ext_array[5];");
16271     CHECK_EQ(0, result->Int32Value());
16272     CheckElementValue(isolate, 0, jsobj, 5);
16273
16274     result = CompileRun("for (var i = 0; i < 8; i++) {"
16275                         "  ext_array[i] = 5;"
16276                         "}"
16277                         "for (var i = 0; i < 8; i++) {"
16278                         "  ext_array[i] = Infinity;"
16279                         "}"
16280                         "ext_array[5];");
16281     int expected_value =
16282         (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16283     CHECK_EQ(expected_value, result->Int32Value());
16284     CheckElementValue(isolate, expected_value, jsobj, 5);
16285
16286     result = CompileRun("for (var i = 0; i < 8; i++) {"
16287                         "  ext_array[i] = 5;"
16288                         "}"
16289                         "for (var i = 0; i < 8; i++) {"
16290                         "  ext_array[i] = -Infinity;"
16291                         "}"
16292                         "ext_array[5];");
16293     CHECK_EQ(0, result->Int32Value());
16294     CheckElementValue(isolate, 0, jsobj, 5);
16295
16296     // Check truncation behavior of integral arrays.
16297     const char* unsigned_data =
16298         "var source_data = [0.6, 10.6];"
16299         "var expected_results = [0, 10];";
16300     const char* signed_data =
16301         "var source_data = [0.6, 10.6, -0.6, -10.6];"
16302         "var expected_results = [0, 10, 0, -10];";
16303     const char* pixel_data =
16304         "var source_data = [0.6, 10.6];"
16305         "var expected_results = [1, 11];";
16306     bool is_unsigned =
16307         (array_type == v8::kExternalUint8Array ||
16308          array_type == v8::kExternalUint16Array ||
16309          array_type == v8::kExternalUint32Array);
16310     bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16311
16312     i::OS::SNPrintF(test_buf,
16313                     "%s"
16314                     "var all_passed = true;"
16315                     "for (var i = 0; i < source_data.length; i++) {"
16316                     "  for (var j = 0; j < 8; j++) {"
16317                     "    ext_array[j] = source_data[i];"
16318                     "  }"
16319                     "  all_passed = all_passed &&"
16320                     "               (ext_array[5] == expected_results[i]);"
16321                     "}"
16322                     "all_passed;",
16323                     (is_unsigned ?
16324                          unsigned_data :
16325                          (is_pixel_data ? pixel_data : signed_data)));
16326     result = CompileRun(test_buf.start());
16327     CHECK_EQ(true, result->BooleanValue());
16328   }
16329
16330   i::Handle<ExternalArrayClass> array(
16331       ExternalArrayClass::cast(jsobj->elements()));
16332   for (int i = 0; i < element_count; i++) {
16333     array->set(i, static_cast<ElementType>(i));
16334   }
16335
16336   // Test complex assignments
16337   result = CompileRun("function ee_op_test_complex_func(sum) {"
16338                       " for (var i = 0; i < 40; ++i) {"
16339                       "   sum += (ext_array[i] += 1);"
16340                       "   sum += (ext_array[i] -= 1);"
16341                       " } "
16342                       " return sum;"
16343                       "}"
16344                       "sum=0;"
16345                       "for (var i=0;i<10000;++i) {"
16346                       "  sum=ee_op_test_complex_func(sum);"
16347                       "}"
16348                       "sum;");
16349   CHECK_EQ(16000000, result->Int32Value());
16350
16351   // Test count operations
16352   result = CompileRun("function ee_op_test_count_func(sum) {"
16353                       " for (var i = 0; i < 40; ++i) {"
16354                       "   sum += (++ext_array[i]);"
16355                       "   sum += (--ext_array[i]);"
16356                       " } "
16357                       " return sum;"
16358                       "}"
16359                       "sum=0;"
16360                       "for (var i=0;i<10000;++i) {"
16361                       "  sum=ee_op_test_count_func(sum);"
16362                       "}"
16363                       "sum;");
16364   CHECK_EQ(16000000, result->Int32Value());
16365
16366   result = CompileRun("ext_array[3] = 33;"
16367                       "delete ext_array[3];"
16368                       "ext_array[3];");
16369   CHECK_EQ(33, result->Int32Value());
16370
16371   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16372                       "ext_array[2] = 12; ext_array[3] = 13;"
16373                       "ext_array.__defineGetter__('2',"
16374                       "function() { return 120; });"
16375                       "ext_array[2];");
16376   CHECK_EQ(12, result->Int32Value());
16377
16378   result = CompileRun("var js_array = new Array(40);"
16379                       "js_array[0] = 77;"
16380                       "js_array;");
16381   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16382
16383   result = CompileRun("ext_array[1] = 23;"
16384                       "ext_array.__proto__ = [];"
16385                       "js_array.__proto__ = ext_array;"
16386                       "js_array.concat(ext_array);");
16387   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16388   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16389
16390   result = CompileRun("ext_array[1] = 23;");
16391   CHECK_EQ(23, result->Int32Value());
16392 }
16393
16394
16395 template <class FixedTypedArrayClass,
16396           i::ElementsKind elements_kind,
16397           class ElementType>
16398 static void FixedTypedArrayTestHelper(
16399     v8::ExternalArrayType array_type,
16400     ElementType low,
16401     ElementType high) {
16402   i::FLAG_allow_natives_syntax = true;
16403   LocalContext context;
16404   i::Isolate* isolate = CcTest::i_isolate();
16405   i::Factory* factory = isolate->factory();
16406   v8::HandleScope scope(context->GetIsolate());
16407   const int kElementCount = 260;
16408   i::Handle<FixedTypedArrayClass> fixed_array =
16409     i::Handle<FixedTypedArrayClass>::cast(
16410         factory->NewFixedTypedArray(kElementCount, array_type));
16411   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16412            fixed_array->map()->instance_type());
16413   CHECK_EQ(kElementCount, fixed_array->length());
16414   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16415   for (int i = 0; i < kElementCount; i++) {
16416     fixed_array->set(i, static_cast<ElementType>(i));
16417   }
16418   // Force GC to trigger verification.
16419   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16420   for (int i = 0; i < kElementCount; i++) {
16421     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16422              static_cast<int64_t>(fixed_array->get_scalar(i)));
16423   }
16424   v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16425   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16426   i::Handle<i::Map> fixed_array_map =
16427       i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16428   jsobj->set_map(*fixed_array_map);
16429   jsobj->set_elements(*fixed_array);
16430
16431   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16432       context.local(), obj, kElementCount, array_type,
16433       static_cast<int64_t>(low),
16434       static_cast<int64_t>(high));
16435 }
16436
16437
16438 THREADED_TEST(FixedUint8Array) {
16439   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16440     v8::kExternalUint8Array,
16441     0x0, 0xFF);
16442 }
16443
16444
16445 THREADED_TEST(FixedUint8ClampedArray) {
16446   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16447                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16448     v8::kExternalUint8ClampedArray,
16449     0x0, 0xFF);
16450 }
16451
16452
16453 THREADED_TEST(FixedInt8Array) {
16454   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16455     v8::kExternalInt8Array,
16456     -0x80, 0x7F);
16457 }
16458
16459
16460 THREADED_TEST(FixedUint16Array) {
16461   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16462     v8::kExternalUint16Array,
16463     0x0, 0xFFFF);
16464 }
16465
16466
16467 THREADED_TEST(FixedInt16Array) {
16468   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16469     v8::kExternalInt16Array,
16470     -0x8000, 0x7FFF);
16471 }
16472
16473
16474 THREADED_TEST(FixedUint32Array) {
16475   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16476     v8::kExternalUint32Array,
16477     0x0, UINT_MAX);
16478 }
16479
16480
16481 THREADED_TEST(FixedInt32Array) {
16482   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16483     v8::kExternalInt32Array,
16484     INT_MIN, INT_MAX);
16485 }
16486
16487
16488 THREADED_TEST(FixedFloat32Array) {
16489   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16490     v8::kExternalFloat32Array,
16491     -500, 500);
16492 }
16493
16494
16495 THREADED_TEST(FixedFloat64Array) {
16496   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16497     v8::kExternalFloat64Array,
16498     -500, 500);
16499 }
16500
16501
16502 template <class ExternalArrayClass, class ElementType>
16503 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16504                                     int64_t low,
16505                                     int64_t high) {
16506   LocalContext context;
16507   i::Isolate* isolate = CcTest::i_isolate();
16508   i::Factory* factory = isolate->factory();
16509   v8::HandleScope scope(context->GetIsolate());
16510   const int kElementCount = 40;
16511   int element_size = ExternalArrayElementSize(array_type);
16512   ElementType* array_data =
16513       static_cast<ElementType*>(malloc(kElementCount * element_size));
16514   i::Handle<ExternalArrayClass> array =
16515       i::Handle<ExternalArrayClass>::cast(
16516           factory->NewExternalArray(kElementCount, array_type, array_data));
16517   // Force GC to trigger verification.
16518   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16519   for (int i = 0; i < kElementCount; i++) {
16520     array->set(i, static_cast<ElementType>(i));
16521   }
16522   // Force GC to trigger verification.
16523   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16524   for (int i = 0; i < kElementCount; i++) {
16525     CHECK_EQ(static_cast<int64_t>(i),
16526              static_cast<int64_t>(array->get_scalar(i)));
16527     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16528   }
16529
16530   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16531   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16532   // Set the elements to be the external array.
16533   obj->SetIndexedPropertiesToExternalArrayData(array_data,
16534                                                array_type,
16535                                                kElementCount);
16536   CHECK_EQ(1,
16537            static_cast<int>(
16538                i::Object::GetElement(isolate, jsobj, 1)->Number()));
16539
16540   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16541       context.local(), obj, kElementCount, array_type, low, high);
16542
16543   v8::Handle<v8::Value> result;
16544
16545   // Test more complex manipulations which cause eax to contain values
16546   // that won't be completely overwritten by loads from the arrays.
16547   // This catches bugs in the instructions used for the KeyedLoadIC
16548   // for byte and word types.
16549   {
16550     const int kXSize = 300;
16551     const int kYSize = 300;
16552     const int kLargeElementCount = kXSize * kYSize * 4;
16553     ElementType* large_array_data =
16554         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16555     v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16556     // Set the elements to be the external array.
16557     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16558                                                        array_type,
16559                                                        kLargeElementCount);
16560     context->Global()->Set(v8_str("large_array"), large_obj);
16561     // Initialize contents of a few rows.
16562     for (int x = 0; x < 300; x++) {
16563       int row = 0;
16564       int offset = row * 300 * 4;
16565       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16566       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16567       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16568       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16569       row = 150;
16570       offset = row * 300 * 4;
16571       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16572       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16573       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16574       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16575       row = 298;
16576       offset = row * 300 * 4;
16577       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16578       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16579       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16580       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16581     }
16582     // The goal of the code below is to make "offset" large enough
16583     // that the computation of the index (which goes into eax) has
16584     // high bits set which will not be overwritten by a byte or short
16585     // load.
16586     result = CompileRun("var failed = false;"
16587                         "var offset = 0;"
16588                         "for (var i = 0; i < 300; i++) {"
16589                         "  if (large_array[4 * i] != 127 ||"
16590                         "      large_array[4 * i + 1] != 0 ||"
16591                         "      large_array[4 * i + 2] != 0 ||"
16592                         "      large_array[4 * i + 3] != 127) {"
16593                         "    failed = true;"
16594                         "  }"
16595                         "}"
16596                         "offset = 150 * 300 * 4;"
16597                         "for (var i = 0; i < 300; i++) {"
16598                         "  if (large_array[offset + 4 * i] != 127 ||"
16599                         "      large_array[offset + 4 * i + 1] != 0 ||"
16600                         "      large_array[offset + 4 * i + 2] != 0 ||"
16601                         "      large_array[offset + 4 * i + 3] != 127) {"
16602                         "    failed = true;"
16603                         "  }"
16604                         "}"
16605                         "offset = 298 * 300 * 4;"
16606                         "for (var i = 0; i < 300; i++) {"
16607                         "  if (large_array[offset + 4 * i] != 127 ||"
16608                         "      large_array[offset + 4 * i + 1] != 0 ||"
16609                         "      large_array[offset + 4 * i + 2] != 0 ||"
16610                         "      large_array[offset + 4 * i + 3] != 127) {"
16611                         "    failed = true;"
16612                         "  }"
16613                         "}"
16614                         "!failed;");
16615     CHECK_EQ(true, result->BooleanValue());
16616     free(large_array_data);
16617   }
16618
16619   // The "" property descriptor is overloaded to store information about
16620   // the external array. Ensure that setting and accessing the "" property
16621   // works (it should overwrite the information cached about the external
16622   // array in the DescriptorArray) in various situations.
16623   result = CompileRun("ext_array[''] = 23; ext_array['']");
16624   CHECK_EQ(23, result->Int32Value());
16625
16626   // Property "" set after the external array is associated with the object.
16627   {
16628     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16629     obj2->Set(v8_str("ee_test_field"),
16630               v8::Int32::New(context->GetIsolate(), 256));
16631     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16632     // Set the elements to be the external array.
16633     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16634                                                   array_type,
16635                                                   kElementCount);
16636     context->Global()->Set(v8_str("ext_array"), obj2);
16637     result = CompileRun("ext_array['']");
16638     CHECK_EQ(1503, result->Int32Value());
16639   }
16640
16641   // Property "" set after the external array is associated with the object.
16642   {
16643     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16644     obj2->Set(v8_str("ee_test_field_2"),
16645               v8::Int32::New(context->GetIsolate(), 256));
16646     // Set the elements to be the external array.
16647     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16648                                                   array_type,
16649                                                   kElementCount);
16650     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16651     context->Global()->Set(v8_str("ext_array"), obj2);
16652     result = CompileRun("ext_array['']");
16653     CHECK_EQ(1503, result->Int32Value());
16654   }
16655
16656   // Should reuse the map from previous test.
16657   {
16658     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16659     obj2->Set(v8_str("ee_test_field_2"),
16660               v8::Int32::New(context->GetIsolate(), 256));
16661     // Set the elements to be the external array. Should re-use the map
16662     // from previous test.
16663     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16664                                                   array_type,
16665                                                   kElementCount);
16666     context->Global()->Set(v8_str("ext_array"), obj2);
16667     result = CompileRun("ext_array['']");
16668   }
16669
16670   // Property "" is a constant function that shouldn't not be interfered with
16671   // when an external array is set.
16672   {
16673     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16674     // Start
16675     obj2->Set(v8_str("ee_test_field3"),
16676               v8::Int32::New(context->GetIsolate(), 256));
16677
16678     // Add a constant function to an object.
16679     context->Global()->Set(v8_str("ext_array"), obj2);
16680     result = CompileRun("ext_array[''] = function() {return 1503;};"
16681                         "ext_array['']();");
16682
16683     // Add an external array transition to the same map that
16684     // has the constant transition.
16685     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16686     obj3->Set(v8_str("ee_test_field3"),
16687               v8::Int32::New(context->GetIsolate(), 256));
16688     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16689                                                   array_type,
16690                                                   kElementCount);
16691     context->Global()->Set(v8_str("ext_array"), obj3);
16692   }
16693
16694   // If a external array transition is in the map, it should get clobbered
16695   // by a constant function.
16696   {
16697     // Add an external array transition.
16698     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16699     obj3->Set(v8_str("ee_test_field4"),
16700               v8::Int32::New(context->GetIsolate(), 256));
16701     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16702                                                   array_type,
16703                                                   kElementCount);
16704
16705     // Add a constant function to the same map that just got an external array
16706     // transition.
16707     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16708     obj2->Set(v8_str("ee_test_field4"),
16709               v8::Int32::New(context->GetIsolate(), 256));
16710     context->Global()->Set(v8_str("ext_array"), obj2);
16711     result = CompileRun("ext_array[''] = function() {return 1503;};"
16712                         "ext_array['']();");
16713   }
16714
16715   free(array_data);
16716 }
16717
16718
16719 THREADED_TEST(ExternalInt8Array) {
16720   ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16721       v8::kExternalInt8Array,
16722       -128,
16723       127);
16724 }
16725
16726
16727 THREADED_TEST(ExternalUint8Array) {
16728   ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16729       v8::kExternalUint8Array,
16730       0,
16731       255);
16732 }
16733
16734
16735 THREADED_TEST(ExternalUint8ClampedArray) {
16736   ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16737       v8::kExternalUint8ClampedArray,
16738       0,
16739       255);
16740 }
16741
16742
16743 THREADED_TEST(ExternalInt16Array) {
16744   ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16745       v8::kExternalInt16Array,
16746       -32768,
16747       32767);
16748 }
16749
16750
16751 THREADED_TEST(ExternalUint16Array) {
16752   ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16753       v8::kExternalUint16Array,
16754       0,
16755       65535);
16756 }
16757
16758
16759 THREADED_TEST(ExternalInt32Array) {
16760   ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16761       v8::kExternalInt32Array,
16762       INT_MIN,   // -2147483648
16763       INT_MAX);  //  2147483647
16764 }
16765
16766
16767 THREADED_TEST(ExternalUint32Array) {
16768   ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16769       v8::kExternalUint32Array,
16770       0,
16771       UINT_MAX);  // 4294967295
16772 }
16773
16774
16775 THREADED_TEST(ExternalFloat32Array) {
16776   ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16777       v8::kExternalFloat32Array,
16778       -500,
16779       500);
16780 }
16781
16782
16783 THREADED_TEST(ExternalFloat64Array) {
16784   ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16785       v8::kExternalFloat64Array,
16786       -500,
16787       500);
16788 }
16789
16790
16791 THREADED_TEST(ExternalArrays) {
16792   TestExternalInt8Array();
16793   TestExternalUint8Array();
16794   TestExternalInt16Array();
16795   TestExternalUint16Array();
16796   TestExternalInt32Array();
16797   TestExternalUint32Array();
16798   TestExternalFloat32Array();
16799 }
16800
16801
16802 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16803   LocalContext context;
16804   v8::HandleScope scope(context->GetIsolate());
16805   for (int size = 0; size < 100; size += 10) {
16806     int element_size = ExternalArrayElementSize(array_type);
16807     void* external_data = malloc(size * element_size);
16808     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16809     obj->SetIndexedPropertiesToExternalArrayData(
16810         external_data, array_type, size);
16811     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16812     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16813     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16814     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16815     free(external_data);
16816   }
16817 }
16818
16819
16820 THREADED_TEST(ExternalArrayInfo) {
16821   ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16822   ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16823   ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16824   ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16825   ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16826   ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16827   ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16828   ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16829   ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16830 }
16831
16832
16833 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16834                           v8::ExternalArrayType array_type,
16835                           int size) {
16836   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16837   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16838   last_location = last_message = NULL;
16839   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16840   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16841   CHECK_NE(NULL, last_location);
16842   CHECK_NE(NULL, last_message);
16843 }
16844
16845
16846 TEST(ExternalArrayLimits) {
16847   LocalContext context;
16848   v8::Isolate* isolate = context->GetIsolate();
16849   v8::HandleScope scope(isolate);
16850   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16851   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16852   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16853   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16854   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16855   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16856   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16857   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16858   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16859   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16860   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
16861   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
16862   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
16863   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
16864   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
16865   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
16866   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
16867   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
16868 }
16869
16870
16871 template <typename ElementType, typename TypedArray,
16872           class ExternalArrayClass>
16873 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16874                           int64_t low, int64_t high) {
16875   const int kElementCount = 50;
16876
16877   i::ScopedVector<ElementType> backing_store(kElementCount+2);
16878
16879   LocalContext env;
16880   v8::Isolate* isolate = env->GetIsolate();
16881   v8::HandleScope handle_scope(isolate);
16882
16883   Local<v8::ArrayBuffer> ab =
16884       v8::ArrayBuffer::New(isolate, backing_store.start(),
16885                            (kElementCount + 2) * sizeof(ElementType));
16886   Local<TypedArray> ta =
16887       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16888   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16889   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16890   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
16891   CHECK_EQ(kElementCount*sizeof(ElementType),
16892            static_cast<int>(ta->ByteLength()));
16893   CHECK_EQ(ab, ta->Buffer());
16894
16895   ElementType* data = backing_store.start() + 2;
16896   for (int i = 0; i < kElementCount; i++) {
16897     data[i] = static_cast<ElementType>(i);
16898   }
16899
16900   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16901       env.local(), ta, kElementCount, array_type, low, high);
16902 }
16903
16904
16905 THREADED_TEST(Uint8Array) {
16906   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
16907       v8::kExternalUint8Array, 0, 0xFF);
16908 }
16909
16910
16911 THREADED_TEST(Int8Array) {
16912   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
16913       v8::kExternalInt8Array, -0x80, 0x7F);
16914 }
16915
16916
16917 THREADED_TEST(Uint16Array) {
16918   TypedArrayTestHelper<uint16_t,
16919                        v8::Uint16Array,
16920                        i::ExternalUint16Array>(
16921       v8::kExternalUint16Array, 0, 0xFFFF);
16922 }
16923
16924
16925 THREADED_TEST(Int16Array) {
16926   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
16927       v8::kExternalInt16Array, -0x8000, 0x7FFF);
16928 }
16929
16930
16931 THREADED_TEST(Uint32Array) {
16932   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
16933       v8::kExternalUint32Array, 0, UINT_MAX);
16934 }
16935
16936
16937 THREADED_TEST(Int32Array) {
16938   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
16939       v8::kExternalInt32Array, INT_MIN, INT_MAX);
16940 }
16941
16942
16943 THREADED_TEST(Float32Array) {
16944   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
16945       v8::kExternalFloat32Array, -500, 500);
16946 }
16947
16948
16949 THREADED_TEST(Float64Array) {
16950   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
16951       v8::kExternalFloat64Array, -500, 500);
16952 }
16953
16954
16955 THREADED_TEST(Uint8ClampedArray) {
16956   TypedArrayTestHelper<uint8_t,
16957                        v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
16958       v8::kExternalUint8ClampedArray, 0, 0xFF);
16959 }
16960
16961
16962 THREADED_TEST(DataView) {
16963   const int kSize = 50;
16964
16965   i::ScopedVector<uint8_t> backing_store(kSize+2);
16966
16967   LocalContext env;
16968   v8::Isolate* isolate = env->GetIsolate();
16969   v8::HandleScope handle_scope(isolate);
16970
16971   Local<v8::ArrayBuffer> ab =
16972       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16973   Local<v8::DataView> dv =
16974       v8::DataView::New(ab, 2, kSize);
16975   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16976   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
16977   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16978   CHECK_EQ(ab, dv->Buffer());
16979 }
16980
16981
16982 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
16983   THREADED_TEST(Is##View) {                                                   \
16984     LocalContext env;                                                         \
16985     v8::Isolate* isolate = env->GetIsolate();                                 \
16986     v8::HandleScope handle_scope(isolate);                                    \
16987                                                                               \
16988     Handle<Value> result = CompileRun(                                        \
16989         "var ab = new ArrayBuffer(128);"                                      \
16990         "new " #View "(ab)");                                                 \
16991     CHECK(result->IsArrayBufferView());                                       \
16992     CHECK(result->Is##View());                                                \
16993     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
16994   }
16995
16996 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16997 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16998 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16999 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17000 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17001 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17002 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17003 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17004 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17005 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17006
17007 #undef IS_ARRAY_BUFFER_VIEW_TEST
17008
17009
17010
17011 THREADED_TEST(ScriptContextDependence) {
17012   LocalContext c1;
17013   v8::HandleScope scope(c1->GetIsolate());
17014   const char *source = "foo";
17015   v8::Handle<v8::Script> dep = v8_compile(source);
17016   v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17017       c1->GetIsolate(), source));
17018   v8::Handle<v8::UnboundScript> indep =
17019       v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17020   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17021                     v8::Integer::New(c1->GetIsolate(), 100));
17022   CHECK_EQ(dep->Run()->Int32Value(), 100);
17023   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17024   LocalContext c2;
17025   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17026                     v8::Integer::New(c2->GetIsolate(), 101));
17027   CHECK_EQ(dep->Run()->Int32Value(), 100);
17028   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17029 }
17030
17031
17032 THREADED_TEST(StackTrace) {
17033   LocalContext context;
17034   v8::HandleScope scope(context->GetIsolate());
17035   v8::TryCatch try_catch;
17036   const char *source = "function foo() { FAIL.FAIL; }; foo();";
17037   v8::Handle<v8::String> src =
17038       v8::String::NewFromUtf8(context->GetIsolate(), source);
17039   v8::Handle<v8::String> origin =
17040       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17041   v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17042   v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17043       ->BindToCurrentContext()
17044       ->Run();
17045   CHECK(try_catch.HasCaught());
17046   v8::String::Utf8Value stack(try_catch.StackTrace());
17047   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17048 }
17049
17050
17051 // Checks that a StackFrame has certain expected values.
17052 void checkStackFrame(const char* expected_script_name,
17053     const char* expected_func_name, int expected_line_number,
17054     int expected_column, bool is_eval, bool is_constructor,
17055     v8::Handle<v8::StackFrame> frame) {
17056   v8::HandleScope scope(CcTest::isolate());
17057   v8::String::Utf8Value func_name(frame->GetFunctionName());
17058   v8::String::Utf8Value script_name(frame->GetScriptName());
17059   if (*script_name == NULL) {
17060     // The situation where there is no associated script, like for evals.
17061     CHECK(expected_script_name == NULL);
17062   } else {
17063     CHECK(strstr(*script_name, expected_script_name) != NULL);
17064   }
17065   CHECK(strstr(*func_name, expected_func_name) != NULL);
17066   CHECK_EQ(expected_line_number, frame->GetLineNumber());
17067   CHECK_EQ(expected_column, frame->GetColumn());
17068   CHECK_EQ(is_eval, frame->IsEval());
17069   CHECK_EQ(is_constructor, frame->IsConstructor());
17070 }
17071
17072
17073 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17074   v8::HandleScope scope(args.GetIsolate());
17075   const char* origin = "capture-stack-trace-test";
17076   const int kOverviewTest = 1;
17077   const int kDetailedTest = 2;
17078
17079   ASSERT(args.Length() == 1);
17080
17081   int testGroup = args[0]->Int32Value();
17082   if (testGroup == kOverviewTest) {
17083     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17084         args.GetIsolate(), 10, v8::StackTrace::kOverview);
17085     CHECK_EQ(4, stackTrace->GetFrameCount());
17086     checkStackFrame(origin, "bar", 2, 10, false, false,
17087                     stackTrace->GetFrame(0));
17088     checkStackFrame(origin, "foo", 6, 3, false, false,
17089                     stackTrace->GetFrame(1));
17090     // This is the source string inside the eval which has the call to foo.
17091     checkStackFrame(NULL, "", 1, 5, false, false,
17092                     stackTrace->GetFrame(2));
17093     // The last frame is an anonymous function which has the initial eval call.
17094     checkStackFrame(origin, "", 8, 7, false, false,
17095                     stackTrace->GetFrame(3));
17096
17097     CHECK(stackTrace->AsArray()->IsArray());
17098   } else if (testGroup == kDetailedTest) {
17099     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17100         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17101     CHECK_EQ(4, stackTrace->GetFrameCount());
17102     checkStackFrame(origin, "bat", 4, 22, false, false,
17103                     stackTrace->GetFrame(0));
17104     checkStackFrame(origin, "baz", 8, 3, false, true,
17105                     stackTrace->GetFrame(1));
17106 #ifdef ENABLE_DEBUGGER_SUPPORT
17107     bool is_eval = true;
17108 #else  // ENABLE_DEBUGGER_SUPPORT
17109     bool is_eval = false;
17110 #endif  // ENABLE_DEBUGGER_SUPPORT
17111
17112     // This is the source string inside the eval which has the call to baz.
17113     checkStackFrame(NULL, "", 1, 5, is_eval, false,
17114                     stackTrace->GetFrame(2));
17115     // The last frame is an anonymous function which has the initial eval call.
17116     checkStackFrame(origin, "", 10, 1, false, false,
17117                     stackTrace->GetFrame(3));
17118
17119     CHECK(stackTrace->AsArray()->IsArray());
17120   }
17121 }
17122
17123
17124 // Tests the C++ StackTrace API.
17125 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17126 // THREADED_TEST(CaptureStackTrace) {
17127 TEST(CaptureStackTrace) {
17128   v8::Isolate* isolate = CcTest::isolate();
17129   v8::HandleScope scope(isolate);
17130   v8::Handle<v8::String> origin =
17131       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17132   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17133   templ->Set(v8_str("AnalyzeStackInNativeCode"),
17134              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17135   LocalContext context(0, templ);
17136
17137   // Test getting OVERVIEW information. Should ignore information that is not
17138   // script name, function name, line number, and column offset.
17139   const char *overview_source =
17140     "function bar() {\n"
17141     "  var y; AnalyzeStackInNativeCode(1);\n"
17142     "}\n"
17143     "function foo() {\n"
17144     "\n"
17145     "  bar();\n"
17146     "}\n"
17147     "var x;eval('new foo();');";
17148   v8::Handle<v8::String> overview_src =
17149       v8::String::NewFromUtf8(isolate, overview_source);
17150   v8::ScriptCompiler::Source script_source(overview_src,
17151                                            v8::ScriptOrigin(origin));
17152   v8::Handle<Value> overview_result(
17153       v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17154           ->BindToCurrentContext()
17155           ->Run());
17156   CHECK(!overview_result.IsEmpty());
17157   CHECK(overview_result->IsObject());
17158
17159   // Test getting DETAILED information.
17160   const char *detailed_source =
17161     "function bat() {AnalyzeStackInNativeCode(2);\n"
17162     "}\n"
17163     "\n"
17164     "function baz() {\n"
17165     "  bat();\n"
17166     "}\n"
17167     "eval('new baz();');";
17168   v8::Handle<v8::String> detailed_src =
17169       v8::String::NewFromUtf8(isolate, detailed_source);
17170   // Make the script using a non-zero line and column offset.
17171   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17172   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17173   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17174   v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17175   v8::Handle<v8::UnboundScript> detailed_script(
17176       v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17177   v8::Handle<Value> detailed_result(
17178       detailed_script->BindToCurrentContext()->Run());
17179   CHECK(!detailed_result.IsEmpty());
17180   CHECK(detailed_result->IsObject());
17181 }
17182
17183
17184 static void StackTraceForUncaughtExceptionListener(
17185     v8::Handle<v8::Message> message,
17186     v8::Handle<Value>) {
17187   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17188   CHECK_EQ(2, stack_trace->GetFrameCount());
17189   checkStackFrame("origin", "foo", 2, 3, false, false,
17190                   stack_trace->GetFrame(0));
17191   checkStackFrame("origin", "bar", 5, 3, false, false,
17192                   stack_trace->GetFrame(1));
17193 }
17194
17195
17196 TEST(CaptureStackTraceForUncaughtException) {
17197   report_count = 0;
17198   LocalContext env;
17199   v8::HandleScope scope(env->GetIsolate());
17200   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17201   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17202
17203   CompileRunWithOrigin(
17204       "function foo() {\n"
17205       "  throw 1;\n"
17206       "};\n"
17207       "function bar() {\n"
17208       "  foo();\n"
17209       "};",
17210       "origin");
17211   v8::Local<v8::Object> global = env->Global();
17212   Local<Value> trouble = global->Get(v8_str("bar"));
17213   CHECK(trouble->IsFunction());
17214   Function::Cast(*trouble)->Call(global, 0, NULL);
17215   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17216   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17217 }
17218
17219
17220 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17221   LocalContext env;
17222   v8::HandleScope scope(env->GetIsolate());
17223   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17224                                                     1024,
17225                                                     v8::StackTrace::kDetailed);
17226
17227   CompileRun(
17228       "var setters = ['column', 'lineNumber', 'scriptName',\n"
17229       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17230       "    'isConstructor'];\n"
17231       "for (var i = 0; i < setters.length; i++) {\n"
17232       "  var prop = setters[i];\n"
17233       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17234       "}\n");
17235   CompileRun("throw 'exception';");
17236   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17237 }
17238
17239
17240 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17241                                      v8::Handle<v8::Value> data) {
17242   // Use the frame where JavaScript is called from.
17243   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17244   CHECK(!stack_trace.IsEmpty());
17245   int frame_count = stack_trace->GetFrameCount();
17246   CHECK_EQ(3, frame_count);
17247   int line_number[] = {1, 2, 5};
17248   for (int i = 0; i < frame_count; i++) {
17249     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17250   }
17251 }
17252
17253
17254 // Test that we only return the stack trace at the site where the exception
17255 // is first thrown (not where it is rethrown).
17256 TEST(RethrowStackTrace) {
17257   LocalContext env;
17258   v8::HandleScope scope(env->GetIsolate());
17259   // We make sure that
17260   // - the stack trace of the ReferenceError in g() is reported.
17261   // - the stack trace is not overwritten when e1 is rethrown by t().
17262   // - the stack trace of e2 does not overwrite that of e1.
17263   const char* source =
17264       "function g() { error; }          \n"
17265       "function f() { g(); }            \n"
17266       "function t(e) { throw e; }       \n"
17267       "try {                            \n"
17268       "  f();                           \n"
17269       "} catch (e1) {                   \n"
17270       "  try {                          \n"
17271       "    error;                       \n"
17272       "  } catch (e2) {                 \n"
17273       "    t(e1);                       \n"
17274       "  }                              \n"
17275       "}                                \n";
17276   v8::V8::AddMessageListener(RethrowStackTraceHandler);
17277   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17278   CompileRun(source);
17279   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17280   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17281 }
17282
17283
17284 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17285                                               v8::Handle<v8::Value> data) {
17286   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17287   CHECK(!stack_trace.IsEmpty());
17288   int frame_count = stack_trace->GetFrameCount();
17289   CHECK_EQ(2, frame_count);
17290   int line_number[] = {3, 7};
17291   for (int i = 0; i < frame_count; i++) {
17292     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17293   }
17294 }
17295
17296
17297 // Test that we do not recognize identity for primitive exceptions.
17298 TEST(RethrowPrimitiveStackTrace) {
17299   LocalContext env;
17300   v8::HandleScope scope(env->GetIsolate());
17301   // We do not capture stack trace for non Error objects on creation time.
17302   // Instead, we capture the stack trace on last throw.
17303   const char* source =
17304       "function g() { throw 404; }      \n"
17305       "function f() { g(); }            \n"
17306       "function t(e) { throw e; }       \n"
17307       "try {                            \n"
17308       "  f();                           \n"
17309       "} catch (e1) {                   \n"
17310       "  t(e1)                          \n"
17311       "}                                \n";
17312   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17313   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17314   CompileRun(source);
17315   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17316   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17317 }
17318
17319
17320 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17321                                               v8::Handle<v8::Value> data) {
17322   // Use the frame where JavaScript is called from.
17323   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17324   CHECK(!stack_trace.IsEmpty());
17325   CHECK_EQ(1, stack_trace->GetFrameCount());
17326   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17327 }
17328
17329
17330 // Test that the stack trace is captured when the error object is created and
17331 // not where it is thrown.
17332 TEST(RethrowExistingStackTrace) {
17333   LocalContext env;
17334   v8::HandleScope scope(env->GetIsolate());
17335   const char* source =
17336       "var e = new Error();           \n"
17337       "throw e;                       \n";
17338   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17339   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17340   CompileRun(source);
17341   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17342   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17343 }
17344
17345
17346 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17347                                                v8::Handle<v8::Value> data) {
17348   // Use the frame where JavaScript is called from.
17349   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17350   CHECK(!stack_trace.IsEmpty());
17351   CHECK_EQ(1, stack_trace->GetFrameCount());
17352   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17353 }
17354
17355
17356 // Test that the stack trace is captured where the bogus Error object is thrown.
17357 TEST(RethrowBogusErrorStackTrace) {
17358   LocalContext env;
17359   v8::HandleScope scope(env->GetIsolate());
17360   const char* source =
17361       "var e = {__proto__: new Error()} \n"
17362       "throw e;                         \n";
17363   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17364   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17365   CompileRun(source);
17366   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17367   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17368 }
17369
17370
17371 void AnalyzeStackOfEvalWithSourceURL(
17372     const v8::FunctionCallbackInfo<v8::Value>& args) {
17373   v8::HandleScope scope(args.GetIsolate());
17374   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17375       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17376   CHECK_EQ(5, stackTrace->GetFrameCount());
17377   v8::Handle<v8::String> url = v8_str("eval_url");
17378   for (int i = 0; i < 3; i++) {
17379     v8::Handle<v8::String> name =
17380         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17381     CHECK(!name.IsEmpty());
17382     CHECK_EQ(url, name);
17383   }
17384 }
17385
17386
17387 TEST(SourceURLInStackTrace) {
17388   v8::Isolate* isolate = CcTest::isolate();
17389   v8::HandleScope scope(isolate);
17390   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17391   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17392              v8::FunctionTemplate::New(isolate,
17393                                        AnalyzeStackOfEvalWithSourceURL));
17394   LocalContext context(0, templ);
17395
17396   const char *source =
17397     "function outer() {\n"
17398     "function bar() {\n"
17399     "  AnalyzeStackOfEvalWithSourceURL();\n"
17400     "}\n"
17401     "function foo() {\n"
17402     "\n"
17403     "  bar();\n"
17404     "}\n"
17405     "foo();\n"
17406     "}\n"
17407     "eval('(' + outer +')()%s');";
17408
17409   i::ScopedVector<char> code(1024);
17410   i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
17411   CHECK(CompileRun(code.start())->IsUndefined());
17412   i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
17413   CHECK(CompileRun(code.start())->IsUndefined());
17414 }
17415
17416
17417 static int scriptIdInStack[2];
17418
17419 void AnalyzeScriptIdInStack(
17420     const v8::FunctionCallbackInfo<v8::Value>& args) {
17421   v8::HandleScope scope(args.GetIsolate());
17422   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17423       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17424   CHECK_EQ(2, stackTrace->GetFrameCount());
17425   for (int i = 0; i < 2; i++) {
17426     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17427   }
17428 }
17429
17430
17431 TEST(ScriptIdInStackTrace) {
17432   v8::Isolate* isolate = CcTest::isolate();
17433   v8::HandleScope scope(isolate);
17434   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17435   templ->Set(v8_str("AnalyzeScriptIdInStack"),
17436              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17437   LocalContext context(0, templ);
17438
17439   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17440     isolate,
17441     "function foo() {\n"
17442     "  AnalyzeScriptIdInStack();"
17443     "}\n"
17444     "foo();\n");
17445   v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17446   script->Run();
17447   for (int i = 0; i < 2; i++) {
17448     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17449     CHECK_EQ(scriptIdInStack[i], script->GetId());
17450   }
17451 }
17452
17453
17454 void AnalyzeStackOfInlineScriptWithSourceURL(
17455     const v8::FunctionCallbackInfo<v8::Value>& args) {
17456   v8::HandleScope scope(args.GetIsolate());
17457   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17458       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17459   CHECK_EQ(4, stackTrace->GetFrameCount());
17460   v8::Handle<v8::String> url = v8_str("url");
17461   for (int i = 0; i < 3; i++) {
17462     v8::Handle<v8::String> name =
17463         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17464     CHECK(!name.IsEmpty());
17465     CHECK_EQ(url, name);
17466   }
17467 }
17468
17469
17470 TEST(InlineScriptWithSourceURLInStackTrace) {
17471   v8::Isolate* isolate = CcTest::isolate();
17472   v8::HandleScope scope(isolate);
17473   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17474   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17475              v8::FunctionTemplate::New(
17476                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17477   LocalContext context(0, templ);
17478
17479   const char *source =
17480     "function outer() {\n"
17481     "function bar() {\n"
17482     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
17483     "}\n"
17484     "function foo() {\n"
17485     "\n"
17486     "  bar();\n"
17487     "}\n"
17488     "foo();\n"
17489     "}\n"
17490     "outer()\n%s";
17491
17492   i::ScopedVector<char> code(1024);
17493   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17494   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17495   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17496   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17497 }
17498
17499
17500 void AnalyzeStackOfDynamicScriptWithSourceURL(
17501     const v8::FunctionCallbackInfo<v8::Value>& args) {
17502   v8::HandleScope scope(args.GetIsolate());
17503   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17504       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17505   CHECK_EQ(4, stackTrace->GetFrameCount());
17506   v8::Handle<v8::String> url = v8_str("source_url");
17507   for (int i = 0; i < 3; i++) {
17508     v8::Handle<v8::String> name =
17509         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17510     CHECK(!name.IsEmpty());
17511     CHECK_EQ(url, name);
17512   }
17513 }
17514
17515
17516 TEST(DynamicWithSourceURLInStackTrace) {
17517   v8::Isolate* isolate = CcTest::isolate();
17518   v8::HandleScope scope(isolate);
17519   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17520   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17521              v8::FunctionTemplate::New(
17522                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17523   LocalContext context(0, templ);
17524
17525   const char *source =
17526     "function outer() {\n"
17527     "function bar() {\n"
17528     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17529     "}\n"
17530     "function foo() {\n"
17531     "\n"
17532     "  bar();\n"
17533     "}\n"
17534     "foo();\n"
17535     "}\n"
17536     "outer()\n%s";
17537
17538   i::ScopedVector<char> code(1024);
17539   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17540   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17541   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17542   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17543 }
17544
17545
17546 TEST(DynamicWithSourceURLInStackTraceString) {
17547   LocalContext context;
17548   v8::HandleScope scope(context->GetIsolate());
17549
17550   const char *source =
17551     "function outer() {\n"
17552     "  function foo() {\n"
17553     "    FAIL.FAIL;\n"
17554     "  }\n"
17555     "  foo();\n"
17556     "}\n"
17557     "outer()\n%s";
17558
17559   i::ScopedVector<char> code(1024);
17560   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17561   v8::TryCatch try_catch;
17562   CompileRunWithOrigin(code.start(), "", 0, 0);
17563   CHECK(try_catch.HasCaught());
17564   v8::String::Utf8Value stack(try_catch.StackTrace());
17565   CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17566 }
17567
17568
17569 static void CreateGarbageInOldSpace() {
17570   i::Factory* factory = CcTest::i_isolate()->factory();
17571   v8::HandleScope scope(CcTest::isolate());
17572   i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17573   for (int i = 0; i < 1000; i++) {
17574     factory->NewFixedArray(1000, i::TENURED);
17575   }
17576 }
17577
17578
17579 // Test that idle notification can be handled and eventually returns true.
17580 TEST(IdleNotification) {
17581   const intptr_t MB = 1024 * 1024;
17582   LocalContext env;
17583   v8::HandleScope scope(env->GetIsolate());
17584   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17585   CreateGarbageInOldSpace();
17586   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17587   CHECK_GT(size_with_garbage, initial_size + MB);
17588   bool finished = false;
17589   for (int i = 0; i < 200 && !finished; i++) {
17590     finished = v8::V8::IdleNotification();
17591   }
17592   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17593   CHECK(finished);
17594   CHECK_LT(final_size, initial_size + 1);
17595 }
17596
17597
17598 // Test that idle notification can be handled and eventually collects garbage.
17599 TEST(IdleNotificationWithSmallHint) {
17600   const intptr_t MB = 1024 * 1024;
17601   const int IdlePauseInMs = 900;
17602   LocalContext env;
17603   v8::HandleScope scope(env->GetIsolate());
17604   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17605   CreateGarbageInOldSpace();
17606   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17607   CHECK_GT(size_with_garbage, initial_size + MB);
17608   bool finished = false;
17609   for (int i = 0; i < 200 && !finished; i++) {
17610     finished = v8::V8::IdleNotification(IdlePauseInMs);
17611   }
17612   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17613   CHECK(finished);
17614   CHECK_LT(final_size, initial_size + 1);
17615 }
17616
17617
17618 // Test that idle notification can be handled and eventually collects garbage.
17619 TEST(IdleNotificationWithLargeHint) {
17620   const intptr_t MB = 1024 * 1024;
17621   const int IdlePauseInMs = 900;
17622   LocalContext env;
17623   v8::HandleScope scope(env->GetIsolate());
17624   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17625   CreateGarbageInOldSpace();
17626   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17627   CHECK_GT(size_with_garbage, initial_size + MB);
17628   bool finished = false;
17629   for (int i = 0; i < 200 && !finished; i++) {
17630     finished = v8::V8::IdleNotification(IdlePauseInMs);
17631   }
17632   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17633   CHECK(finished);
17634   CHECK_LT(final_size, initial_size + 1);
17635 }
17636
17637
17638 TEST(Regress2107) {
17639   const intptr_t MB = 1024 * 1024;
17640   const int kShortIdlePauseInMs = 100;
17641   const int kLongIdlePauseInMs = 1000;
17642   LocalContext env;
17643   v8::Isolate* isolate = env->GetIsolate();
17644   v8::HandleScope scope(env->GetIsolate());
17645   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17646   // Send idle notification to start a round of incremental GCs.
17647   v8::V8::IdleNotification(kShortIdlePauseInMs);
17648   // Emulate 7 page reloads.
17649   for (int i = 0; i < 7; i++) {
17650     {
17651       v8::HandleScope inner_scope(env->GetIsolate());
17652       v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17653       ctx->Enter();
17654       CreateGarbageInOldSpace();
17655       ctx->Exit();
17656     }
17657     v8::V8::ContextDisposedNotification();
17658     v8::V8::IdleNotification(kLongIdlePauseInMs);
17659   }
17660   // Create garbage and check that idle notification still collects it.
17661   CreateGarbageInOldSpace();
17662   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17663   CHECK_GT(size_with_garbage, initial_size + MB);
17664   bool finished = false;
17665   for (int i = 0; i < 200 && !finished; i++) {
17666     finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17667   }
17668   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17669   CHECK_LT(final_size, initial_size + 1);
17670 }
17671
17672
17673 TEST(Regress2333) {
17674   LocalContext env;
17675   for (int i = 0; i < 3; i++) {
17676     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17677   }
17678 }
17679
17680 static uint32_t* stack_limit;
17681
17682 static void GetStackLimitCallback(
17683     const v8::FunctionCallbackInfo<v8::Value>& args) {
17684   stack_limit = reinterpret_cast<uint32_t*>(
17685       CcTest::i_isolate()->stack_guard()->real_climit());
17686 }
17687
17688
17689 // Uses the address of a local variable to determine the stack top now.
17690 // Given a size, returns an address that is that far from the current
17691 // top of stack.
17692 static uint32_t* ComputeStackLimit(uint32_t size) {
17693   uint32_t* answer = &size - (size / sizeof(size));
17694   // If the size is very large and the stack is very near the bottom of
17695   // memory then the calculation above may wrap around and give an address
17696   // that is above the (downwards-growing) stack.  In that case we return
17697   // a very low address.
17698   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17699   return answer;
17700 }
17701
17702
17703 // We need at least 165kB for an x64 debug build with clang and ASAN.
17704 static const int stack_breathing_room = 256 * i::KB;
17705
17706
17707 TEST(SetResourceConstraints) {
17708   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17709
17710   // Set stack limit.
17711   v8::ResourceConstraints constraints;
17712   constraints.set_stack_limit(set_limit);
17713   CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17714
17715   // Execute a script.
17716   LocalContext env;
17717   v8::HandleScope scope(env->GetIsolate());
17718   Local<v8::FunctionTemplate> fun_templ =
17719       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17720   Local<Function> fun = fun_templ->GetFunction();
17721   env->Global()->Set(v8_str("get_stack_limit"), fun);
17722   CompileRun("get_stack_limit();");
17723
17724   CHECK(stack_limit == set_limit);
17725 }
17726
17727
17728 TEST(SetResourceConstraintsInThread) {
17729   uint32_t* set_limit;
17730   {
17731     v8::Locker locker(CcTest::isolate());
17732     set_limit = ComputeStackLimit(stack_breathing_room);
17733
17734     // Set stack limit.
17735     v8::ResourceConstraints constraints;
17736     constraints.set_stack_limit(set_limit);
17737     CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17738
17739     // Execute a script.
17740     v8::HandleScope scope(CcTest::isolate());
17741     LocalContext env;
17742     Local<v8::FunctionTemplate> fun_templ =
17743         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17744     Local<Function> fun = fun_templ->GetFunction();
17745     env->Global()->Set(v8_str("get_stack_limit"), fun);
17746     CompileRun("get_stack_limit();");
17747
17748     CHECK(stack_limit == set_limit);
17749   }
17750   {
17751     v8::Locker locker(CcTest::isolate());
17752     CHECK(stack_limit == set_limit);
17753   }
17754 }
17755
17756
17757 THREADED_TEST(GetHeapStatistics) {
17758   LocalContext c1;
17759   v8::HandleScope scope(c1->GetIsolate());
17760   v8::HeapStatistics heap_statistics;
17761   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17762   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17763   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17764   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17765   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17766 }
17767
17768
17769 class VisitorImpl : public v8::ExternalResourceVisitor {
17770  public:
17771   explicit VisitorImpl(TestResource** resource) {
17772     for (int i = 0; i < 4; i++) {
17773       resource_[i] = resource[i];
17774       found_resource_[i] = false;
17775     }
17776   }
17777   virtual ~VisitorImpl() {}
17778   virtual void VisitExternalString(v8::Handle<v8::String> string) {
17779     if (!string->IsExternal()) {
17780       CHECK(string->IsExternalAscii());
17781       return;
17782     }
17783     v8::String::ExternalStringResource* resource =
17784         string->GetExternalStringResource();
17785     CHECK(resource);
17786     for (int i = 0; i < 4; i++) {
17787       if (resource_[i] == resource) {
17788         CHECK(!found_resource_[i]);
17789         found_resource_[i] = true;
17790       }
17791     }
17792   }
17793   void CheckVisitedResources() {
17794     for (int i = 0; i < 4; i++) {
17795       CHECK(found_resource_[i]);
17796     }
17797   }
17798
17799  private:
17800   v8::String::ExternalStringResource* resource_[4];
17801   bool found_resource_[4];
17802 };
17803
17804
17805 TEST(ExternalizeOldSpaceTwoByteCons) {
17806   LocalContext env;
17807   v8::HandleScope scope(env->GetIsolate());
17808   v8::Local<v8::String> cons =
17809       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17810   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17811   CcTest::heap()->CollectAllAvailableGarbage();
17812   CHECK(CcTest::heap()->old_pointer_space()->Contains(
17813             *v8::Utils::OpenHandle(*cons)));
17814
17815   TestResource* resource = new TestResource(
17816       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
17817   cons->MakeExternal(resource);
17818
17819   CHECK(cons->IsExternal());
17820   CHECK_EQ(resource, cons->GetExternalStringResource());
17821   String::Encoding encoding;
17822   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17823   CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
17824 }
17825
17826
17827 TEST(ExternalizeOldSpaceOneByteCons) {
17828   LocalContext env;
17829   v8::HandleScope scope(env->GetIsolate());
17830   v8::Local<v8::String> cons =
17831       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17832   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17833   CcTest::heap()->CollectAllAvailableGarbage();
17834   CHECK(CcTest::heap()->old_pointer_space()->Contains(
17835             *v8::Utils::OpenHandle(*cons)));
17836
17837   TestAsciiResource* resource =
17838       new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet"));
17839   cons->MakeExternal(resource);
17840
17841   CHECK(cons->IsExternalAscii());
17842   CHECK_EQ(resource, cons->GetExternalAsciiStringResource());
17843   String::Encoding encoding;
17844   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17845   CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
17846 }
17847
17848
17849 TEST(VisitExternalStrings) {
17850   LocalContext env;
17851   v8::HandleScope scope(env->GetIsolate());
17852   const char* string = "Some string";
17853   uint16_t* two_byte_string = AsciiToTwoByteString(string);
17854   TestResource* resource[4];
17855   resource[0] = new TestResource(two_byte_string);
17856   v8::Local<v8::String> string0 =
17857       v8::String::NewExternal(env->GetIsolate(), resource[0]);
17858   resource[1] = new TestResource(two_byte_string, NULL, false);
17859   v8::Local<v8::String> string1 =
17860       v8::String::NewExternal(env->GetIsolate(), resource[1]);
17861
17862   // Externalized symbol.
17863   resource[2] = new TestResource(two_byte_string, NULL, false);
17864   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17865       env->GetIsolate(), string, v8::String::kInternalizedString);
17866   CHECK(string2->MakeExternal(resource[2]));
17867
17868   // Symbolized External.
17869   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17870   v8::Local<v8::String> string3 =
17871       v8::String::NewExternal(env->GetIsolate(), resource[3]);
17872   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
17873   // Turn into a symbol.
17874   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17875   CHECK(!CcTest::heap()->InternalizeString(*string3_i)->IsFailure());
17876   CHECK(string3_i->IsInternalizedString());
17877
17878   // We need to add usages for string* to avoid warnings in GCC 4.7
17879   CHECK(string0->IsExternal());
17880   CHECK(string1->IsExternal());
17881   CHECK(string2->IsExternal());
17882   CHECK(string3->IsExternal());
17883
17884   VisitorImpl visitor(resource);
17885   v8::V8::VisitExternalResources(&visitor);
17886   visitor.CheckVisitedResources();
17887 }
17888
17889
17890 TEST(ExternalStringCollectedAtTearDown) {
17891   int destroyed = 0;
17892   v8::Isolate* isolate = v8::Isolate::New();
17893   { v8::Isolate::Scope isolate_scope(isolate);
17894     v8::HandleScope handle_scope(isolate);
17895     const char* s = "One string to test them all, one string to find them.";
17896     TestAsciiResource* inscription =
17897         new TestAsciiResource(i::StrDup(s), &destroyed);
17898     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
17899     // Ring is still alive.  Orcs are roaming freely across our lands.
17900     CHECK_EQ(0, destroyed);
17901     USE(ring);
17902   }
17903
17904   isolate->Dispose();
17905   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
17906   CHECK_EQ(1, destroyed);
17907 }
17908
17909
17910 TEST(ExternalInternalizedStringCollectedAtTearDown) {
17911   int destroyed = 0;
17912   v8::Isolate* isolate = v8::Isolate::New();
17913   { v8::Isolate::Scope isolate_scope(isolate);
17914     LocalContext env(isolate);
17915     v8::HandleScope handle_scope(isolate);
17916     CompileRun("var ring = 'One string to test them all';");
17917     const char* s = "One string to test them all";
17918     TestAsciiResource* inscription =
17919         new TestAsciiResource(i::StrDup(s), &destroyed);
17920     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17921     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17922     ring->MakeExternal(inscription);
17923     // Ring is still alive.  Orcs are roaming freely across our lands.
17924     CHECK_EQ(0, destroyed);
17925     USE(ring);
17926   }
17927
17928   isolate->Dispose();
17929   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
17930   CHECK_EQ(1, destroyed);
17931 }
17932
17933
17934 TEST(ExternalInternalizedStringCollectedAtGC) {
17935   int destroyed = 0;
17936   { LocalContext env;
17937     v8::HandleScope handle_scope(env->GetIsolate());
17938     CompileRun("var ring = 'One string to test them all';");
17939     const char* s = "One string to test them all";
17940     TestAsciiResource* inscription =
17941         new TestAsciiResource(i::StrDup(s), &destroyed);
17942     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17943     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17944     ring->MakeExternal(inscription);
17945     // Ring is still alive.  Orcs are roaming freely across our lands.
17946     CHECK_EQ(0, destroyed);
17947     USE(ring);
17948   }
17949
17950   // Garbage collector deals swift blows to evil.
17951   CcTest::i_isolate()->compilation_cache()->Clear();
17952   CcTest::heap()->CollectAllAvailableGarbage();
17953
17954   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
17955   CHECK_EQ(1, destroyed);
17956 }
17957
17958
17959 static double DoubleFromBits(uint64_t value) {
17960   double target;
17961   i::OS::MemCopy(&target, &value, sizeof(target));
17962   return target;
17963 }
17964
17965
17966 static uint64_t DoubleToBits(double value) {
17967   uint64_t target;
17968   i::OS::MemCopy(&target, &value, sizeof(target));
17969   return target;
17970 }
17971
17972
17973 static double DoubleToDateTime(double input) {
17974   double date_limit = 864e13;
17975   if (std::isnan(input) || input < -date_limit || input > date_limit) {
17976     return i::OS::nan_value();
17977   }
17978   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
17979 }
17980
17981
17982 // We don't have a consistent way to write 64-bit constants syntactically, so we
17983 // split them into two 32-bit constants and combine them programmatically.
17984 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
17985   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
17986 }
17987
17988
17989 THREADED_TEST(QuietSignalingNaNs) {
17990   LocalContext context;
17991   v8::Isolate* isolate = context->GetIsolate();
17992   v8::HandleScope scope(isolate);
17993   v8::TryCatch try_catch;
17994
17995   // Special double values.
17996   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
17997   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
17998   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
17999   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18000   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18001   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18002   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18003
18004   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18005   // on either side of the epoch.
18006   double date_limit = 864e13;
18007
18008   double test_values[] = {
18009       snan,
18010       qnan,
18011       infinity,
18012       max_normal,
18013       date_limit + 1,
18014       date_limit,
18015       min_normal,
18016       max_denormal,
18017       min_denormal,
18018       0,
18019       -0,
18020       -min_denormal,
18021       -max_denormal,
18022       -min_normal,
18023       -date_limit,
18024       -date_limit - 1,
18025       -max_normal,
18026       -infinity,
18027       -qnan,
18028       -snan
18029   };
18030   int num_test_values = 20;
18031
18032   for (int i = 0; i < num_test_values; i++) {
18033     double test_value = test_values[i];
18034
18035     // Check that Number::New preserves non-NaNs and quiets SNaNs.
18036     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18037     double stored_number = number->NumberValue();
18038     if (!std::isnan(test_value)) {
18039       CHECK_EQ(test_value, stored_number);
18040     } else {
18041       uint64_t stored_bits = DoubleToBits(stored_number);
18042       // Check if quiet nan (bits 51..62 all set).
18043 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18044       // Most significant fraction bit for quiet nan is set to 0
18045       // on MIPS architecture. Allowed by IEEE-754.
18046       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18047 #else
18048       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18049 #endif
18050     }
18051
18052     // Check that Date::New preserves non-NaNs in the date range and
18053     // quiets SNaNs.
18054     v8::Handle<v8::Value> date =
18055         v8::Date::New(isolate, test_value);
18056     double expected_stored_date = DoubleToDateTime(test_value);
18057     double stored_date = date->NumberValue();
18058     if (!std::isnan(expected_stored_date)) {
18059       CHECK_EQ(expected_stored_date, stored_date);
18060     } else {
18061       uint64_t stored_bits = DoubleToBits(stored_date);
18062       // Check if quiet nan (bits 51..62 all set).
18063 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18064       // Most significant fraction bit for quiet nan is set to 0
18065       // on MIPS architecture. Allowed by IEEE-754.
18066       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18067 #else
18068       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18069 #endif
18070     }
18071   }
18072 }
18073
18074
18075 static void SpaghettiIncident(
18076     const v8::FunctionCallbackInfo<v8::Value>& args) {
18077   v8::HandleScope scope(args.GetIsolate());
18078   v8::TryCatch tc;
18079   v8::Handle<v8::String> str(args[0]->ToString());
18080   USE(str);
18081   if (tc.HasCaught())
18082     tc.ReThrow();
18083 }
18084
18085
18086 // Test that an exception can be propagated down through a spaghetti
18087 // stack using ReThrow.
18088 THREADED_TEST(SpaghettiStackReThrow) {
18089   v8::Isolate* isolate = CcTest::isolate();
18090   v8::HandleScope scope(isolate);
18091   LocalContext context;
18092   context->Global()->Set(
18093       v8::String::NewFromUtf8(isolate, "s"),
18094       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18095   v8::TryCatch try_catch;
18096   CompileRun(
18097       "var i = 0;"
18098       "var o = {"
18099       "  toString: function () {"
18100       "    if (i == 10) {"
18101       "      throw 'Hey!';"
18102       "    } else {"
18103       "      i++;"
18104       "      return s(o);"
18105       "    }"
18106       "  }"
18107       "};"
18108       "s(o);");
18109   CHECK(try_catch.HasCaught());
18110   v8::String::Utf8Value value(try_catch.Exception());
18111   CHECK_EQ(0, strcmp(*value, "Hey!"));
18112 }
18113
18114
18115 TEST(Regress528) {
18116   v8::V8::Initialize();
18117   v8::Isolate* isolate = CcTest::isolate();
18118   v8::HandleScope scope(isolate);
18119   v8::Local<Context> other_context;
18120   int gc_count;
18121
18122   // Create a context used to keep the code from aging in the compilation
18123   // cache.
18124   other_context = Context::New(isolate);
18125
18126   // Context-dependent context data creates reference from the compilation
18127   // cache to the global object.
18128   const char* source_simple = "1";
18129   {
18130     v8::HandleScope scope(isolate);
18131     v8::Local<Context> context = Context::New(isolate);
18132
18133     context->Enter();
18134     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18135     context->SetEmbedderData(0, obj);
18136     CompileRun(source_simple);
18137     context->Exit();
18138   }
18139   v8::V8::ContextDisposedNotification();
18140   for (gc_count = 1; gc_count < 10; gc_count++) {
18141     other_context->Enter();
18142     CompileRun(source_simple);
18143     other_context->Exit();
18144     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18145     if (GetGlobalObjectsCount() == 1) break;
18146   }
18147   CHECK_GE(2, gc_count);
18148   CHECK_EQ(1, GetGlobalObjectsCount());
18149
18150   // Eval in a function creates reference from the compilation cache to the
18151   // global object.
18152   const char* source_eval = "function f(){eval('1')}; f()";
18153   {
18154     v8::HandleScope scope(isolate);
18155     v8::Local<Context> context = Context::New(isolate);
18156
18157     context->Enter();
18158     CompileRun(source_eval);
18159     context->Exit();
18160   }
18161   v8::V8::ContextDisposedNotification();
18162   for (gc_count = 1; gc_count < 10; gc_count++) {
18163     other_context->Enter();
18164     CompileRun(source_eval);
18165     other_context->Exit();
18166     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18167     if (GetGlobalObjectsCount() == 1) break;
18168   }
18169   CHECK_GE(2, gc_count);
18170   CHECK_EQ(1, GetGlobalObjectsCount());
18171
18172   // Looking up the line number for an exception creates reference from the
18173   // compilation cache to the global object.
18174   const char* source_exception = "function f(){throw 1;} f()";
18175   {
18176     v8::HandleScope scope(isolate);
18177     v8::Local<Context> context = Context::New(isolate);
18178
18179     context->Enter();
18180     v8::TryCatch try_catch;
18181     CompileRun(source_exception);
18182     CHECK(try_catch.HasCaught());
18183     v8::Handle<v8::Message> message = try_catch.Message();
18184     CHECK(!message.IsEmpty());
18185     CHECK_EQ(1, message->GetLineNumber());
18186     context->Exit();
18187   }
18188   v8::V8::ContextDisposedNotification();
18189   for (gc_count = 1; gc_count < 10; gc_count++) {
18190     other_context->Enter();
18191     CompileRun(source_exception);
18192     other_context->Exit();
18193     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18194     if (GetGlobalObjectsCount() == 1) break;
18195   }
18196   CHECK_GE(2, gc_count);
18197   CHECK_EQ(1, GetGlobalObjectsCount());
18198
18199   v8::V8::ContextDisposedNotification();
18200 }
18201
18202
18203 THREADED_TEST(ScriptOrigin) {
18204   LocalContext env;
18205   v8::HandleScope scope(env->GetIsolate());
18206   v8::ScriptOrigin origin =
18207       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18208   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18209       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18210   v8::Script::Compile(script, &origin)->Run();
18211   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18212       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18213   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18214       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18215
18216   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18217   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18218   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18219
18220   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18221   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18222   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18223 }
18224
18225
18226 THREADED_TEST(FunctionGetInferredName) {
18227   LocalContext env;
18228   v8::HandleScope scope(env->GetIsolate());
18229   v8::ScriptOrigin origin =
18230       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18231   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18232       env->GetIsolate(),
18233       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18234   v8::Script::Compile(script, &origin)->Run();
18235   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18236       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18237   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18238 }
18239
18240
18241 THREADED_TEST(FunctionGetDisplayName) {
18242   LocalContext env;
18243   v8::HandleScope scope(env->GetIsolate());
18244   const char* code = "var error = false;"
18245                      "function a() { this.x = 1; };"
18246                      "a.displayName = 'display_a';"
18247                      "var b = (function() {"
18248                      "  var f = function() { this.x = 2; };"
18249                      "  f.displayName = 'display_b';"
18250                      "  return f;"
18251                      "})();"
18252                      "var c = function() {};"
18253                      "c.__defineGetter__('displayName', function() {"
18254                      "  error = true;"
18255                      "  throw new Error();"
18256                      "});"
18257                      "function d() {};"
18258                      "d.__defineGetter__('displayName', function() {"
18259                      "  error = true;"
18260                      "  return 'wrong_display_name';"
18261                      "});"
18262                      "function e() {};"
18263                      "e.displayName = 'wrong_display_name';"
18264                      "e.__defineSetter__('displayName', function() {"
18265                      "  error = true;"
18266                      "  throw new Error();"
18267                      "});"
18268                      "function f() {};"
18269                      "f.displayName = { 'foo': 6, toString: function() {"
18270                      "  error = true;"
18271                      "  return 'wrong_display_name';"
18272                      "}};"
18273                      "var g = function() {"
18274                      "  arguments.callee.displayName = 'set_in_runtime';"
18275                      "}; g();"
18276                      ;
18277   v8::ScriptOrigin origin =
18278       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18279   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18280       ->Run();
18281   v8::Local<v8::Value> error =
18282       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18283   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18284       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18285   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18286       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18287   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18288       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18289   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18290       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18291   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18292       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18293   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18294       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18295   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18296       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18297   CHECK_EQ(false, error->BooleanValue());
18298   CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18299   CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18300   CHECK(c->GetDisplayName()->IsUndefined());
18301   CHECK(d->GetDisplayName()->IsUndefined());
18302   CHECK(e->GetDisplayName()->IsUndefined());
18303   CHECK(f->GetDisplayName()->IsUndefined());
18304   CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18305 }
18306
18307
18308 THREADED_TEST(ScriptLineNumber) {
18309   LocalContext env;
18310   v8::HandleScope scope(env->GetIsolate());
18311   v8::ScriptOrigin origin =
18312       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18313   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18314       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18315   v8::Script::Compile(script, &origin)->Run();
18316   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18317       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18318   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18319       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18320   CHECK_EQ(0, f->GetScriptLineNumber());
18321   CHECK_EQ(2, g->GetScriptLineNumber());
18322 }
18323
18324
18325 THREADED_TEST(ScriptColumnNumber) {
18326   LocalContext env;
18327   v8::Isolate* isolate = env->GetIsolate();
18328   v8::HandleScope scope(isolate);
18329   v8::ScriptOrigin origin =
18330       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18331                        v8::Integer::New(isolate, 3),
18332                        v8::Integer::New(isolate, 2));
18333   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18334       isolate, "function foo() {}\n\n     function bar() {}");
18335   v8::Script::Compile(script, &origin)->Run();
18336   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18337       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18338   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18339       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18340   CHECK_EQ(14, foo->GetScriptColumnNumber());
18341   CHECK_EQ(17, bar->GetScriptColumnNumber());
18342 }
18343
18344
18345 THREADED_TEST(FunctionIsBuiltin) {
18346   LocalContext env;
18347   v8::Isolate* isolate = env->GetIsolate();
18348   v8::HandleScope scope(isolate);
18349   v8::Local<v8::Function> f;
18350   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18351   CHECK(f->IsBuiltin());
18352   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18353   CHECK(f->IsBuiltin());
18354   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18355   CHECK(f->IsBuiltin());
18356   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18357   CHECK(f->IsBuiltin());
18358   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18359   CHECK(!f->IsBuiltin());
18360 }
18361
18362
18363 THREADED_TEST(FunctionGetScriptId) {
18364   LocalContext env;
18365   v8::Isolate* isolate = env->GetIsolate();
18366   v8::HandleScope scope(isolate);
18367   v8::ScriptOrigin origin =
18368       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18369                        v8::Integer::New(isolate, 3),
18370                        v8::Integer::New(isolate, 2));
18371   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18372       isolate, "function foo() {}\n\n     function bar() {}");
18373   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18374   script->Run();
18375   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18376       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18377   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18378       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18379   CHECK_EQ(script->GetId(), foo->ScriptId());
18380   CHECK_EQ(script->GetId(), bar->ScriptId());
18381 }
18382
18383
18384 THREADED_TEST(FunctionGetBoundFunction) {
18385   LocalContext env;
18386   v8::HandleScope scope(env->GetIsolate());
18387   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18388       env->GetIsolate(), "test"));
18389   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18390       env->GetIsolate(),
18391       "var a = new Object();\n"
18392       "a.x = 1;\n"
18393       "function f () { return this.x };\n"
18394       "var g = f.bind(a);\n"
18395       "var b = g();");
18396   v8::Script::Compile(script, &origin)->Run();
18397   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18398       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18399   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18400       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18401   CHECK(g->GetBoundFunction()->IsFunction());
18402   Local<v8::Function> original_function = Local<v8::Function>::Cast(
18403       g->GetBoundFunction());
18404   CHECK_EQ(f->GetName(), original_function->GetName());
18405   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18406   CHECK_EQ(f->GetScriptColumnNumber(),
18407            original_function->GetScriptColumnNumber());
18408 }
18409
18410
18411 static void GetterWhichReturns42(
18412     Local<String> name,
18413     const v8::PropertyCallbackInfo<v8::Value>& info) {
18414   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18415   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18416   info.GetReturnValue().Set(v8_num(42));
18417 }
18418
18419
18420 static void SetterWhichSetsYOnThisTo23(
18421     Local<String> name,
18422     Local<Value> value,
18423     const v8::PropertyCallbackInfo<void>& info) {
18424   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18425   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18426   info.This()->Set(v8_str("y"), v8_num(23));
18427 }
18428
18429
18430 void FooGetInterceptor(Local<String> name,
18431                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18432   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18433   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18434   if (!name->Equals(v8_str("foo"))) return;
18435   info.GetReturnValue().Set(v8_num(42));
18436 }
18437
18438
18439 void FooSetInterceptor(Local<String> name,
18440                        Local<Value> value,
18441                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18442   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18443   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18444   if (!name->Equals(v8_str("foo"))) return;
18445   info.This()->Set(v8_str("y"), v8_num(23));
18446   info.GetReturnValue().Set(v8_num(23));
18447 }
18448
18449
18450 TEST(SetterOnConstructorPrototype) {
18451   v8::Isolate* isolate = CcTest::isolate();
18452   v8::HandleScope scope(isolate);
18453   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18454   templ->SetAccessor(v8_str("x"),
18455                      GetterWhichReturns42,
18456                      SetterWhichSetsYOnThisTo23);
18457   LocalContext context;
18458   context->Global()->Set(v8_str("P"), templ->NewInstance());
18459   CompileRun("function C1() {"
18460              "  this.x = 23;"
18461              "};"
18462              "C1.prototype = P;"
18463              "function C2() {"
18464              "  this.x = 23"
18465              "};"
18466              "C2.prototype = { };"
18467              "C2.prototype.__proto__ = P;");
18468
18469   v8::Local<v8::Script> script;
18470   script = v8_compile("new C1();");
18471   for (int i = 0; i < 10; i++) {
18472     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18473     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18474     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18475   }
18476
18477 script = v8_compile("new C2();");
18478   for (int i = 0; i < 10; i++) {
18479     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18480     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18481     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18482   }
18483 }
18484
18485
18486 static void NamedPropertyGetterWhichReturns42(
18487     Local<String> name,
18488     const v8::PropertyCallbackInfo<v8::Value>& info) {
18489   info.GetReturnValue().Set(v8_num(42));
18490 }
18491
18492
18493 static void NamedPropertySetterWhichSetsYOnThisTo23(
18494     Local<String> name,
18495     Local<Value> value,
18496     const v8::PropertyCallbackInfo<v8::Value>& info) {
18497   if (name->Equals(v8_str("x"))) {
18498     info.This()->Set(v8_str("y"), v8_num(23));
18499   }
18500 }
18501
18502
18503 THREADED_TEST(InterceptorOnConstructorPrototype) {
18504   v8::Isolate* isolate = CcTest::isolate();
18505   v8::HandleScope scope(isolate);
18506   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18507   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18508                                  NamedPropertySetterWhichSetsYOnThisTo23);
18509   LocalContext context;
18510   context->Global()->Set(v8_str("P"), templ->NewInstance());
18511   CompileRun("function C1() {"
18512              "  this.x = 23;"
18513              "};"
18514              "C1.prototype = P;"
18515              "function C2() {"
18516              "  this.x = 23"
18517              "};"
18518              "C2.prototype = { };"
18519              "C2.prototype.__proto__ = P;");
18520
18521   v8::Local<v8::Script> script;
18522   script = v8_compile("new C1();");
18523   for (int i = 0; i < 10; i++) {
18524     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18525     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18526     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18527   }
18528
18529   script = v8_compile("new C2();");
18530   for (int i = 0; i < 10; i++) {
18531     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18532     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18533     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18534   }
18535 }
18536
18537
18538 TEST(Regress618) {
18539   const char* source = "function C1() {"
18540                        "  this.x = 23;"
18541                        "};"
18542                        "C1.prototype = P;";
18543
18544   LocalContext context;
18545   v8::Isolate* isolate = context->GetIsolate();
18546   v8::HandleScope scope(isolate);
18547   v8::Local<v8::Script> script;
18548
18549   // Use a simple object as prototype.
18550   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18551   prototype->Set(v8_str("y"), v8_num(42));
18552   context->Global()->Set(v8_str("P"), prototype);
18553
18554   // This compile will add the code to the compilation cache.
18555   CompileRun(source);
18556
18557   script = v8_compile("new C1();");
18558   // Allow enough iterations for the inobject slack tracking logic
18559   // to finalize instance size and install the fast construct stub.
18560   for (int i = 0; i < 256; i++) {
18561     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18562     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18563     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18564   }
18565
18566   // Use an API object with accessors as prototype.
18567   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18568   templ->SetAccessor(v8_str("x"),
18569                      GetterWhichReturns42,
18570                      SetterWhichSetsYOnThisTo23);
18571   context->Global()->Set(v8_str("P"), templ->NewInstance());
18572
18573   // This compile will get the code from the compilation cache.
18574   CompileRun(source);
18575
18576   script = v8_compile("new C1();");
18577   for (int i = 0; i < 10; i++) {
18578     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18579     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18580     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18581   }
18582 }
18583
18584 v8::Isolate* gc_callbacks_isolate = NULL;
18585 int prologue_call_count = 0;
18586 int epilogue_call_count = 0;
18587 int prologue_call_count_second = 0;
18588 int epilogue_call_count_second = 0;
18589 int prologue_call_count_alloc = 0;
18590 int epilogue_call_count_alloc = 0;
18591
18592 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18593   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18594   ++prologue_call_count;
18595 }
18596
18597
18598 void PrologueCallback(v8::Isolate* isolate,
18599                       v8::GCType,
18600                       v8::GCCallbackFlags flags) {
18601   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18602   CHECK_EQ(gc_callbacks_isolate, isolate);
18603   ++prologue_call_count;
18604 }
18605
18606
18607 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18608   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18609   ++epilogue_call_count;
18610 }
18611
18612
18613 void EpilogueCallback(v8::Isolate* isolate,
18614                       v8::GCType,
18615                       v8::GCCallbackFlags flags) {
18616   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18617   CHECK_EQ(gc_callbacks_isolate, isolate);
18618   ++epilogue_call_count;
18619 }
18620
18621
18622 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18623   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18624   ++prologue_call_count_second;
18625 }
18626
18627
18628 void PrologueCallbackSecond(v8::Isolate* isolate,
18629                             v8::GCType,
18630                             v8::GCCallbackFlags flags) {
18631   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18632   CHECK_EQ(gc_callbacks_isolate, isolate);
18633   ++prologue_call_count_second;
18634 }
18635
18636
18637 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18638   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18639   ++epilogue_call_count_second;
18640 }
18641
18642
18643 void EpilogueCallbackSecond(v8::Isolate* isolate,
18644                             v8::GCType,
18645                             v8::GCCallbackFlags flags) {
18646   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18647   CHECK_EQ(gc_callbacks_isolate, isolate);
18648   ++epilogue_call_count_second;
18649 }
18650
18651
18652 void PrologueCallbackAlloc(v8::Isolate* isolate,
18653                            v8::GCType,
18654                            v8::GCCallbackFlags flags) {
18655   v8::HandleScope scope(isolate);
18656
18657   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18658   CHECK_EQ(gc_callbacks_isolate, isolate);
18659   ++prologue_call_count_alloc;
18660
18661   // Simulate full heap to see if we will reenter this callback
18662   SimulateFullSpace(CcTest::heap()->new_space());
18663
18664   Local<Object> obj = Object::New(isolate);
18665   CHECK(!obj.IsEmpty());
18666
18667   CcTest::heap()->CollectAllGarbage(
18668       i::Heap::kAbortIncrementalMarkingMask);
18669 }
18670
18671
18672 void EpilogueCallbackAlloc(v8::Isolate* isolate,
18673                            v8::GCType,
18674                            v8::GCCallbackFlags flags) {
18675   v8::HandleScope scope(isolate);
18676
18677   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18678   CHECK_EQ(gc_callbacks_isolate, isolate);
18679   ++epilogue_call_count_alloc;
18680
18681   // Simulate full heap to see if we will reenter this callback
18682   SimulateFullSpace(CcTest::heap()->new_space());
18683
18684   Local<Object> obj = Object::New(isolate);
18685   CHECK(!obj.IsEmpty());
18686
18687   CcTest::heap()->CollectAllGarbage(
18688       i::Heap::kAbortIncrementalMarkingMask);
18689 }
18690
18691
18692 TEST(GCCallbacksOld) {
18693   LocalContext context;
18694
18695   v8::V8::AddGCPrologueCallback(PrologueCallback);
18696   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18697   CHECK_EQ(0, prologue_call_count);
18698   CHECK_EQ(0, epilogue_call_count);
18699   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18700   CHECK_EQ(1, prologue_call_count);
18701   CHECK_EQ(1, epilogue_call_count);
18702   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18703   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18704   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18705   CHECK_EQ(2, prologue_call_count);
18706   CHECK_EQ(2, epilogue_call_count);
18707   CHECK_EQ(1, prologue_call_count_second);
18708   CHECK_EQ(1, epilogue_call_count_second);
18709   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18710   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18711   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18712   CHECK_EQ(2, prologue_call_count);
18713   CHECK_EQ(2, epilogue_call_count);
18714   CHECK_EQ(2, prologue_call_count_second);
18715   CHECK_EQ(2, epilogue_call_count_second);
18716   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18717   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18718   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18719   CHECK_EQ(2, prologue_call_count);
18720   CHECK_EQ(2, epilogue_call_count);
18721   CHECK_EQ(2, prologue_call_count_second);
18722   CHECK_EQ(2, epilogue_call_count_second);
18723 }
18724
18725
18726 TEST(GCCallbacks) {
18727   LocalContext context;
18728   v8::Isolate* isolate = context->GetIsolate();
18729   gc_callbacks_isolate = isolate;
18730   isolate->AddGCPrologueCallback(PrologueCallback);
18731   isolate->AddGCEpilogueCallback(EpilogueCallback);
18732   CHECK_EQ(0, prologue_call_count);
18733   CHECK_EQ(0, epilogue_call_count);
18734   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18735   CHECK_EQ(1, prologue_call_count);
18736   CHECK_EQ(1, epilogue_call_count);
18737   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18738   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18739   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18740   CHECK_EQ(2, prologue_call_count);
18741   CHECK_EQ(2, epilogue_call_count);
18742   CHECK_EQ(1, prologue_call_count_second);
18743   CHECK_EQ(1, epilogue_call_count_second);
18744   isolate->RemoveGCPrologueCallback(PrologueCallback);
18745   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18746   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18747   CHECK_EQ(2, prologue_call_count);
18748   CHECK_EQ(2, epilogue_call_count);
18749   CHECK_EQ(2, prologue_call_count_second);
18750   CHECK_EQ(2, epilogue_call_count_second);
18751   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18752   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18753   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18754   CHECK_EQ(2, prologue_call_count);
18755   CHECK_EQ(2, epilogue_call_count);
18756   CHECK_EQ(2, prologue_call_count_second);
18757   CHECK_EQ(2, epilogue_call_count_second);
18758
18759   CHECK_EQ(0, prologue_call_count_alloc);
18760   CHECK_EQ(0, epilogue_call_count_alloc);
18761   isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
18762   isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
18763   CcTest::heap()->CollectAllGarbage(
18764       i::Heap::kAbortIncrementalMarkingMask);
18765   CHECK_EQ(1, prologue_call_count_alloc);
18766   CHECK_EQ(1, epilogue_call_count_alloc);
18767   isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
18768   isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
18769 }
18770
18771
18772 THREADED_TEST(AddToJSFunctionResultCache) {
18773   i::FLAG_stress_compaction = false;
18774   i::FLAG_allow_natives_syntax = true;
18775   v8::HandleScope scope(CcTest::isolate());
18776
18777   LocalContext context;
18778
18779   const char* code =
18780       "(function() {"
18781       "  var key0 = 'a';"
18782       "  var key1 = 'b';"
18783       "  var r0 = %_GetFromCache(0, key0);"
18784       "  var r1 = %_GetFromCache(0, key1);"
18785       "  var r0_ = %_GetFromCache(0, key0);"
18786       "  if (r0 !== r0_)"
18787       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18788       "  var r1_ = %_GetFromCache(0, key1);"
18789       "  if (r1 !== r1_)"
18790       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18791       "  return 'PASSED';"
18792       "})()";
18793   CcTest::heap()->ClearJSFunctionResultCaches();
18794   ExpectString(code, "PASSED");
18795 }
18796
18797
18798 THREADED_TEST(FillJSFunctionResultCache) {
18799   i::FLAG_allow_natives_syntax = true;
18800   LocalContext context;
18801   v8::HandleScope scope(context->GetIsolate());
18802
18803   const char* code =
18804       "(function() {"
18805       "  var k = 'a';"
18806       "  var r = %_GetFromCache(0, k);"
18807       "  for (var i = 0; i < 16; i++) {"
18808       "    %_GetFromCache(0, 'a' + i);"
18809       "  };"
18810       "  if (r === %_GetFromCache(0, k))"
18811       "    return 'FAILED: k0CacheSize is too small';"
18812       "  return 'PASSED';"
18813       "})()";
18814   CcTest::heap()->ClearJSFunctionResultCaches();
18815   ExpectString(code, "PASSED");
18816 }
18817
18818
18819 THREADED_TEST(RoundRobinGetFromCache) {
18820   i::FLAG_allow_natives_syntax = true;
18821   LocalContext context;
18822   v8::HandleScope scope(context->GetIsolate());
18823
18824   const char* code =
18825       "(function() {"
18826       "  var keys = [];"
18827       "  for (var i = 0; i < 16; i++) keys.push(i);"
18828       "  var values = [];"
18829       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18830       "  for (var i = 0; i < 16; i++) {"
18831       "    var v = %_GetFromCache(0, keys[i]);"
18832       "    if (v.toString() !== values[i].toString())"
18833       "      return 'Wrong value for ' + "
18834       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18835       "  };"
18836       "  return 'PASSED';"
18837       "})()";
18838   CcTest::heap()->ClearJSFunctionResultCaches();
18839   ExpectString(code, "PASSED");
18840 }
18841
18842
18843 THREADED_TEST(ReverseGetFromCache) {
18844   i::FLAG_allow_natives_syntax = true;
18845   LocalContext context;
18846   v8::HandleScope scope(context->GetIsolate());
18847
18848   const char* code =
18849       "(function() {"
18850       "  var keys = [];"
18851       "  for (var i = 0; i < 16; i++) keys.push(i);"
18852       "  var values = [];"
18853       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18854       "  for (var i = 15; i >= 16; i--) {"
18855       "    var v = %_GetFromCache(0, keys[i]);"
18856       "    if (v !== values[i])"
18857       "      return 'Wrong value for ' + "
18858       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18859       "  };"
18860       "  return 'PASSED';"
18861       "})()";
18862   CcTest::heap()->ClearJSFunctionResultCaches();
18863   ExpectString(code, "PASSED");
18864 }
18865
18866
18867 THREADED_TEST(TestEviction) {
18868   i::FLAG_allow_natives_syntax = true;
18869   LocalContext context;
18870   v8::HandleScope scope(context->GetIsolate());
18871
18872   const char* code =
18873       "(function() {"
18874       "  for (var i = 0; i < 2*16; i++) {"
18875       "    %_GetFromCache(0, 'a' + i);"
18876       "  };"
18877       "  return 'PASSED';"
18878       "})()";
18879   CcTest::heap()->ClearJSFunctionResultCaches();
18880   ExpectString(code, "PASSED");
18881 }
18882
18883
18884 THREADED_TEST(TwoByteStringInAsciiCons) {
18885   // See Chromium issue 47824.
18886   LocalContext context;
18887   v8::HandleScope scope(context->GetIsolate());
18888
18889   const char* init_code =
18890       "var str1 = 'abelspendabel';"
18891       "var str2 = str1 + str1 + str1;"
18892       "str2;";
18893   Local<Value> result = CompileRun(init_code);
18894
18895   Local<Value> indexof = CompileRun("str2.indexOf('els')");
18896   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
18897
18898   CHECK(result->IsString());
18899   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
18900   int length = string->length();
18901   CHECK(string->IsOneByteRepresentation());
18902
18903   FlattenString(string);
18904   i::Handle<i::String> flat_string = FlattenGetString(string);
18905
18906   CHECK(string->IsOneByteRepresentation());
18907   CHECK(flat_string->IsOneByteRepresentation());
18908
18909   // Create external resource.
18910   uint16_t* uc16_buffer = new uint16_t[length + 1];
18911
18912   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
18913   uc16_buffer[length] = 0;
18914
18915   TestResource resource(uc16_buffer);
18916
18917   flat_string->MakeExternal(&resource);
18918
18919   CHECK(flat_string->IsTwoByteRepresentation());
18920
18921   // If the cons string has been short-circuited, skip the following checks.
18922   if (!string.is_identical_to(flat_string)) {
18923     // At this point, we should have a Cons string which is flat and ASCII,
18924     // with a first half that is a two-byte string (although it only contains
18925     // ASCII characters). This is a valid sequence of steps, and it can happen
18926     // in real pages.
18927     CHECK(string->IsOneByteRepresentation());
18928     i::ConsString* cons = i::ConsString::cast(*string);
18929     CHECK_EQ(0, cons->second()->length());
18930     CHECK(cons->first()->IsTwoByteRepresentation());
18931   }
18932
18933   // Check that some string operations work.
18934
18935   // Atom RegExp.
18936   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
18937   CHECK_EQ(6, reresult->Int32Value());
18938
18939   // Nonatom RegExp.
18940   reresult = CompileRun("str2.match(/abe./g).length;");
18941   CHECK_EQ(6, reresult->Int32Value());
18942
18943   reresult = CompileRun("str2.search(/bel/g);");
18944   CHECK_EQ(1, reresult->Int32Value());
18945
18946   reresult = CompileRun("str2.search(/be./g);");
18947   CHECK_EQ(1, reresult->Int32Value());
18948
18949   ExpectTrue("/bel/g.test(str2);");
18950
18951   ExpectTrue("/be./g.test(str2);");
18952
18953   reresult = CompileRun("/bel/g.exec(str2);");
18954   CHECK(!reresult->IsNull());
18955
18956   reresult = CompileRun("/be./g.exec(str2);");
18957   CHECK(!reresult->IsNull());
18958
18959   ExpectString("str2.substring(2, 10);", "elspenda");
18960
18961   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
18962
18963   ExpectString("str2.charAt(2);", "e");
18964
18965   ExpectObject("str2.indexOf('els');", indexof);
18966
18967   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
18968
18969   reresult = CompileRun("str2.charCodeAt(2);");
18970   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
18971 }
18972
18973
18974 TEST(ContainsOnlyOneByte) {
18975   v8::V8::Initialize();
18976   v8::Isolate* isolate = CcTest::isolate();
18977   v8::HandleScope scope(isolate);
18978   // Make a buffer long enough that it won't automatically be converted.
18979   const int length = 512;
18980   // Ensure word aligned assignment.
18981   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
18982   i::SmartArrayPointer<uintptr_t>
18983   aligned_contents(new uintptr_t[aligned_length]);
18984   uint16_t* string_contents =
18985       reinterpret_cast<uint16_t*>(aligned_contents.get());
18986   // Set to contain only one byte.
18987   for (int i = 0; i < length-1; i++) {
18988     string_contents[i] = 0x41;
18989   }
18990   string_contents[length-1] = 0;
18991   // Simple case.
18992   Handle<String> string =
18993       String::NewExternal(isolate,
18994                           new TestResource(string_contents, NULL, false));
18995   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18996   // Counter example.
18997   string = String::NewFromTwoByte(isolate, string_contents);
18998   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18999   // Test left right and balanced cons strings.
19000   Handle<String> base = String::NewFromUtf8(isolate, "a");
19001   Handle<String> left = base;
19002   Handle<String> right = base;
19003   for (int i = 0; i < 1000; i++) {
19004     left = String::Concat(base, left);
19005     right = String::Concat(right, base);
19006   }
19007   Handle<String> balanced = String::Concat(left, base);
19008   balanced = String::Concat(balanced, right);
19009   Handle<String> cons_strings[] = {left, balanced, right};
19010   Handle<String> two_byte =
19011       String::NewExternal(isolate,
19012                           new TestResource(string_contents, NULL, false));
19013   USE(two_byte); USE(cons_strings);
19014   for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
19015     // Base assumptions.
19016     string = cons_strings[i];
19017     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19018     // Test left and right concatentation.
19019     string = String::Concat(two_byte, cons_strings[i]);
19020     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19021     string = String::Concat(cons_strings[i], two_byte);
19022     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19023   }
19024   // Set bits in different positions
19025   // for strings of different lengths and alignments.
19026   for (int alignment = 0; alignment < 7; alignment++) {
19027     for (int size = 2; alignment + size < length; size *= 2) {
19028       int zero_offset = size + alignment;
19029       string_contents[zero_offset] = 0;
19030       for (int i = 0; i < size; i++) {
19031         int shift = 8 + (i % 7);
19032         string_contents[alignment + i] = 1 << shift;
19033         string = String::NewExternal(
19034             isolate,
19035             new TestResource(string_contents + alignment, NULL, false));
19036         CHECK_EQ(size, string->Length());
19037         CHECK(!string->ContainsOnlyOneByte());
19038         string_contents[alignment + i] = 0x41;
19039       }
19040       string_contents[zero_offset] = 0x41;
19041     }
19042   }
19043 }
19044
19045
19046 // Failed access check callback that performs a GC on each invocation.
19047 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19048                                  v8::AccessType type,
19049                                  Local<v8::Value> data) {
19050   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19051 }
19052
19053
19054 TEST(GCInFailedAccessCheckCallback) {
19055   // Install a failed access check callback that performs a GC on each
19056   // invocation. Then force the callback to be called from va
19057
19058   v8::V8::Initialize();
19059   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19060
19061   v8::Isolate* isolate = CcTest::isolate();
19062   v8::HandleScope scope(isolate);
19063
19064   // Create an ObjectTemplate for global objects and install access
19065   // check callbacks that will block access.
19066   v8::Handle<v8::ObjectTemplate> global_template =
19067       v8::ObjectTemplate::New(isolate);
19068   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19069                                            IndexedGetAccessBlocker,
19070                                            v8::Handle<v8::Value>(),
19071                                            false);
19072
19073   // Create a context and set an x property on it's global object.
19074   LocalContext context0(NULL, global_template);
19075   context0->Global()->Set(v8_str("x"), v8_num(42));
19076   v8::Handle<v8::Object> global0 = context0->Global();
19077
19078   // Create a context with a different security token so that the
19079   // failed access check callback will be called on each access.
19080   LocalContext context1(NULL, global_template);
19081   context1->Global()->Set(v8_str("other"), global0);
19082
19083   // Get property with failed access check.
19084   ExpectUndefined("other.x");
19085
19086   // Get element with failed access check.
19087   ExpectUndefined("other[0]");
19088
19089   // Set property with failed access check.
19090   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19091   CHECK(result->IsObject());
19092
19093   // Set element with failed access check.
19094   result = CompileRun("other[0] = new Object()");
19095   CHECK(result->IsObject());
19096
19097   // Get property attribute with failed access check.
19098   ExpectFalse("\'x\' in other");
19099
19100   // Get property attribute for element with failed access check.
19101   ExpectFalse("0 in other");
19102
19103   // Delete property.
19104   ExpectFalse("delete other.x");
19105
19106   // Delete element.
19107   CHECK_EQ(false, global0->Delete(0));
19108
19109   // DefineAccessor.
19110   CHECK_EQ(false,
19111            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19112
19113   // Define JavaScript accessor.
19114   ExpectUndefined("Object.prototype.__defineGetter__.call("
19115                   "    other, \'x\', function() { return 42; })");
19116
19117   // LookupAccessor.
19118   ExpectUndefined("Object.prototype.__lookupGetter__.call("
19119                   "    other, \'x\')");
19120
19121   // HasLocalElement.
19122   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19123
19124   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19125   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19126   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19127
19128   // Reset the failed access check callback so it does not influence
19129   // the other tests.
19130   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19131 }
19132
19133
19134 TEST(IsolateNewDispose) {
19135   v8::Isolate* current_isolate = CcTest::isolate();
19136   v8::Isolate* isolate = v8::Isolate::New();
19137   CHECK(isolate != NULL);
19138   CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
19139   CHECK(current_isolate != isolate);
19140   CHECK(current_isolate == CcTest::isolate());
19141
19142   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19143   last_location = last_message = NULL;
19144   isolate->Dispose();
19145   CHECK_EQ(last_location, NULL);
19146   CHECK_EQ(last_message, NULL);
19147 }
19148
19149
19150 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19151   v8::Isolate* isolate = v8::Isolate::New();
19152   {
19153     v8::Isolate::Scope i_scope(isolate);
19154     v8::HandleScope scope(isolate);
19155     LocalContext context(isolate);
19156     // Run something in this isolate.
19157     ExpectTrue("true");
19158     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19159     last_location = last_message = NULL;
19160     // Still entered, should fail.
19161     isolate->Dispose();
19162     CHECK_NE(last_location, NULL);
19163     CHECK_NE(last_message, NULL);
19164   }
19165   isolate->Dispose();
19166 }
19167
19168
19169 TEST(RunTwoIsolatesOnSingleThread) {
19170   // Run isolate 1.
19171   v8::Isolate* isolate1 = v8::Isolate::New();
19172   isolate1->Enter();
19173   v8::Persistent<v8::Context> context1;
19174   {
19175     v8::HandleScope scope(isolate1);
19176     context1.Reset(isolate1, Context::New(isolate1));
19177   }
19178
19179   {
19180     v8::HandleScope scope(isolate1);
19181     v8::Local<v8::Context> context =
19182         v8::Local<v8::Context>::New(isolate1, context1);
19183     v8::Context::Scope context_scope(context);
19184     // Run something in new isolate.
19185     CompileRun("var foo = 'isolate 1';");
19186     ExpectString("function f() { return foo; }; f()", "isolate 1");
19187   }
19188
19189   // Run isolate 2.
19190   v8::Isolate* isolate2 = v8::Isolate::New();
19191   v8::Persistent<v8::Context> context2;
19192
19193   {
19194     v8::Isolate::Scope iscope(isolate2);
19195     v8::HandleScope scope(isolate2);
19196     context2.Reset(isolate2, Context::New(isolate2));
19197     v8::Local<v8::Context> context =
19198         v8::Local<v8::Context>::New(isolate2, context2);
19199     v8::Context::Scope context_scope(context);
19200
19201     // Run something in new isolate.
19202     CompileRun("var foo = 'isolate 2';");
19203     ExpectString("function f() { return foo; }; f()", "isolate 2");
19204   }
19205
19206   {
19207     v8::HandleScope scope(isolate1);
19208     v8::Local<v8::Context> context =
19209         v8::Local<v8::Context>::New(isolate1, context1);
19210     v8::Context::Scope context_scope(context);
19211     // Now again in isolate 1
19212     ExpectString("function f() { return foo; }; f()", "isolate 1");
19213   }
19214
19215   isolate1->Exit();
19216
19217   // Run some stuff in default isolate.
19218   v8::Persistent<v8::Context> context_default;
19219   {
19220     v8::Isolate* isolate = CcTest::isolate();
19221     v8::Isolate::Scope iscope(isolate);
19222     v8::HandleScope scope(isolate);
19223     context_default.Reset(isolate, Context::New(isolate));
19224   }
19225
19226   {
19227     v8::HandleScope scope(CcTest::isolate());
19228     v8::Local<v8::Context> context =
19229         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19230     v8::Context::Scope context_scope(context);
19231     // Variables in other isolates should be not available, verify there
19232     // is an exception.
19233     ExpectTrue("function f() {"
19234                "  try {"
19235                "    foo;"
19236                "    return false;"
19237                "  } catch(e) {"
19238                "    return true;"
19239                "  }"
19240                "};"
19241                "var isDefaultIsolate = true;"
19242                "f()");
19243   }
19244
19245   isolate1->Enter();
19246
19247   {
19248     v8::Isolate::Scope iscope(isolate2);
19249     v8::HandleScope scope(isolate2);
19250     v8::Local<v8::Context> context =
19251         v8::Local<v8::Context>::New(isolate2, context2);
19252     v8::Context::Scope context_scope(context);
19253     ExpectString("function f() { return foo; }; f()", "isolate 2");
19254   }
19255
19256   {
19257     v8::HandleScope scope(v8::Isolate::GetCurrent());
19258     v8::Local<v8::Context> context =
19259         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19260     v8::Context::Scope context_scope(context);
19261     ExpectString("function f() { return foo; }; f()", "isolate 1");
19262   }
19263
19264   {
19265     v8::Isolate::Scope iscope(isolate2);
19266     context2.Reset();
19267   }
19268
19269   context1.Reset();
19270   isolate1->Exit();
19271
19272   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19273   last_location = last_message = NULL;
19274
19275   isolate1->Dispose();
19276   CHECK_EQ(last_location, NULL);
19277   CHECK_EQ(last_message, NULL);
19278
19279   isolate2->Dispose();
19280   CHECK_EQ(last_location, NULL);
19281   CHECK_EQ(last_message, NULL);
19282
19283   // Check that default isolate still runs.
19284   {
19285     v8::HandleScope scope(CcTest::isolate());
19286     v8::Local<v8::Context> context =
19287         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19288     v8::Context::Scope context_scope(context);
19289     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19290   }
19291 }
19292
19293
19294 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19295   v8::Isolate::Scope isolate_scope(isolate);
19296   v8::HandleScope scope(isolate);
19297   LocalContext context(isolate);
19298   i::ScopedVector<char> code(1024);
19299   i::OS::SNPrintF(code, "function fib(n) {"
19300                         "  if (n <= 2) return 1;"
19301                         "  return fib(n-1) + fib(n-2);"
19302                         "}"
19303                         "fib(%d)", limit);
19304   Local<Value> value = CompileRun(code.start());
19305   CHECK(value->IsNumber());
19306   return static_cast<int>(value->NumberValue());
19307 }
19308
19309 class IsolateThread : public v8::internal::Thread {
19310  public:
19311   IsolateThread(v8::Isolate* isolate, int fib_limit)
19312       : Thread("IsolateThread"),
19313         isolate_(isolate),
19314         fib_limit_(fib_limit),
19315         result_(0) { }
19316
19317   void Run() {
19318     result_ = CalcFibonacci(isolate_, fib_limit_);
19319   }
19320
19321   int result() { return result_; }
19322
19323  private:
19324   v8::Isolate* isolate_;
19325   int fib_limit_;
19326   int result_;
19327 };
19328
19329
19330 TEST(MultipleIsolatesOnIndividualThreads) {
19331   v8::Isolate* isolate1 = v8::Isolate::New();
19332   v8::Isolate* isolate2 = v8::Isolate::New();
19333
19334   IsolateThread thread1(isolate1, 21);
19335   IsolateThread thread2(isolate2, 12);
19336
19337   // Compute some fibonacci numbers on 3 threads in 3 isolates.
19338   thread1.Start();
19339   thread2.Start();
19340
19341   int result1 = CalcFibonacci(CcTest::isolate(), 21);
19342   int result2 = CalcFibonacci(CcTest::isolate(), 12);
19343
19344   thread1.Join();
19345   thread2.Join();
19346
19347   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19348   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19349   CHECK_EQ(result1, 10946);
19350   CHECK_EQ(result2, 144);
19351   CHECK_EQ(result1, thread1.result());
19352   CHECK_EQ(result2, thread2.result());
19353
19354   isolate1->Dispose();
19355   isolate2->Dispose();
19356 }
19357
19358
19359 TEST(IsolateDifferentContexts) {
19360   v8::Isolate* isolate = v8::Isolate::New();
19361   Local<v8::Context> context;
19362   {
19363     v8::Isolate::Scope isolate_scope(isolate);
19364     v8::HandleScope handle_scope(isolate);
19365     context = v8::Context::New(isolate);
19366     v8::Context::Scope context_scope(context);
19367     Local<Value> v = CompileRun("2");
19368     CHECK(v->IsNumber());
19369     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19370   }
19371   {
19372     v8::Isolate::Scope isolate_scope(isolate);
19373     v8::HandleScope handle_scope(isolate);
19374     context = v8::Context::New(isolate);
19375     v8::Context::Scope context_scope(context);
19376     Local<Value> v = CompileRun("22");
19377     CHECK(v->IsNumber());
19378     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19379   }
19380   isolate->Dispose();
19381 }
19382
19383 class InitDefaultIsolateThread : public v8::internal::Thread {
19384  public:
19385   enum TestCase {
19386     SetResourceConstraints,
19387     SetFatalHandler,
19388     SetCounterFunction,
19389     SetCreateHistogramFunction,
19390     SetAddHistogramSampleFunction
19391   };
19392
19393   explicit InitDefaultIsolateThread(TestCase testCase)
19394       : Thread("InitDefaultIsolateThread"),
19395         testCase_(testCase),
19396         result_(false) { }
19397
19398   void Run() {
19399     v8::Isolate* isolate = v8::Isolate::New();
19400     isolate->Enter();
19401     switch (testCase_) {
19402       case SetResourceConstraints: {
19403         static const int K = 1024;
19404         v8::ResourceConstraints constraints;
19405         constraints.set_max_young_space_size(256 * K);
19406         constraints.set_max_old_space_size(4 * K * K);
19407         v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19408         break;
19409       }
19410
19411       case SetFatalHandler:
19412         v8::V8::SetFatalErrorHandler(NULL);
19413         break;
19414
19415       case SetCounterFunction:
19416         v8::V8::SetCounterFunction(NULL);
19417         break;
19418
19419       case SetCreateHistogramFunction:
19420         v8::V8::SetCreateHistogramFunction(NULL);
19421         break;
19422
19423       case SetAddHistogramSampleFunction:
19424         v8::V8::SetAddHistogramSampleFunction(NULL);
19425         break;
19426     }
19427     isolate->Exit();
19428     isolate->Dispose();
19429     result_ = true;
19430   }
19431
19432   bool result() { return result_; }
19433
19434  private:
19435   TestCase testCase_;
19436   bool result_;
19437 };
19438
19439
19440 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19441   InitDefaultIsolateThread thread(testCase);
19442   thread.Start();
19443   thread.Join();
19444   CHECK_EQ(thread.result(), true);
19445 }
19446
19447
19448 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19449   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19450 }
19451
19452
19453 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19454   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19455 }
19456
19457
19458 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19459   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19460 }
19461
19462
19463 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19464   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19465 }
19466
19467
19468 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19469   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19470 }
19471
19472
19473 TEST(StringCheckMultipleContexts) {
19474   const char* code =
19475       "(function() { return \"a\".charAt(0); })()";
19476
19477   {
19478     // Run the code twice in the first context to initialize the call IC.
19479     LocalContext context1;
19480     v8::HandleScope scope(context1->GetIsolate());
19481     ExpectString(code, "a");
19482     ExpectString(code, "a");
19483   }
19484
19485   {
19486     // Change the String.prototype in the second context and check
19487     // that the right function gets called.
19488     LocalContext context2;
19489     v8::HandleScope scope(context2->GetIsolate());
19490     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19491     ExpectString(code, "not a");
19492   }
19493 }
19494
19495
19496 TEST(NumberCheckMultipleContexts) {
19497   const char* code =
19498       "(function() { return (42).toString(); })()";
19499
19500   {
19501     // Run the code twice in the first context to initialize the call IC.
19502     LocalContext context1;
19503     v8::HandleScope scope(context1->GetIsolate());
19504     ExpectString(code, "42");
19505     ExpectString(code, "42");
19506   }
19507
19508   {
19509     // Change the Number.prototype in the second context and check
19510     // that the right function gets called.
19511     LocalContext context2;
19512     v8::HandleScope scope(context2->GetIsolate());
19513     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19514     ExpectString(code, "not 42");
19515   }
19516 }
19517
19518
19519 TEST(BooleanCheckMultipleContexts) {
19520   const char* code =
19521       "(function() { return true.toString(); })()";
19522
19523   {
19524     // Run the code twice in the first context to initialize the call IC.
19525     LocalContext context1;
19526     v8::HandleScope scope(context1->GetIsolate());
19527     ExpectString(code, "true");
19528     ExpectString(code, "true");
19529   }
19530
19531   {
19532     // Change the Boolean.prototype in the second context and check
19533     // that the right function gets called.
19534     LocalContext context2;
19535     v8::HandleScope scope(context2->GetIsolate());
19536     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19537     ExpectString(code, "");
19538   }
19539 }
19540
19541
19542 TEST(DontDeleteCellLoadIC) {
19543   const char* function_code =
19544       "function readCell() { while (true) { return cell; } }";
19545
19546   {
19547     // Run the code twice in the first context to initialize the load
19548     // IC for a don't delete cell.
19549     LocalContext context1;
19550     v8::HandleScope scope(context1->GetIsolate());
19551     CompileRun("var cell = \"first\";");
19552     ExpectBoolean("delete cell", false);
19553     CompileRun(function_code);
19554     ExpectString("readCell()", "first");
19555     ExpectString("readCell()", "first");
19556   }
19557
19558   {
19559     // Use a deletable cell in the second context.
19560     LocalContext context2;
19561     v8::HandleScope scope(context2->GetIsolate());
19562     CompileRun("cell = \"second\";");
19563     CompileRun(function_code);
19564     ExpectString("readCell()", "second");
19565     ExpectBoolean("delete cell", true);
19566     ExpectString("(function() {"
19567                  "  try {"
19568                  "    return readCell();"
19569                  "  } catch(e) {"
19570                  "    return e.toString();"
19571                  "  }"
19572                  "})()",
19573                  "ReferenceError: cell is not defined");
19574     CompileRun("cell = \"new_second\";");
19575     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19576     ExpectString("readCell()", "new_second");
19577     ExpectString("readCell()", "new_second");
19578   }
19579 }
19580
19581
19582 TEST(DontDeleteCellLoadICForceDelete) {
19583   const char* function_code =
19584       "function readCell() { while (true) { return cell; } }";
19585
19586   // Run the code twice to initialize the load IC for a don't delete
19587   // cell.
19588   LocalContext context;
19589   v8::HandleScope scope(context->GetIsolate());
19590   CompileRun("var cell = \"value\";");
19591   ExpectBoolean("delete cell", false);
19592   CompileRun(function_code);
19593   ExpectString("readCell()", "value");
19594   ExpectString("readCell()", "value");
19595
19596   // Delete the cell using the API and check the inlined code works
19597   // correctly.
19598   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19599   ExpectString("(function() {"
19600                "  try {"
19601                "    return readCell();"
19602                "  } catch(e) {"
19603                "    return e.toString();"
19604                "  }"
19605                "})()",
19606                "ReferenceError: cell is not defined");
19607 }
19608
19609
19610 TEST(DontDeleteCellLoadICAPI) {
19611   const char* function_code =
19612       "function readCell() { while (true) { return cell; } }";
19613
19614   // Run the code twice to initialize the load IC for a don't delete
19615   // cell created using the API.
19616   LocalContext context;
19617   v8::HandleScope scope(context->GetIsolate());
19618   context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19619   ExpectBoolean("delete cell", false);
19620   CompileRun(function_code);
19621   ExpectString("readCell()", "value");
19622   ExpectString("readCell()", "value");
19623
19624   // Delete the cell using the API and check the inlined code works
19625   // correctly.
19626   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19627   ExpectString("(function() {"
19628                "  try {"
19629                "    return readCell();"
19630                "  } catch(e) {"
19631                "    return e.toString();"
19632                "  }"
19633                "})()",
19634                "ReferenceError: cell is not defined");
19635 }
19636
19637
19638 class Visitor42 : public v8::PersistentHandleVisitor {
19639  public:
19640   explicit Visitor42(v8::Persistent<v8::Object>* object)
19641       : counter_(0), object_(object) { }
19642
19643   virtual void VisitPersistentHandle(Persistent<Value>* value,
19644                                      uint16_t class_id) {
19645     if (class_id != 42) return;
19646     CHECK_EQ(42, value->WrapperClassId());
19647     v8::Isolate* isolate = CcTest::isolate();
19648     v8::HandleScope handle_scope(isolate);
19649     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19650     v8::Handle<v8::Value> object =
19651         v8::Local<v8::Object>::New(isolate, *object_);
19652     CHECK(handle->IsObject());
19653     CHECK_EQ(Handle<Object>::Cast(handle), object);
19654     ++counter_;
19655   }
19656
19657   int counter_;
19658   v8::Persistent<v8::Object>* object_;
19659 };
19660
19661
19662 TEST(PersistentHandleVisitor) {
19663   LocalContext context;
19664   v8::Isolate* isolate = context->GetIsolate();
19665   v8::HandleScope scope(isolate);
19666   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19667   CHECK_EQ(0, object.WrapperClassId());
19668   object.SetWrapperClassId(42);
19669   CHECK_EQ(42, object.WrapperClassId());
19670
19671   Visitor42 visitor(&object);
19672   v8::V8::VisitHandlesWithClassIds(&visitor);
19673   CHECK_EQ(1, visitor.counter_);
19674
19675   object.Reset();
19676 }
19677
19678
19679 TEST(WrapperClassId) {
19680   LocalContext context;
19681   v8::Isolate* isolate = context->GetIsolate();
19682   v8::HandleScope scope(isolate);
19683   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19684   CHECK_EQ(0, object.WrapperClassId());
19685   object.SetWrapperClassId(65535);
19686   CHECK_EQ(65535, object.WrapperClassId());
19687   object.Reset();
19688 }
19689
19690
19691 TEST(PersistentHandleInNewSpaceVisitor) {
19692   LocalContext context;
19693   v8::Isolate* isolate = context->GetIsolate();
19694   v8::HandleScope scope(isolate);
19695   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19696   CHECK_EQ(0, object1.WrapperClassId());
19697   object1.SetWrapperClassId(42);
19698   CHECK_EQ(42, object1.WrapperClassId());
19699
19700   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19701
19702   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19703   CHECK_EQ(0, object2.WrapperClassId());
19704   object2.SetWrapperClassId(42);
19705   CHECK_EQ(42, object2.WrapperClassId());
19706
19707   Visitor42 visitor(&object2);
19708   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19709   CHECK_EQ(1, visitor.counter_);
19710
19711   object1.Reset();
19712   object2.Reset();
19713 }
19714
19715
19716 TEST(RegExp) {
19717   LocalContext context;
19718   v8::HandleScope scope(context->GetIsolate());
19719
19720   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19721   CHECK(re->IsRegExp());
19722   CHECK(re->GetSource()->Equals(v8_str("foo")));
19723   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19724
19725   re = v8::RegExp::New(v8_str("bar"),
19726                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19727                                                       v8::RegExp::kGlobal));
19728   CHECK(re->IsRegExp());
19729   CHECK(re->GetSource()->Equals(v8_str("bar")));
19730   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19731            static_cast<int>(re->GetFlags()));
19732
19733   re = v8::RegExp::New(v8_str("baz"),
19734                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19735                                                       v8::RegExp::kMultiline));
19736   CHECK(re->IsRegExp());
19737   CHECK(re->GetSource()->Equals(v8_str("baz")));
19738   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19739            static_cast<int>(re->GetFlags()));
19740
19741   re = CompileRun("/quux/").As<v8::RegExp>();
19742   CHECK(re->IsRegExp());
19743   CHECK(re->GetSource()->Equals(v8_str("quux")));
19744   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19745
19746   re = CompileRun("/quux/gm").As<v8::RegExp>();
19747   CHECK(re->IsRegExp());
19748   CHECK(re->GetSource()->Equals(v8_str("quux")));
19749   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19750            static_cast<int>(re->GetFlags()));
19751
19752   // Override the RegExp constructor and check the API constructor
19753   // still works.
19754   CompileRun("RegExp = function() {}");
19755
19756   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19757   CHECK(re->IsRegExp());
19758   CHECK(re->GetSource()->Equals(v8_str("foobar")));
19759   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19760
19761   re = v8::RegExp::New(v8_str("foobarbaz"),
19762                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19763                                                       v8::RegExp::kMultiline));
19764   CHECK(re->IsRegExp());
19765   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19766   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19767            static_cast<int>(re->GetFlags()));
19768
19769   context->Global()->Set(v8_str("re"), re);
19770   ExpectTrue("re.test('FoobarbaZ')");
19771
19772   // RegExps are objects on which you can set properties.
19773   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19774   v8::Handle<v8::Value> value(CompileRun("re.property"));
19775   CHECK_EQ(32, value->Int32Value());
19776
19777   v8::TryCatch try_catch;
19778   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19779   CHECK(re.IsEmpty());
19780   CHECK(try_catch.HasCaught());
19781   context->Global()->Set(v8_str("ex"), try_catch.Exception());
19782   ExpectTrue("ex instanceof SyntaxError");
19783 }
19784
19785
19786 THREADED_TEST(Equals) {
19787   LocalContext localContext;
19788   v8::HandleScope handleScope(localContext->GetIsolate());
19789
19790   v8::Handle<v8::Object> globalProxy = localContext->Global();
19791   v8::Handle<Value> global = globalProxy->GetPrototype();
19792
19793   CHECK(global->StrictEquals(global));
19794   CHECK(!global->StrictEquals(globalProxy));
19795   CHECK(!globalProxy->StrictEquals(global));
19796   CHECK(globalProxy->StrictEquals(globalProxy));
19797
19798   CHECK(global->Equals(global));
19799   CHECK(!global->Equals(globalProxy));
19800   CHECK(!globalProxy->Equals(global));
19801   CHECK(globalProxy->Equals(globalProxy));
19802 }
19803
19804
19805 static void Getter(v8::Local<v8::String> property,
19806                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
19807   info.GetReturnValue().Set(v8_str("42!"));
19808 }
19809
19810
19811 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19812   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19813   result->Set(0, v8_str("universalAnswer"));
19814   info.GetReturnValue().Set(result);
19815 }
19816
19817
19818 TEST(NamedEnumeratorAndForIn) {
19819   LocalContext context;
19820   v8::Isolate* isolate = context->GetIsolate();
19821   v8::HandleScope handle_scope(isolate);
19822   v8::Context::Scope context_scope(context.local());
19823
19824   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19825   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19826   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19827   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19828         "var result = []; for (var k in o) result.push(k); result"));
19829   CHECK_EQ(1, result->Length());
19830   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19831 }
19832
19833
19834 TEST(DefinePropertyPostDetach) {
19835   LocalContext context;
19836   v8::HandleScope scope(context->GetIsolate());
19837   v8::Handle<v8::Object> proxy = context->Global();
19838   v8::Handle<v8::Function> define_property =
19839       CompileRun("(function() {"
19840                  "  Object.defineProperty("
19841                  "    this,"
19842                  "    1,"
19843                  "    { configurable: true, enumerable: true, value: 3 });"
19844                  "})").As<Function>();
19845   context->DetachGlobal();
19846   define_property->Call(proxy, 0, NULL);
19847 }
19848
19849
19850 static void InstallContextId(v8::Handle<Context> context, int id) {
19851   Context::Scope scope(context);
19852   CompileRun("Object.prototype").As<Object>()->
19853       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19854 }
19855
19856
19857 static void CheckContextId(v8::Handle<Object> object, int expected) {
19858   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19859 }
19860
19861
19862 THREADED_TEST(CreationContext) {
19863   v8::Isolate* isolate = CcTest::isolate();
19864   HandleScope handle_scope(isolate);
19865   Handle<Context> context1 = Context::New(isolate);
19866   InstallContextId(context1, 1);
19867   Handle<Context> context2 = Context::New(isolate);
19868   InstallContextId(context2, 2);
19869   Handle<Context> context3 = Context::New(isolate);
19870   InstallContextId(context3, 3);
19871
19872   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
19873
19874   Local<Object> object1;
19875   Local<Function> func1;
19876   {
19877     Context::Scope scope(context1);
19878     object1 = Object::New(isolate);
19879     func1 = tmpl->GetFunction();
19880   }
19881
19882   Local<Object> object2;
19883   Local<Function> func2;
19884   {
19885     Context::Scope scope(context2);
19886     object2 = Object::New(isolate);
19887     func2 = tmpl->GetFunction();
19888   }
19889
19890   Local<Object> instance1;
19891   Local<Object> instance2;
19892
19893   {
19894     Context::Scope scope(context3);
19895     instance1 = func1->NewInstance();
19896     instance2 = func2->NewInstance();
19897   }
19898
19899   CHECK(object1->CreationContext() == context1);
19900   CheckContextId(object1, 1);
19901   CHECK(func1->CreationContext() == context1);
19902   CheckContextId(func1, 1);
19903   CHECK(instance1->CreationContext() == context1);
19904   CheckContextId(instance1, 1);
19905   CHECK(object2->CreationContext() == context2);
19906   CheckContextId(object2, 2);
19907   CHECK(func2->CreationContext() == context2);
19908   CheckContextId(func2, 2);
19909   CHECK(instance2->CreationContext() == context2);
19910   CheckContextId(instance2, 2);
19911
19912   {
19913     Context::Scope scope(context1);
19914     CHECK(object1->CreationContext() == context1);
19915     CheckContextId(object1, 1);
19916     CHECK(func1->CreationContext() == context1);
19917     CheckContextId(func1, 1);
19918     CHECK(instance1->CreationContext() == context1);
19919     CheckContextId(instance1, 1);
19920     CHECK(object2->CreationContext() == context2);
19921     CheckContextId(object2, 2);
19922     CHECK(func2->CreationContext() == context2);
19923     CheckContextId(func2, 2);
19924     CHECK(instance2->CreationContext() == context2);
19925     CheckContextId(instance2, 2);
19926   }
19927
19928   {
19929     Context::Scope scope(context2);
19930     CHECK(object1->CreationContext() == context1);
19931     CheckContextId(object1, 1);
19932     CHECK(func1->CreationContext() == context1);
19933     CheckContextId(func1, 1);
19934     CHECK(instance1->CreationContext() == context1);
19935     CheckContextId(instance1, 1);
19936     CHECK(object2->CreationContext() == context2);
19937     CheckContextId(object2, 2);
19938     CHECK(func2->CreationContext() == context2);
19939     CheckContextId(func2, 2);
19940     CHECK(instance2->CreationContext() == context2);
19941     CheckContextId(instance2, 2);
19942   }
19943 }
19944
19945
19946 THREADED_TEST(CreationContextOfJsFunction) {
19947   HandleScope handle_scope(CcTest::isolate());
19948   Handle<Context> context = Context::New(CcTest::isolate());
19949   InstallContextId(context, 1);
19950
19951   Local<Object> function;
19952   {
19953     Context::Scope scope(context);
19954     function = CompileRun("function foo() {}; foo").As<Object>();
19955   }
19956
19957   CHECK(function->CreationContext() == context);
19958   CheckContextId(function, 1);
19959 }
19960
19961
19962 void HasOwnPropertyIndexedPropertyGetter(
19963     uint32_t index,
19964     const v8::PropertyCallbackInfo<v8::Value>& info) {
19965   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
19966 }
19967
19968
19969 void HasOwnPropertyNamedPropertyGetter(
19970     Local<String> property,
19971     const v8::PropertyCallbackInfo<v8::Value>& info) {
19972   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
19973 }
19974
19975
19976 void HasOwnPropertyIndexedPropertyQuery(
19977     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
19978   if (index == 42) info.GetReturnValue().Set(1);
19979 }
19980
19981
19982 void HasOwnPropertyNamedPropertyQuery(
19983     Local<String> property,
19984     const v8::PropertyCallbackInfo<v8::Integer>& info) {
19985   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
19986 }
19987
19988
19989 void HasOwnPropertyNamedPropertyQuery2(
19990     Local<String> property,
19991     const v8::PropertyCallbackInfo<v8::Integer>& info) {
19992   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
19993 }
19994
19995
19996 void HasOwnPropertyAccessorGetter(
19997     Local<String> property,
19998     const v8::PropertyCallbackInfo<v8::Value>& info) {
19999   info.GetReturnValue().Set(v8_str("yes"));
20000 }
20001
20002
20003 TEST(HasOwnProperty) {
20004   LocalContext env;
20005   v8::Isolate* isolate = env->GetIsolate();
20006   v8::HandleScope scope(isolate);
20007   { // Check normal properties and defined getters.
20008     Handle<Value> value = CompileRun(
20009         "function Foo() {"
20010         "    this.foo = 11;"
20011         "    this.__defineGetter__('baz', function() { return 1; });"
20012         "};"
20013         "function Bar() { "
20014         "    this.bar = 13;"
20015         "    this.__defineGetter__('bla', function() { return 2; });"
20016         "};"
20017         "Bar.prototype = new Foo();"
20018         "new Bar();");
20019     CHECK(value->IsObject());
20020     Handle<Object> object = value->ToObject();
20021     CHECK(object->Has(v8_str("foo")));
20022     CHECK(!object->HasOwnProperty(v8_str("foo")));
20023     CHECK(object->HasOwnProperty(v8_str("bar")));
20024     CHECK(object->Has(v8_str("baz")));
20025     CHECK(!object->HasOwnProperty(v8_str("baz")));
20026     CHECK(object->HasOwnProperty(v8_str("bla")));
20027   }
20028   { // Check named getter interceptors.
20029     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20030     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20031     Handle<Object> instance = templ->NewInstance();
20032     CHECK(!instance->HasOwnProperty(v8_str("42")));
20033     CHECK(instance->HasOwnProperty(v8_str("foo")));
20034     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20035   }
20036   { // Check indexed getter interceptors.
20037     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20038     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20039     Handle<Object> instance = templ->NewInstance();
20040     CHECK(instance->HasOwnProperty(v8_str("42")));
20041     CHECK(!instance->HasOwnProperty(v8_str("43")));
20042     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20043   }
20044   { // Check named query interceptors.
20045     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20046     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20047     Handle<Object> instance = templ->NewInstance();
20048     CHECK(instance->HasOwnProperty(v8_str("foo")));
20049     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20050   }
20051   { // Check indexed query interceptors.
20052     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20053     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20054     Handle<Object> instance = templ->NewInstance();
20055     CHECK(instance->HasOwnProperty(v8_str("42")));
20056     CHECK(!instance->HasOwnProperty(v8_str("41")));
20057   }
20058   { // Check callbacks.
20059     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20060     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20061     Handle<Object> instance = templ->NewInstance();
20062     CHECK(instance->HasOwnProperty(v8_str("foo")));
20063     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20064   }
20065   { // Check that query wins on disagreement.
20066     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20067     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20068                                    0,
20069                                    HasOwnPropertyNamedPropertyQuery2);
20070     Handle<Object> instance = templ->NewInstance();
20071     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20072     CHECK(instance->HasOwnProperty(v8_str("bar")));
20073   }
20074 }
20075
20076
20077 TEST(IndexedInterceptorWithStringProto) {
20078   v8::Isolate* isolate = CcTest::isolate();
20079   v8::HandleScope scope(isolate);
20080   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20081   templ->SetIndexedPropertyHandler(NULL,
20082                                    NULL,
20083                                    HasOwnPropertyIndexedPropertyQuery);
20084   LocalContext context;
20085   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20086   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20087   // These should be intercepted.
20088   CHECK(CompileRun("42 in obj")->BooleanValue());
20089   CHECK(CompileRun("'42' in obj")->BooleanValue());
20090   // These should fall through to the String prototype.
20091   CHECK(CompileRun("0 in obj")->BooleanValue());
20092   CHECK(CompileRun("'0' in obj")->BooleanValue());
20093   // And these should both fail.
20094   CHECK(!CompileRun("32 in obj")->BooleanValue());
20095   CHECK(!CompileRun("'32' in obj")->BooleanValue());
20096 }
20097
20098
20099 void CheckCodeGenerationAllowed() {
20100   Handle<Value> result = CompileRun("eval('42')");
20101   CHECK_EQ(42, result->Int32Value());
20102   result = CompileRun("(function(e) { return e('42'); })(eval)");
20103   CHECK_EQ(42, result->Int32Value());
20104   result = CompileRun("var f = new Function('return 42'); f()");
20105   CHECK_EQ(42, result->Int32Value());
20106 }
20107
20108
20109 void CheckCodeGenerationDisallowed() {
20110   TryCatch try_catch;
20111
20112   Handle<Value> result = CompileRun("eval('42')");
20113   CHECK(result.IsEmpty());
20114   CHECK(try_catch.HasCaught());
20115   try_catch.Reset();
20116
20117   result = CompileRun("(function(e) { return e('42'); })(eval)");
20118   CHECK(result.IsEmpty());
20119   CHECK(try_catch.HasCaught());
20120   try_catch.Reset();
20121
20122   result = CompileRun("var f = new Function('return 42'); f()");
20123   CHECK(result.IsEmpty());
20124   CHECK(try_catch.HasCaught());
20125 }
20126
20127
20128 bool CodeGenerationAllowed(Local<Context> context) {
20129   ApiTestFuzzer::Fuzz();
20130   return true;
20131 }
20132
20133
20134 bool CodeGenerationDisallowed(Local<Context> context) {
20135   ApiTestFuzzer::Fuzz();
20136   return false;
20137 }
20138
20139
20140 THREADED_TEST(AllowCodeGenFromStrings) {
20141   LocalContext context;
20142   v8::HandleScope scope(context->GetIsolate());
20143
20144   // eval and the Function constructor allowed by default.
20145   CHECK(context->IsCodeGenerationFromStringsAllowed());
20146   CheckCodeGenerationAllowed();
20147
20148   // Disallow eval and the Function constructor.
20149   context->AllowCodeGenerationFromStrings(false);
20150   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20151   CheckCodeGenerationDisallowed();
20152
20153   // Allow again.
20154   context->AllowCodeGenerationFromStrings(true);
20155   CheckCodeGenerationAllowed();
20156
20157   // Disallow but setting a global callback that will allow the calls.
20158   context->AllowCodeGenerationFromStrings(false);
20159   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20160   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20161   CheckCodeGenerationAllowed();
20162
20163   // Set a callback that disallows the code generation.
20164   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20165   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20166   CheckCodeGenerationDisallowed();
20167 }
20168
20169
20170 TEST(SetErrorMessageForCodeGenFromStrings) {
20171   LocalContext context;
20172   v8::HandleScope scope(context->GetIsolate());
20173   TryCatch try_catch;
20174
20175   Handle<String> message = v8_str("Message") ;
20176   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20177   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20178   context->AllowCodeGenerationFromStrings(false);
20179   context->SetErrorMessageForCodeGenerationFromStrings(message);
20180   Handle<Value> result = CompileRun("eval('42')");
20181   CHECK(result.IsEmpty());
20182   CHECK(try_catch.HasCaught());
20183   Handle<String> actual_message = try_catch.Message()->Get();
20184   CHECK(expected_message->Equals(actual_message));
20185 }
20186
20187
20188 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20189 }
20190
20191
20192 THREADED_TEST(CallAPIFunctionOnNonObject) {
20193   LocalContext context;
20194   v8::Isolate* isolate = context->GetIsolate();
20195   v8::HandleScope scope(isolate);
20196   Handle<FunctionTemplate> templ =
20197       v8::FunctionTemplate::New(isolate, NonObjectThis);
20198   Handle<Function> function = templ->GetFunction();
20199   context->Global()->Set(v8_str("f"), function);
20200   TryCatch try_catch;
20201   CompileRun("f.call(2)");
20202 }
20203
20204
20205 // Regression test for issue 1470.
20206 THREADED_TEST(ReadOnlyIndexedProperties) {
20207   v8::Isolate* isolate = CcTest::isolate();
20208   v8::HandleScope scope(isolate);
20209   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20210
20211   LocalContext context;
20212   Local<v8::Object> obj = templ->NewInstance();
20213   context->Global()->Set(v8_str("obj"), obj);
20214   obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20215   obj->Set(v8_str("1"), v8_str("foobar"));
20216   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20217   obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20218   obj->Set(v8_num(2), v8_str("foobar"));
20219   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20220
20221   // Test non-smi case.
20222   obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20223   obj->Set(v8_str("2000000000"), v8_str("foobar"));
20224   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20225 }
20226
20227
20228 THREADED_TEST(Regress1516) {
20229   LocalContext context;
20230   v8::HandleScope scope(context->GetIsolate());
20231
20232   { v8::HandleScope temp_scope(context->GetIsolate());
20233     CompileRun("({'a': 0})");
20234   }
20235
20236   int elements;
20237   { i::MapCache* map_cache =
20238         i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20239     elements = map_cache->NumberOfElements();
20240     CHECK_LE(1, elements);
20241   }
20242
20243   CcTest::heap()->CollectAllGarbage(
20244       i::Heap::kAbortIncrementalMarkingMask);
20245   { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20246     if (raw_map_cache != CcTest::heap()->undefined_value()) {
20247       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20248       CHECK_GT(elements, map_cache->NumberOfElements());
20249     }
20250   }
20251 }
20252
20253
20254 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20255                                                 Local<Value> name,
20256                                                 v8::AccessType type,
20257                                                 Local<Value> data) {
20258   // Only block read access to __proto__.
20259   if (type == v8::ACCESS_GET &&
20260       name->IsString() &&
20261       name->ToString()->Length() == 9 &&
20262       name->ToString()->Utf8Length() == 9) {
20263     char buffer[10];
20264     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20265     return strncmp(buffer, "__proto__", 9) != 0;
20266   }
20267
20268   return true;
20269 }
20270
20271
20272 THREADED_TEST(Regress93759) {
20273   v8::Isolate* isolate = CcTest::isolate();
20274   HandleScope scope(isolate);
20275
20276   // Template for object with security check.
20277   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20278   // We don't do indexing, so any callback can be used for that.
20279   no_proto_template->SetAccessCheckCallbacks(
20280       BlockProtoNamedSecurityTestCallback,
20281       IndexedSecurityTestCallback);
20282
20283   // Templates for objects with hidden prototypes and possibly security check.
20284   Local<FunctionTemplate> hidden_proto_template =
20285       v8::FunctionTemplate::New(isolate);
20286   hidden_proto_template->SetHiddenPrototype(true);
20287
20288   Local<FunctionTemplate> protected_hidden_proto_template =
20289       v8::FunctionTemplate::New(isolate);
20290   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20291       BlockProtoNamedSecurityTestCallback,
20292       IndexedSecurityTestCallback);
20293   protected_hidden_proto_template->SetHiddenPrototype(true);
20294
20295   // Context for "foreign" objects used in test.
20296   Local<Context> context = v8::Context::New(isolate);
20297   context->Enter();
20298
20299   // Plain object, no security check.
20300   Local<Object> simple_object = Object::New(isolate);
20301
20302   // Object with explicit security check.
20303   Local<Object> protected_object =
20304       no_proto_template->NewInstance();
20305
20306   // JSGlobalProxy object, always have security check.
20307   Local<Object> proxy_object =
20308       context->Global();
20309
20310   // Global object, the  prototype of proxy_object. No security checks.
20311   Local<Object> global_object =
20312       proxy_object->GetPrototype()->ToObject();
20313
20314   // Hidden prototype without security check.
20315   Local<Object> hidden_prototype =
20316       hidden_proto_template->GetFunction()->NewInstance();
20317   Local<Object> object_with_hidden =
20318     Object::New(isolate);
20319   object_with_hidden->SetPrototype(hidden_prototype);
20320
20321   // Hidden prototype with security check on the hidden prototype.
20322   Local<Object> protected_hidden_prototype =
20323       protected_hidden_proto_template->GetFunction()->NewInstance();
20324   Local<Object> object_with_protected_hidden =
20325     Object::New(isolate);
20326   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20327
20328   context->Exit();
20329
20330   // Template for object for second context. Values to test are put on it as
20331   // properties.
20332   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20333   global_template->Set(v8_str("simple"), simple_object);
20334   global_template->Set(v8_str("protected"), protected_object);
20335   global_template->Set(v8_str("global"), global_object);
20336   global_template->Set(v8_str("proxy"), proxy_object);
20337   global_template->Set(v8_str("hidden"), object_with_hidden);
20338   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20339
20340   LocalContext context2(NULL, global_template);
20341
20342   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20343   CHECK(result1->Equals(simple_object->GetPrototype()));
20344
20345   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20346   CHECK(result2->Equals(Undefined(isolate)));
20347
20348   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20349   CHECK(result3->Equals(global_object->GetPrototype()));
20350
20351   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20352   CHECK(result4->Equals(Undefined(isolate)));
20353
20354   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20355   CHECK(result5->Equals(
20356       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20357
20358   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20359   CHECK(result6->Equals(Undefined(isolate)));
20360 }
20361
20362
20363 THREADED_TEST(Regress125988) {
20364   v8::HandleScope scope(CcTest::isolate());
20365   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20366   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20367   LocalContext env;
20368   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20369   CompileRun("var a = new Object();"
20370              "var b = new Intercept();"
20371              "var c = new Object();"
20372              "c.__proto__ = b;"
20373              "b.__proto__ = a;"
20374              "a.x = 23;"
20375              "for (var i = 0; i < 3; i++) c.x;");
20376   ExpectBoolean("c.hasOwnProperty('x')", false);
20377   ExpectInt32("c.x", 23);
20378   CompileRun("a.y = 42;"
20379              "for (var i = 0; i < 3; i++) c.x;");
20380   ExpectBoolean("c.hasOwnProperty('x')", false);
20381   ExpectInt32("c.x", 23);
20382   ExpectBoolean("c.hasOwnProperty('y')", false);
20383   ExpectInt32("c.y", 42);
20384 }
20385
20386
20387 static void TestReceiver(Local<Value> expected_result,
20388                          Local<Value> expected_receiver,
20389                          const char* code) {
20390   Local<Value> result = CompileRun(code);
20391   CHECK(result->IsObject());
20392   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20393   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20394 }
20395
20396
20397 THREADED_TEST(ForeignFunctionReceiver) {
20398   v8::Isolate* isolate = CcTest::isolate();
20399   HandleScope scope(isolate);
20400
20401   // Create two contexts with different "id" properties ('i' and 'o').
20402   // Call a function both from its own context and from a the foreign
20403   // context, and see what "this" is bound to (returning both "this"
20404   // and "this.id" for comparison).
20405
20406   Local<Context> foreign_context = v8::Context::New(isolate);
20407   foreign_context->Enter();
20408   Local<Value> foreign_function =
20409     CompileRun("function func() { return { 0: this.id, "
20410                "                           1: this, "
20411                "                           toString: function() { "
20412                "                               return this[0];"
20413                "                           }"
20414                "                         };"
20415                "}"
20416                "var id = 'i';"
20417                "func;");
20418   CHECK(foreign_function->IsFunction());
20419   foreign_context->Exit();
20420
20421   LocalContext context;
20422
20423   Local<String> password = v8_str("Password");
20424   // Don't get hit by security checks when accessing foreign_context's
20425   // global receiver (aka. global proxy).
20426   context->SetSecurityToken(password);
20427   foreign_context->SetSecurityToken(password);
20428
20429   Local<String> i = v8_str("i");
20430   Local<String> o = v8_str("o");
20431   Local<String> id = v8_str("id");
20432
20433   CompileRun("function ownfunc() { return { 0: this.id, "
20434              "                              1: this, "
20435              "                              toString: function() { "
20436              "                                  return this[0];"
20437              "                              }"
20438              "                             };"
20439              "}"
20440              "var id = 'o';"
20441              "ownfunc");
20442   context->Global()->Set(v8_str("func"), foreign_function);
20443
20444   // Sanity check the contexts.
20445   CHECK(i->Equals(foreign_context->Global()->Get(id)));
20446   CHECK(o->Equals(context->Global()->Get(id)));
20447
20448   // Checking local function's receiver.
20449   // Calling function using its call/apply methods.
20450   TestReceiver(o, context->Global(), "ownfunc.call()");
20451   TestReceiver(o, context->Global(), "ownfunc.apply()");
20452   // Making calls through built-in functions.
20453   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20454   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20455   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20456   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20457   // Calling with environment record as base.
20458   TestReceiver(o, context->Global(), "ownfunc()");
20459   // Calling with no base.
20460   TestReceiver(o, context->Global(), "(1,ownfunc)()");
20461
20462   // Checking foreign function return value.
20463   // Calling function using its call/apply methods.
20464   TestReceiver(i, foreign_context->Global(), "func.call()");
20465   TestReceiver(i, foreign_context->Global(), "func.apply()");
20466   // Calling function using another context's call/apply methods.
20467   TestReceiver(i, foreign_context->Global(),
20468                "Function.prototype.call.call(func)");
20469   TestReceiver(i, foreign_context->Global(),
20470                "Function.prototype.call.apply(func)");
20471   TestReceiver(i, foreign_context->Global(),
20472                "Function.prototype.apply.call(func)");
20473   TestReceiver(i, foreign_context->Global(),
20474                "Function.prototype.apply.apply(func)");
20475   // Making calls through built-in functions.
20476   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20477   // ToString(func()) is func()[0], i.e., the returned this.id.
20478   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20479   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20480   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20481
20482   // Calling with environment record as base.
20483   TestReceiver(i, foreign_context->Global(), "func()");
20484   // Calling with no base.
20485   TestReceiver(i, foreign_context->Global(), "(1,func)()");
20486 }
20487
20488
20489 uint8_t callback_fired = 0;
20490
20491
20492 void CallCompletedCallback1() {
20493   i::OS::Print("Firing callback 1.\n");
20494   callback_fired ^= 1;  // Toggle first bit.
20495 }
20496
20497
20498 void CallCompletedCallback2() {
20499   i::OS::Print("Firing callback 2.\n");
20500   callback_fired ^= 2;  // Toggle second bit.
20501 }
20502
20503
20504 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20505   int32_t level = args[0]->Int32Value();
20506   if (level < 3) {
20507     level++;
20508     i::OS::Print("Entering recursion level %d.\n", level);
20509     char script[64];
20510     i::Vector<char> script_vector(script, sizeof(script));
20511     i::OS::SNPrintF(script_vector, "recursion(%d)", level);
20512     CompileRun(script_vector.start());
20513     i::OS::Print("Leaving recursion level %d.\n", level);
20514     CHECK_EQ(0, callback_fired);
20515   } else {
20516     i::OS::Print("Recursion ends.\n");
20517     CHECK_EQ(0, callback_fired);
20518   }
20519 }
20520
20521
20522 TEST(CallCompletedCallback) {
20523   LocalContext env;
20524   v8::HandleScope scope(env->GetIsolate());
20525   v8::Handle<v8::FunctionTemplate> recursive_runtime =
20526       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20527   env->Global()->Set(v8_str("recursion"),
20528                      recursive_runtime->GetFunction());
20529   // Adding the same callback a second time has no effect.
20530   v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20531   v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20532   v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
20533   i::OS::Print("--- Script (1) ---\n");
20534   Local<Script> script = v8::Script::Compile(
20535       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20536   script->Run();
20537   CHECK_EQ(3, callback_fired);
20538
20539   i::OS::Print("\n--- Script (2) ---\n");
20540   callback_fired = 0;
20541   v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
20542   script->Run();
20543   CHECK_EQ(2, callback_fired);
20544
20545   i::OS::Print("\n--- Function ---\n");
20546   callback_fired = 0;
20547   Local<Function> recursive_function =
20548       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20549   v8::Handle<Value> args[] = { v8_num(0) };
20550   recursive_function->Call(env->Global(), 1, args);
20551   CHECK_EQ(2, callback_fired);
20552 }
20553
20554
20555 void CallCompletedCallbackNoException() {
20556   v8::HandleScope scope(CcTest::isolate());
20557   CompileRun("1+1;");
20558 }
20559
20560
20561 void CallCompletedCallbackException() {
20562   v8::HandleScope scope(CcTest::isolate());
20563   CompileRun("throw 'second exception';");
20564 }
20565
20566
20567 TEST(CallCompletedCallbackOneException) {
20568   LocalContext env;
20569   v8::HandleScope scope(env->GetIsolate());
20570   v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
20571   CompileRun("throw 'exception';");
20572 }
20573
20574
20575 TEST(CallCompletedCallbackTwoExceptions) {
20576   LocalContext env;
20577   v8::HandleScope scope(env->GetIsolate());
20578   v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
20579   CompileRun("throw 'first exception';");
20580 }
20581
20582
20583 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20584   v8::HandleScope scope(info.GetIsolate());
20585   CompileRun("ext1Calls++;");
20586 }
20587
20588
20589 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20590   v8::HandleScope scope(info.GetIsolate());
20591   CompileRun("ext2Calls++;");
20592 }
20593
20594
20595 TEST(EnqueueMicrotask) {
20596   LocalContext env;
20597   v8::HandleScope scope(env->GetIsolate());
20598   CompileRun(
20599       "var ext1Calls = 0;"
20600       "var ext2Calls = 0;");
20601   CompileRun("1+1;");
20602   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20603   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20604
20605   v8::V8::EnqueueMicrotask(env->GetIsolate(),
20606                            Function::New(env->GetIsolate(), MicrotaskOne));
20607   CompileRun("1+1;");
20608   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20609   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20610
20611   v8::V8::EnqueueMicrotask(env->GetIsolate(),
20612                            Function::New(env->GetIsolate(), MicrotaskOne));
20613   v8::V8::EnqueueMicrotask(env->GetIsolate(),
20614                            Function::New(env->GetIsolate(), MicrotaskTwo));
20615   CompileRun("1+1;");
20616   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20617   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20618
20619   v8::V8::EnqueueMicrotask(env->GetIsolate(),
20620                            Function::New(env->GetIsolate(), MicrotaskTwo));
20621   CompileRun("1+1;");
20622   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20623   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20624
20625   CompileRun("1+1;");
20626   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20627   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20628 }
20629
20630
20631 TEST(SetAutorunMicrotasks) {
20632   LocalContext env;
20633   v8::HandleScope scope(env->GetIsolate());
20634   CompileRun(
20635       "var ext1Calls = 0;"
20636       "var ext2Calls = 0;");
20637   CompileRun("1+1;");
20638   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20639   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20640
20641   v8::V8::EnqueueMicrotask(env->GetIsolate(),
20642                            Function::New(env->GetIsolate(), MicrotaskOne));
20643   CompileRun("1+1;");
20644   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20645   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20646
20647   V8::SetAutorunMicrotasks(env->GetIsolate(), false);
20648   v8::V8::EnqueueMicrotask(env->GetIsolate(),
20649                            Function::New(env->GetIsolate(), MicrotaskOne));
20650   v8::V8::EnqueueMicrotask(env->GetIsolate(),
20651                            Function::New(env->GetIsolate(), MicrotaskTwo));
20652   CompileRun("1+1;");
20653   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20654   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20655
20656   V8::RunMicrotasks(env->GetIsolate());
20657   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20658   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20659
20660   v8::V8::EnqueueMicrotask(env->GetIsolate(),
20661                            Function::New(env->GetIsolate(), MicrotaskTwo));
20662   CompileRun("1+1;");
20663   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20664   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20665
20666   V8::RunMicrotasks(env->GetIsolate());
20667   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20668   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20669
20670   V8::SetAutorunMicrotasks(env->GetIsolate(), true);
20671   v8::V8::EnqueueMicrotask(env->GetIsolate(),
20672                            Function::New(env->GetIsolate(), MicrotaskTwo));
20673   CompileRun("1+1;");
20674   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20675   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20676 }
20677
20678
20679 static int probes_counter = 0;
20680 static int misses_counter = 0;
20681 static int updates_counter = 0;
20682
20683
20684 static int* LookupCounter(const char* name) {
20685   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20686     return &probes_counter;
20687   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20688     return &misses_counter;
20689   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20690     return &updates_counter;
20691   }
20692   return NULL;
20693 }
20694
20695
20696 static const char* kMegamorphicTestProgram =
20697     "function ClassA() { };"
20698     "function ClassB() { };"
20699     "ClassA.prototype.foo = function() { };"
20700     "ClassB.prototype.foo = function() { };"
20701     "function fooify(obj) { obj.foo(); };"
20702     "var a = new ClassA();"
20703     "var b = new ClassB();"
20704     "for (var i = 0; i < 10000; i++) {"
20705     "  fooify(a);"
20706     "  fooify(b);"
20707     "}";
20708
20709
20710 static void StubCacheHelper(bool primary) {
20711   V8::SetCounterFunction(LookupCounter);
20712   USE(kMegamorphicTestProgram);
20713 #ifdef DEBUG
20714   i::FLAG_native_code_counters = true;
20715   if (primary) {
20716     i::FLAG_test_primary_stub_cache = true;
20717   } else {
20718     i::FLAG_test_secondary_stub_cache = true;
20719   }
20720   i::FLAG_crankshaft = false;
20721   LocalContext env;
20722   v8::HandleScope scope(env->GetIsolate());
20723   int initial_probes = probes_counter;
20724   int initial_misses = misses_counter;
20725   int initial_updates = updates_counter;
20726   CompileRun(kMegamorphicTestProgram);
20727   int probes = probes_counter - initial_probes;
20728   int misses = misses_counter - initial_misses;
20729   int updates = updates_counter - initial_updates;
20730   CHECK_LT(updates, 10);
20731   CHECK_LT(misses, 10);
20732   // TODO(verwaest): Update this test to overflow the degree of polymorphism
20733   // before megamorphism. The number of probes will only work once we teach the
20734   // serializer to embed references to counters in the stubs, given that the
20735   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20736   CHECK_GE(probes, 0);
20737 #endif
20738 }
20739
20740
20741 TEST(SecondaryStubCache) {
20742   StubCacheHelper(true);
20743 }
20744
20745
20746 TEST(PrimaryStubCache) {
20747   StubCacheHelper(false);
20748 }
20749
20750
20751 static int cow_arrays_created_runtime = 0;
20752
20753
20754 static int* LookupCounterCOWArrays(const char* name) {
20755   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20756     return &cow_arrays_created_runtime;
20757   }
20758   return NULL;
20759 }
20760
20761
20762 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20763   V8::SetCounterFunction(LookupCounterCOWArrays);
20764 #ifdef DEBUG
20765   i::FLAG_native_code_counters = true;
20766   LocalContext env;
20767   v8::HandleScope scope(env->GetIsolate());
20768   int initial_cow_arrays = cow_arrays_created_runtime;
20769   CompileRun("var o = [1, 2, 3];");
20770   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20771   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20772   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20773   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20774   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20775 #endif
20776 }
20777
20778
20779 TEST(StaticGetters) {
20780   LocalContext context;
20781   i::Factory* factory = CcTest::i_isolate()->factory();
20782   v8::Isolate* isolate = CcTest::isolate();
20783   v8::HandleScope scope(isolate);
20784   i::Handle<i::Object> undefined_value = factory->undefined_value();
20785   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20786   i::Handle<i::Object> null_value = factory->null_value();
20787   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20788   i::Handle<i::Object> true_value = factory->true_value();
20789   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20790   i::Handle<i::Object> false_value = factory->false_value();
20791   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20792 }
20793
20794
20795 UNINITIALIZED_TEST(IsolateEmbedderData) {
20796   CcTest::DisableAutomaticDispose();
20797   v8::Isolate* isolate = v8::Isolate::New();
20798   isolate->Enter();
20799   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20800   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20801     CHECK_EQ(NULL, isolate->GetData(slot));
20802     CHECK_EQ(NULL, i_isolate->GetData(slot));
20803   }
20804   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20805     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20806     isolate->SetData(slot, data);
20807   }
20808   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20809     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20810     CHECK_EQ(data, isolate->GetData(slot));
20811     CHECK_EQ(data, i_isolate->GetData(slot));
20812   }
20813   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20814     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20815     isolate->SetData(slot, data);
20816   }
20817   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20818     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20819     CHECK_EQ(data, isolate->GetData(slot));
20820     CHECK_EQ(data, i_isolate->GetData(slot));
20821   }
20822   isolate->Exit();
20823   isolate->Dispose();
20824 }
20825
20826
20827 TEST(StringEmpty) {
20828   LocalContext context;
20829   i::Factory* factory = CcTest::i_isolate()->factory();
20830   v8::Isolate* isolate = CcTest::isolate();
20831   v8::HandleScope scope(isolate);
20832   i::Handle<i::Object> empty_string = factory->empty_string();
20833   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
20834 }
20835
20836
20837 static int instance_checked_getter_count = 0;
20838 static void InstanceCheckedGetter(
20839     Local<String> name,
20840     const v8::PropertyCallbackInfo<v8::Value>& info) {
20841   CHECK_EQ(name, v8_str("foo"));
20842   instance_checked_getter_count++;
20843   info.GetReturnValue().Set(v8_num(11));
20844 }
20845
20846
20847 static int instance_checked_setter_count = 0;
20848 static void InstanceCheckedSetter(Local<String> name,
20849                       Local<Value> value,
20850                       const v8::PropertyCallbackInfo<void>& info) {
20851   CHECK_EQ(name, v8_str("foo"));
20852   CHECK_EQ(value, v8_num(23));
20853   instance_checked_setter_count++;
20854 }
20855
20856
20857 static void CheckInstanceCheckedResult(int getters,
20858                                        int setters,
20859                                        bool expects_callbacks,
20860                                        TryCatch* try_catch) {
20861   if (expects_callbacks) {
20862     CHECK(!try_catch->HasCaught());
20863     CHECK_EQ(getters, instance_checked_getter_count);
20864     CHECK_EQ(setters, instance_checked_setter_count);
20865   } else {
20866     CHECK(try_catch->HasCaught());
20867     CHECK_EQ(0, instance_checked_getter_count);
20868     CHECK_EQ(0, instance_checked_setter_count);
20869   }
20870   try_catch->Reset();
20871 }
20872
20873
20874 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
20875   instance_checked_getter_count = 0;
20876   instance_checked_setter_count = 0;
20877   TryCatch try_catch;
20878
20879   // Test path through generic runtime code.
20880   CompileRun("obj.foo");
20881   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
20882   CompileRun("obj.foo = 23");
20883   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
20884
20885   // Test path through generated LoadIC and StoredIC.
20886   CompileRun("function test_get(o) { o.foo; }"
20887              "test_get(obj);");
20888   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
20889   CompileRun("test_get(obj);");
20890   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
20891   CompileRun("test_get(obj);");
20892   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
20893   CompileRun("function test_set(o) { o.foo = 23; }"
20894              "test_set(obj);");
20895   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
20896   CompileRun("test_set(obj);");
20897   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
20898   CompileRun("test_set(obj);");
20899   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
20900
20901   // Test path through optimized code.
20902   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
20903              "test_get(obj);");
20904   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
20905   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
20906              "test_set(obj);");
20907   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
20908
20909   // Cleanup so that closures start out fresh in next check.
20910   CompileRun("%DeoptimizeFunction(test_get);"
20911              "%ClearFunctionTypeFeedback(test_get);"
20912              "%DeoptimizeFunction(test_set);"
20913              "%ClearFunctionTypeFeedback(test_set);");
20914 }
20915
20916
20917 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
20918   v8::internal::FLAG_allow_natives_syntax = true;
20919   LocalContext context;
20920   v8::HandleScope scope(context->GetIsolate());
20921
20922   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20923   Local<ObjectTemplate> inst = templ->InstanceTemplate();
20924   inst->SetAccessor(v8_str("foo"),
20925                     InstanceCheckedGetter, InstanceCheckedSetter,
20926                     Handle<Value>(),
20927                     v8::DEFAULT,
20928                     v8::None,
20929                     v8::AccessorSignature::New(context->GetIsolate(), templ));
20930   context->Global()->Set(v8_str("f"), templ->GetFunction());
20931
20932   printf("Testing positive ...\n");
20933   CompileRun("var obj = new f();");
20934   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20935   CheckInstanceCheckedAccessors(true);
20936
20937   printf("Testing negative ...\n");
20938   CompileRun("var obj = {};"
20939              "obj.__proto__ = new f();");
20940   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20941   CheckInstanceCheckedAccessors(false);
20942 }
20943
20944
20945 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
20946   v8::internal::FLAG_allow_natives_syntax = true;
20947   LocalContext context;
20948   v8::HandleScope scope(context->GetIsolate());
20949
20950   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20951   Local<ObjectTemplate> inst = templ->InstanceTemplate();
20952   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20953   inst->SetAccessor(v8_str("foo"),
20954                     InstanceCheckedGetter, InstanceCheckedSetter,
20955                     Handle<Value>(),
20956                     v8::DEFAULT,
20957                     v8::None,
20958                     v8::AccessorSignature::New(context->GetIsolate(), templ));
20959   context->Global()->Set(v8_str("f"), templ->GetFunction());
20960
20961   printf("Testing positive ...\n");
20962   CompileRun("var obj = new f();");
20963   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20964   CheckInstanceCheckedAccessors(true);
20965
20966   printf("Testing negative ...\n");
20967   CompileRun("var obj = {};"
20968              "obj.__proto__ = new f();");
20969   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20970   CheckInstanceCheckedAccessors(false);
20971 }
20972
20973
20974 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
20975   v8::internal::FLAG_allow_natives_syntax = true;
20976   LocalContext context;
20977   v8::HandleScope scope(context->GetIsolate());
20978
20979   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20980   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
20981   proto->SetAccessor(v8_str("foo"),
20982                      InstanceCheckedGetter, InstanceCheckedSetter,
20983                      Handle<Value>(),
20984                      v8::DEFAULT,
20985                      v8::None,
20986                      v8::AccessorSignature::New(context->GetIsolate(), templ));
20987   context->Global()->Set(v8_str("f"), templ->GetFunction());
20988
20989   printf("Testing positive ...\n");
20990   CompileRun("var obj = new f();");
20991   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20992   CheckInstanceCheckedAccessors(true);
20993
20994   printf("Testing negative ...\n");
20995   CompileRun("var obj = {};"
20996              "obj.__proto__ = new f();");
20997   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20998   CheckInstanceCheckedAccessors(false);
20999
21000   printf("Testing positive with modified prototype chain ...\n");
21001   CompileRun("var obj = new f();"
21002              "var pro = {};"
21003              "pro.__proto__ = obj.__proto__;"
21004              "obj.__proto__ = pro;");
21005   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21006   CheckInstanceCheckedAccessors(true);
21007 }
21008
21009
21010 TEST(TryFinallyMessage) {
21011   LocalContext context;
21012   v8::HandleScope scope(context->GetIsolate());
21013   {
21014     // Test that the original error message is not lost if there is a
21015     // recursive call into Javascript is done in the finally block, e.g. to
21016     // initialize an IC. (crbug.com/129171)
21017     TryCatch try_catch;
21018     const char* trigger_ic =
21019         "try {                      \n"
21020         "  throw new Error('test'); \n"
21021         "} finally {                \n"
21022         "  var x = 0;               \n"
21023         "  x++;                     \n"  // Trigger an IC initialization here.
21024         "}                          \n";
21025     CompileRun(trigger_ic);
21026     CHECK(try_catch.HasCaught());
21027     Local<Message> message = try_catch.Message();
21028     CHECK(!message.IsEmpty());
21029     CHECK_EQ(2, message->GetLineNumber());
21030   }
21031
21032   {
21033     // Test that the original exception message is indeed overwritten if
21034     // a new error is thrown in the finally block.
21035     TryCatch try_catch;
21036     const char* throw_again =
21037         "try {                       \n"
21038         "  throw new Error('test');  \n"
21039         "} finally {                 \n"
21040         "  var x = 0;                \n"
21041         "  x++;                      \n"
21042         "  throw new Error('again'); \n"  // This is the new uncaught error.
21043         "}                           \n";
21044     CompileRun(throw_again);
21045     CHECK(try_catch.HasCaught());
21046     Local<Message> message = try_catch.Message();
21047     CHECK(!message.IsEmpty());
21048     CHECK_EQ(6, message->GetLineNumber());
21049   }
21050 }
21051
21052
21053 static void Helper137002(bool do_store,
21054                          bool polymorphic,
21055                          bool remove_accessor,
21056                          bool interceptor) {
21057   LocalContext context;
21058   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21059   if (interceptor) {
21060     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21061   } else {
21062     templ->SetAccessor(v8_str("foo"),
21063                        GetterWhichReturns42,
21064                        SetterWhichSetsYOnThisTo23);
21065   }
21066   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21067
21068   // Turn monomorphic on slow object with native accessor, then turn
21069   // polymorphic, finally optimize to create negative lookup and fail.
21070   CompileRun(do_store ?
21071              "function f(x) { x.foo = void 0; }" :
21072              "function f(x) { return x.foo; }");
21073   CompileRun("obj.y = void 0;");
21074   if (!interceptor) {
21075     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21076   }
21077   CompileRun("obj.__proto__ = null;"
21078              "f(obj); f(obj); f(obj);");
21079   if (polymorphic) {
21080     CompileRun("f({});");
21081   }
21082   CompileRun("obj.y = void 0;"
21083              "%OptimizeFunctionOnNextCall(f);");
21084   if (remove_accessor) {
21085     CompileRun("delete obj.foo;");
21086   }
21087   CompileRun("var result = f(obj);");
21088   if (do_store) {
21089     CompileRun("result = obj.y;");
21090   }
21091   if (remove_accessor && !interceptor) {
21092     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21093   } else {
21094     CHECK_EQ(do_store ? 23 : 42,
21095              context->Global()->Get(v8_str("result"))->Int32Value());
21096   }
21097 }
21098
21099
21100 THREADED_TEST(Regress137002a) {
21101   i::FLAG_allow_natives_syntax = true;
21102   i::FLAG_compilation_cache = false;
21103   v8::HandleScope scope(CcTest::isolate());
21104   for (int i = 0; i < 16; i++) {
21105     Helper137002(i & 8, i & 4, i & 2, i & 1);
21106   }
21107 }
21108
21109
21110 THREADED_TEST(Regress137002b) {
21111   i::FLAG_allow_natives_syntax = true;
21112   LocalContext context;
21113   v8::Isolate* isolate = context->GetIsolate();
21114   v8::HandleScope scope(isolate);
21115   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21116   templ->SetAccessor(v8_str("foo"),
21117                      GetterWhichReturns42,
21118                      SetterWhichSetsYOnThisTo23);
21119   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21120
21121   // Turn monomorphic on slow object with native accessor, then just
21122   // delete the property and fail.
21123   CompileRun("function load(x) { return x.foo; }"
21124              "function store(x) { x.foo = void 0; }"
21125              "function keyed_load(x, key) { return x[key]; }"
21126              // Second version of function has a different source (add void 0)
21127              // so that it does not share code with the first version.  This
21128              // ensures that the ICs are monomorphic.
21129              "function load2(x) { void 0; return x.foo; }"
21130              "function store2(x) { void 0; x.foo = void 0; }"
21131              "function keyed_load2(x, key) { void 0; return x[key]; }"
21132
21133              "obj.y = void 0;"
21134              "obj.__proto__ = null;"
21135              "var subobj = {};"
21136              "subobj.y = void 0;"
21137              "subobj.__proto__ = obj;"
21138              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21139
21140              // Make the ICs monomorphic.
21141              "load(obj); load(obj);"
21142              "load2(subobj); load2(subobj);"
21143              "store(obj); store(obj);"
21144              "store2(subobj); store2(subobj);"
21145              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21146              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21147
21148              // Actually test the shiny new ICs and better not crash. This
21149              // serves as a regression test for issue 142088 as well.
21150              "load(obj);"
21151              "load2(subobj);"
21152              "store(obj);"
21153              "store2(subobj);"
21154              "keyed_load(obj, 'foo');"
21155              "keyed_load2(subobj, 'foo');"
21156
21157              // Delete the accessor.  It better not be called any more now.
21158              "delete obj.foo;"
21159              "obj.y = void 0;"
21160              "subobj.y = void 0;"
21161
21162              "var load_result = load(obj);"
21163              "var load_result2 = load2(subobj);"
21164              "var keyed_load_result = keyed_load(obj, 'foo');"
21165              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21166              "store(obj);"
21167              "store2(subobj);"
21168              "var y_from_obj = obj.y;"
21169              "var y_from_subobj = subobj.y;");
21170   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21171   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21172   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21173   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21174   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21175   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21176 }
21177
21178
21179 THREADED_TEST(Regress142088) {
21180   i::FLAG_allow_natives_syntax = true;
21181   LocalContext context;
21182   v8::Isolate* isolate = context->GetIsolate();
21183   v8::HandleScope scope(isolate);
21184   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21185   templ->SetAccessor(v8_str("foo"),
21186                      GetterWhichReturns42,
21187                      SetterWhichSetsYOnThisTo23);
21188   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21189
21190   CompileRun("function load(x) { return x.foo; }"
21191              "var o = Object.create(obj);"
21192              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21193              "load(o); load(o); load(o); load(o);");
21194 }
21195
21196
21197 THREADED_TEST(Regress137496) {
21198   i::FLAG_expose_gc = true;
21199   LocalContext context;
21200   v8::HandleScope scope(context->GetIsolate());
21201
21202   // Compile a try-finally clause where the finally block causes a GC
21203   // while there still is a message pending for external reporting.
21204   TryCatch try_catch;
21205   try_catch.SetVerbose(true);
21206   CompileRun("try { throw new Error(); } finally { gc(); }");
21207   CHECK(try_catch.HasCaught());
21208 }
21209
21210
21211 THREADED_TEST(Regress149912) {
21212   LocalContext context;
21213   v8::HandleScope scope(context->GetIsolate());
21214   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21215   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21216   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21217   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21218 }
21219
21220
21221 THREADED_TEST(Regress157124) {
21222   LocalContext context;
21223   v8::Isolate* isolate = context->GetIsolate();
21224   v8::HandleScope scope(isolate);
21225   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21226   Local<Object> obj = templ->NewInstance();
21227   obj->GetIdentityHash();
21228   obj->DeleteHiddenValue(v8_str("Bug"));
21229 }
21230
21231
21232 THREADED_TEST(Regress2535) {
21233   i::FLAG_harmony_collections = true;
21234   LocalContext context;
21235   v8::HandleScope scope(context->GetIsolate());
21236   Local<Value> set_value = CompileRun("new Set();");
21237   Local<Object> set_object(Local<Object>::Cast(set_value));
21238   CHECK_EQ(0, set_object->InternalFieldCount());
21239   Local<Value> map_value = CompileRun("new Map();");
21240   Local<Object> map_object(Local<Object>::Cast(map_value));
21241   CHECK_EQ(0, map_object->InternalFieldCount());
21242 }
21243
21244
21245 THREADED_TEST(Regress2746) {
21246   LocalContext context;
21247   v8::Isolate* isolate = context->GetIsolate();
21248   v8::HandleScope scope(isolate);
21249   Local<Object> obj = Object::New(isolate);
21250   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21251   obj->SetHiddenValue(key, v8::Undefined(isolate));
21252   Local<Value> value = obj->GetHiddenValue(key);
21253   CHECK(!value.IsEmpty());
21254   CHECK(value->IsUndefined());
21255 }
21256
21257
21258 THREADED_TEST(Regress260106) {
21259   LocalContext context;
21260   v8::Isolate* isolate = context->GetIsolate();
21261   v8::HandleScope scope(isolate);
21262   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21263                                                         DummyCallHandler);
21264   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21265   Local<Function> function = templ->GetFunction();
21266   CHECK(!function.IsEmpty());
21267   CHECK(function->IsFunction());
21268 }
21269
21270
21271 THREADED_TEST(JSONParseObject) {
21272   LocalContext context;
21273   HandleScope scope(context->GetIsolate());
21274   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21275   Handle<Object> global = context->Global();
21276   global->Set(v8_str("obj"), obj);
21277   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21278 }
21279
21280
21281 THREADED_TEST(JSONParseNumber) {
21282   LocalContext context;
21283   HandleScope scope(context->GetIsolate());
21284   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21285   Handle<Object> global = context->Global();
21286   global->Set(v8_str("obj"), obj);
21287   ExpectString("JSON.stringify(obj)", "42");
21288 }
21289
21290
21291 #if V8_OS_POSIX
21292 class ThreadInterruptTest {
21293  public:
21294   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21295   ~ThreadInterruptTest() {}
21296
21297   void RunTest() {
21298     InterruptThread i_thread(this);
21299     i_thread.Start();
21300
21301     sem_.Wait();
21302     CHECK_EQ(kExpectedValue, sem_value_);
21303   }
21304
21305  private:
21306   static const int kExpectedValue = 1;
21307
21308   class InterruptThread : public i::Thread {
21309    public:
21310     explicit InterruptThread(ThreadInterruptTest* test)
21311         : Thread("InterruptThread"), test_(test) {}
21312
21313     virtual void Run() {
21314       struct sigaction action;
21315
21316       // Ensure that we'll enter waiting condition
21317       i::OS::Sleep(100);
21318
21319       // Setup signal handler
21320       memset(&action, 0, sizeof(action));
21321       action.sa_handler = SignalHandler;
21322       sigaction(SIGCHLD, &action, NULL);
21323
21324       // Send signal
21325       kill(getpid(), SIGCHLD);
21326
21327       // Ensure that if wait has returned because of error
21328       i::OS::Sleep(100);
21329
21330       // Set value and signal semaphore
21331       test_->sem_value_ = 1;
21332       test_->sem_.Signal();
21333     }
21334
21335     static void SignalHandler(int signal) {
21336     }
21337
21338    private:
21339      ThreadInterruptTest* test_;
21340   };
21341
21342   i::Semaphore sem_;
21343   volatile int sem_value_;
21344 };
21345
21346
21347 THREADED_TEST(SemaphoreInterruption) {
21348   ThreadInterruptTest().RunTest();
21349 }
21350
21351
21352 #endif  // V8_OS_POSIX
21353
21354
21355 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21356                                      Local<Value> name,
21357                                      v8::AccessType type,
21358                                      Local<Value> data) {
21359   i::PrintF("Named access blocked.\n");
21360   return false;
21361 }
21362
21363
21364 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21365                                      uint32_t key,
21366                                      v8::AccessType type,
21367                                      Local<Value> data) {
21368   i::PrintF("Indexed access blocked.\n");
21369   return false;
21370 }
21371
21372
21373 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21374   CHECK(false);
21375 }
21376
21377
21378 TEST(JSONStringifyAccessCheck) {
21379   v8::V8::Initialize();
21380   v8::Isolate* isolate = CcTest::isolate();
21381   v8::HandleScope scope(isolate);
21382
21383   // Create an ObjectTemplate for global objects and install access
21384   // check callbacks that will block access.
21385   v8::Handle<v8::ObjectTemplate> global_template =
21386       v8::ObjectTemplate::New(isolate);
21387   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21388                                            IndexAccessAlwaysBlocked);
21389
21390   // Create a context and set an x property on it's global object.
21391   LocalContext context0(NULL, global_template);
21392   v8::Handle<v8::Object> global0 = context0->Global();
21393   global0->Set(v8_str("x"), v8_num(42));
21394   ExpectString("JSON.stringify(this)", "{\"x\":42}");
21395
21396   for (int i = 0; i < 2; i++) {
21397     if (i == 1) {
21398       // Install a toJSON function on the second run.
21399       v8::Handle<v8::FunctionTemplate> toJSON =
21400           v8::FunctionTemplate::New(isolate, UnreachableCallback);
21401
21402       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21403     }
21404     // Create a context with a different security token so that the
21405     // failed access check callback will be called on each access.
21406     LocalContext context1(NULL, global_template);
21407     context1->Global()->Set(v8_str("other"), global0);
21408
21409     ExpectString("JSON.stringify(other)", "{}");
21410     ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21411                  "{\"a\":{},\"b\":[\"c\"]}");
21412     ExpectString("JSON.stringify([other, 'b', 'c'])",
21413                  "[{},\"b\",\"c\"]");
21414
21415     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21416     array->Set(0, v8_str("a"));
21417     array->Set(1, v8_str("b"));
21418     context1->Global()->Set(v8_str("array"), array);
21419     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21420     array->TurnOnAccessCheck();
21421     ExpectString("JSON.stringify(array)", "[]");
21422     ExpectString("JSON.stringify([array])", "[[]]");
21423     ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21424   }
21425 }
21426
21427
21428 bool access_check_fail_thrown = false;
21429 bool catch_callback_called = false;
21430
21431
21432 // Failed access check callback that performs a GC on each invocation.
21433 void FailedAccessCheckThrows(Local<v8::Object> target,
21434                              v8::AccessType type,
21435                              Local<v8::Value> data) {
21436   access_check_fail_thrown = true;
21437   i::PrintF("Access check failed. Error thrown.\n");
21438   CcTest::isolate()->ThrowException(
21439       v8::Exception::Error(v8_str("cross context")));
21440 }
21441
21442
21443 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21444   for (int i = 0; i < args.Length(); i++) {
21445     i::PrintF("%s\n", *String::Utf8Value(args[i]));
21446   }
21447   catch_callback_called = true;
21448 }
21449
21450
21451 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21452   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21453 }
21454
21455
21456 void CheckCorrectThrow(const char* script) {
21457   // Test that the script, when wrapped into a try-catch, triggers the catch
21458   // clause due to failed access check throwing an exception.
21459   // The subsequent try-catch should run without any exception.
21460   access_check_fail_thrown = false;
21461   catch_callback_called = false;
21462   i::ScopedVector<char> source(1024);
21463   i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21464   CompileRun(source.start());
21465   CHECK(access_check_fail_thrown);
21466   CHECK(catch_callback_called);
21467
21468   access_check_fail_thrown = false;
21469   catch_callback_called = false;
21470   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21471   CHECK(!access_check_fail_thrown);
21472   CHECK(!catch_callback_called);
21473 }
21474
21475
21476 TEST(AccessCheckThrows) {
21477   i::FLAG_allow_natives_syntax = true;
21478   v8::V8::Initialize();
21479   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21480   v8::Isolate* isolate = CcTest::isolate();
21481   v8::HandleScope scope(isolate);
21482
21483   // Create an ObjectTemplate for global objects and install access
21484   // check callbacks that will block access.
21485   v8::Handle<v8::ObjectTemplate> global_template =
21486       v8::ObjectTemplate::New(isolate);
21487   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21488                                            IndexAccessAlwaysBlocked);
21489
21490   // Create a context and set an x property on it's global object.
21491   LocalContext context0(NULL, global_template);
21492   context0->Global()->Set(v8_str("x"), v8_num(42));
21493   v8::Handle<v8::Object> global0 = context0->Global();
21494
21495   // Create a context with a different security token so that the
21496   // failed access check callback will be called on each access.
21497   LocalContext context1(NULL, global_template);
21498   context1->Global()->Set(v8_str("other"), global0);
21499
21500   v8::Handle<v8::FunctionTemplate> catcher_fun =
21501       v8::FunctionTemplate::New(isolate, CatcherCallback);
21502   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21503
21504   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21505       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21506   context1->Global()->Set(v8_str("has_own_property"),
21507                           has_own_property_fun->GetFunction());
21508
21509   { v8::TryCatch try_catch;
21510     access_check_fail_thrown = false;
21511     CompileRun("other.x;");
21512     CHECK(access_check_fail_thrown);
21513     CHECK(try_catch.HasCaught());
21514   }
21515
21516   CheckCorrectThrow("other.x");
21517   CheckCorrectThrow("other[1]");
21518   CheckCorrectThrow("JSON.stringify(other)");
21519   CheckCorrectThrow("has_own_property(other, 'x')");
21520   CheckCorrectThrow("%GetProperty(other, 'x')");
21521   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21522   CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21523   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21524   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21525   CheckCorrectThrow("%HasLocalProperty(other, 'x')");
21526   CheckCorrectThrow("%HasProperty(other, 'x')");
21527   CheckCorrectThrow("%HasElement(other, 1)");
21528   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21529   CheckCorrectThrow("%GetPropertyNames(other)");
21530   // PROPERTY_ATTRIBUTES_NONE = 0
21531   CheckCorrectThrow("%GetLocalPropertyNames(other, 0)");
21532   CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21533                         "other, 'x', null, null, 1)");
21534
21535   // Reset the failed access check callback so it does not influence
21536   // the other tests.
21537   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21538 }
21539
21540
21541 THREADED_TEST(Regress256330) {
21542   i::FLAG_allow_natives_syntax = true;
21543   LocalContext context;
21544   v8::HandleScope scope(context->GetIsolate());
21545   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21546   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21547   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21548   CompileRun("\"use strict\"; var o = new Bug;"
21549              "function f(o) { o.x = 10; };"
21550              "f(o); f(o); f(o);"
21551              "%OptimizeFunctionOnNextCall(f);"
21552              "f(o);");
21553   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21554 }
21555
21556
21557 THREADED_TEST(CrankshaftInterceptorSetter) {
21558   i::FLAG_allow_natives_syntax = true;
21559   v8::HandleScope scope(CcTest::isolate());
21560   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21561   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21562   LocalContext env;
21563   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21564   CompileRun("var obj = new Obj;"
21565              // Initialize fields to avoid transitions later.
21566              "obj.age = 0;"
21567              "obj.accessor_age = 42;"
21568              "function setter(i) { this.accessor_age = i; };"
21569              "function getter() { return this.accessor_age; };"
21570              "function setAge(i) { obj.age = i; };"
21571              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21572              "setAge(1);"
21573              "setAge(2);"
21574              "setAge(3);"
21575              "%OptimizeFunctionOnNextCall(setAge);"
21576              "setAge(4);");
21577   // All stores went through the interceptor.
21578   ExpectInt32("obj.interceptor_age", 4);
21579   ExpectInt32("obj.accessor_age", 42);
21580 }
21581
21582
21583 THREADED_TEST(CrankshaftInterceptorGetter) {
21584   i::FLAG_allow_natives_syntax = true;
21585   v8::HandleScope scope(CcTest::isolate());
21586   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21587   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21588   LocalContext env;
21589   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21590   CompileRun("var obj = new Obj;"
21591              // Initialize fields to avoid transitions later.
21592              "obj.age = 1;"
21593              "obj.accessor_age = 42;"
21594              "function getter() { return this.accessor_age; };"
21595              "function getAge() { return obj.interceptor_age; };"
21596              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21597              "getAge();"
21598              "getAge();"
21599              "getAge();"
21600              "%OptimizeFunctionOnNextCall(getAge);");
21601   // Access through interceptor.
21602   ExpectInt32("getAge()", 1);
21603 }
21604
21605
21606 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21607   i::FLAG_allow_natives_syntax = true;
21608   v8::HandleScope scope(CcTest::isolate());
21609   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21610   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21611   LocalContext env;
21612   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21613   CompileRun("var obj = new Obj;"
21614              "obj.__proto__.interceptor_age = 42;"
21615              "obj.age = 100;"
21616              "function getAge() { return obj.interceptor_age; };");
21617   ExpectInt32("getAge();", 100);
21618   ExpectInt32("getAge();", 100);
21619   ExpectInt32("getAge();", 100);
21620   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21621   // Access through interceptor.
21622   ExpectInt32("getAge();", 100);
21623 }
21624
21625
21626 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21627   i::FLAG_allow_natives_syntax = true;
21628   v8::HandleScope scope(CcTest::isolate());
21629   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21630   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21631   LocalContext env;
21632   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21633   CompileRun("var obj = new Obj;"
21634              "obj.age = 100000;"
21635              "function setAge(i) { obj.age = i };"
21636              "setAge(100);"
21637              "setAge(101);"
21638              "setAge(102);"
21639              "%OptimizeFunctionOnNextCall(setAge);"
21640              "setAge(103);");
21641   ExpectInt32("obj.age", 100000);
21642   ExpectInt32("obj.interceptor_age", 103);
21643 }
21644
21645
21646 class RequestInterruptTestBase {
21647  public:
21648   RequestInterruptTestBase()
21649       : env_(),
21650         isolate_(env_->GetIsolate()),
21651         sem_(0),
21652         warmup_(20000),
21653         should_continue_(true) {
21654   }
21655
21656   virtual ~RequestInterruptTestBase() { }
21657
21658   virtual void TestBody() = 0;
21659
21660   void RunTest() {
21661     InterruptThread i_thread(this);
21662     i_thread.Start();
21663
21664     v8::HandleScope handle_scope(isolate_);
21665
21666     TestBody();
21667
21668     isolate_->ClearInterrupt();
21669
21670     // Verify we arrived here because interruptor was called
21671     // not due to a bug causing us to exit the loop too early.
21672     CHECK(!should_continue());
21673   }
21674
21675   void WakeUpInterruptor() {
21676     sem_.Signal();
21677   }
21678
21679   bool should_continue() const { return should_continue_; }
21680
21681   bool ShouldContinue() {
21682     if (warmup_ > 0) {
21683       if (--warmup_ == 0) {
21684         WakeUpInterruptor();
21685       }
21686     }
21687
21688     return should_continue_;
21689   }
21690
21691  protected:
21692   static void ShouldContinueCallback(
21693       const v8::FunctionCallbackInfo<Value>& info) {
21694     RequestInterruptTestBase* test =
21695         reinterpret_cast<RequestInterruptTestBase*>(
21696             info.Data().As<v8::External>()->Value());
21697     info.GetReturnValue().Set(test->ShouldContinue());
21698   }
21699
21700   class InterruptThread : public i::Thread {
21701    public:
21702     explicit InterruptThread(RequestInterruptTestBase* test)
21703         : Thread("RequestInterruptTest"), test_(test) {}
21704
21705     virtual void Run() {
21706       test_->sem_.Wait();
21707       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21708     }
21709
21710     static void OnInterrupt(v8::Isolate* isolate, void* data) {
21711       reinterpret_cast<RequestInterruptTestBase*>(data)->
21712           should_continue_ = false;
21713     }
21714
21715    private:
21716      RequestInterruptTestBase* test_;
21717   };
21718
21719   LocalContext env_;
21720   v8::Isolate* isolate_;
21721   i::Semaphore sem_;
21722   int warmup_;
21723   bool should_continue_;
21724 };
21725
21726
21727 class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase {
21728  public:
21729   virtual void TestBody() {
21730     Local<Function> func = Function::New(
21731         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21732     env_->Global()->Set(v8_str("ShouldContinue"), func);
21733
21734     CompileRun("while (ShouldContinue()) { }");
21735   }
21736 };
21737
21738
21739 class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase {
21740  public:
21741   virtual void TestBody() {
21742     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21743     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21744     proto->Set(v8_str("shouldContinue"), Function::New(
21745         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21746     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21747
21748     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21749   }
21750 };
21751
21752
21753 class RequestInterruptTestWithAccessor : public RequestInterruptTestBase {
21754  public:
21755   virtual void TestBody() {
21756     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21757     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21758     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21759         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21760     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21761
21762     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21763   }
21764 };
21765
21766
21767 class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase {
21768  public:
21769   virtual void TestBody() {
21770     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21771     t->InstanceTemplate()->SetNativeDataProperty(
21772         v8_str("shouldContinue"),
21773         &ShouldContinueNativeGetter,
21774         NULL,
21775         v8::External::New(isolate_, this));
21776     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21777
21778     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21779   }
21780
21781  private:
21782   static void ShouldContinueNativeGetter(
21783       Local<String> property,
21784       const v8::PropertyCallbackInfo<v8::Value>& info) {
21785     RequestInterruptTestBase* test =
21786         reinterpret_cast<RequestInterruptTestBase*>(
21787             info.Data().As<v8::External>()->Value());
21788     info.GetReturnValue().Set(test->ShouldContinue());
21789   }
21790 };
21791
21792
21793 class RequestInterruptTestWithMethodCallAndInterceptor
21794     : public RequestInterruptTestBase {
21795  public:
21796   virtual void TestBody() {
21797     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21798     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21799     proto->Set(v8_str("shouldContinue"), Function::New(
21800         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21801     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
21802     instance_template->SetNamedPropertyHandler(EmptyInterceptor);
21803
21804     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21805
21806     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21807   }
21808
21809  private:
21810   static void EmptyInterceptor(
21811       Local<String> property,
21812       const v8::PropertyCallbackInfo<v8::Value>& info) {
21813   }
21814 };
21815
21816
21817 class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase {
21818  public:
21819   virtual void TestBody() {
21820     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
21821         isolate_,
21822         WakeUpInterruptorCallback,
21823         v8::External::New(isolate_, this)));
21824
21825     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
21826         isolate_,
21827         ShouldContinueCallback,
21828         v8::External::New(isolate_, this)));
21829
21830     i::FLAG_allow_natives_syntax = true;
21831     CompileRun("function loopish(o) {"
21832                "  var pre = 10;"
21833                "  while (o.abs(1) > 0) {"
21834                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
21835                "    if (pre > 0) {"
21836                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
21837                "    }"
21838                "  }"
21839                "}"
21840                "var i = 50;"
21841                "var obj = {abs: function () { return i-- }, x: null};"
21842                "delete obj.x;"
21843                "loopish(obj);"
21844                "%OptimizeFunctionOnNextCall(loopish);"
21845                "loopish(Math);");
21846
21847     i::FLAG_allow_natives_syntax = false;
21848   }
21849
21850  private:
21851   static void WakeUpInterruptorCallback(
21852       const v8::FunctionCallbackInfo<Value>& info) {
21853     if (!info[0]->BooleanValue()) return;
21854
21855     RequestInterruptTestBase* test =
21856         reinterpret_cast<RequestInterruptTestBase*>(
21857             info.Data().As<v8::External>()->Value());
21858     test->WakeUpInterruptor();
21859   }
21860
21861   static void ShouldContinueCallback(
21862       const v8::FunctionCallbackInfo<Value>& info) {
21863     RequestInterruptTestBase* test =
21864         reinterpret_cast<RequestInterruptTestBase*>(
21865             info.Data().As<v8::External>()->Value());
21866     info.GetReturnValue().Set(test->should_continue());
21867   }
21868 };
21869
21870
21871 TEST(RequestInterruptTestWithFunctionCall) {
21872   RequestInterruptTestWithFunctionCall().RunTest();
21873 }
21874
21875
21876 TEST(RequestInterruptTestWithMethodCall) {
21877   RequestInterruptTestWithMethodCall().RunTest();
21878 }
21879
21880
21881 TEST(RequestInterruptTestWithAccessor) {
21882   RequestInterruptTestWithAccessor().RunTest();
21883 }
21884
21885
21886 TEST(RequestInterruptTestWithNativeAccessor) {
21887   RequestInterruptTestWithNativeAccessor().RunTest();
21888 }
21889
21890
21891 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
21892   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
21893 }
21894
21895
21896 TEST(RequestInterruptTestWithMathAbs) {
21897   RequestInterruptTestWithMathAbs().RunTest();
21898 }
21899
21900
21901 static Local<Value> function_new_expected_env;
21902 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
21903   CHECK_EQ(function_new_expected_env, info.Data());
21904   info.GetReturnValue().Set(17);
21905 }
21906
21907
21908 THREADED_TEST(FunctionNew) {
21909   LocalContext env;
21910   v8::Isolate* isolate = env->GetIsolate();
21911   v8::HandleScope scope(isolate);
21912   Local<Object> data = v8::Object::New(isolate);
21913   function_new_expected_env = data;
21914   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
21915   env->Global()->Set(v8_str("func"), func);
21916   Local<Value> result = CompileRun("func();");
21917   CHECK_EQ(v8::Integer::New(isolate, 17), result);
21918   // Verify function not cached
21919   int serial_number =
21920       i::Smi::cast(v8::Utils::OpenHandle(*func)
21921           ->shared()->get_api_func_data()->serial_number())->value();
21922   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21923   i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
21924   i::Handle<i::Object> elm =
21925       i::Object::GetElementNoExceptionThrown(i_isolate, cache, serial_number);
21926   CHECK(elm->IsUndefined());
21927   // Verify that each Function::New creates a new function instance
21928   Local<Object> data2 = v8::Object::New(isolate);
21929   function_new_expected_env = data2;
21930   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
21931   CHECK(!func2->IsNull());
21932   CHECK_NE(func, func2);
21933   env->Global()->Set(v8_str("func2"), func2);
21934   Local<Value> result2 = CompileRun("func2();");
21935   CHECK_EQ(v8::Integer::New(isolate, 17), result2);
21936 }
21937
21938
21939 TEST(EscapeableHandleScope) {
21940   HandleScope outer_scope(CcTest::isolate());
21941   LocalContext context;
21942   const int runs = 10;
21943   Local<String> values[runs];
21944   for (int i = 0; i < runs; i++) {
21945     v8::EscapableHandleScope inner_scope(CcTest::isolate());
21946     Local<String> value;
21947     if (i != 0) value = v8_str("escape value");
21948     values[i] = inner_scope.Escape(value);
21949   }
21950   for (int i = 0; i < runs; i++) {
21951     Local<String> expected;
21952     if (i != 0) {
21953       CHECK_EQ(v8_str("escape value"), values[i]);
21954     } else {
21955       CHECK(values[i].IsEmpty());
21956     }
21957   }
21958 }
21959
21960
21961 static void SetterWhichExpectsThisAndHolderToDiffer(
21962     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
21963   CHECK(info.Holder() != info.This());
21964 }
21965
21966
21967 TEST(Regress239669) {
21968   LocalContext context;
21969   v8::Isolate* isolate = context->GetIsolate();
21970   v8::HandleScope scope(isolate);
21971   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21972   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
21973   context->Global()->Set(v8_str("P"), templ->NewInstance());
21974   CompileRun(
21975       "function C1() {"
21976       "  this.x = 23;"
21977       "};"
21978       "C1.prototype = P;"
21979       "for (var i = 0; i < 4; i++ ) {"
21980       "  new C1();"
21981       "}");
21982 }
21983
21984
21985 class ApiCallOptimizationChecker {
21986  private:
21987   static Local<Object> data;
21988   static Local<Object> receiver;
21989   static Local<Object> holder;
21990   static Local<Object> callee;
21991   static int count;
21992
21993   static void OptimizationCallback(
21994       const v8::FunctionCallbackInfo<v8::Value>& info) {
21995     CHECK(callee == info.Callee());
21996     CHECK(data == info.Data());
21997     CHECK(receiver == info.This());
21998     if (info.Length() == 1) {
21999       CHECK_EQ(v8_num(1), info[0]);
22000     }
22001     CHECK(holder == info.Holder());
22002     count++;
22003     info.GetReturnValue().Set(v8_str("returned"));
22004   }
22005
22006   public:
22007     enum SignatureType {
22008       kNoSignature,
22009       kSignatureOnReceiver,
22010       kSignatureOnPrototype
22011     };
22012
22013     void RunAll() {
22014       SignatureType signature_types[] =
22015         {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22016       for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) {
22017         SignatureType signature_type = signature_types[i];
22018         for (int j = 0; j < 2; j++) {
22019           bool global = j == 0;
22020           int key = signature_type +
22021               ARRAY_SIZE(signature_types) * (global ? 1 : 0);
22022           Run(signature_type, global, key);
22023         }
22024       }
22025     }
22026
22027     void Run(SignatureType signature_type, bool global, int key) {
22028       v8::Isolate* isolate = CcTest::isolate();
22029       v8::HandleScope scope(isolate);
22030       // Build a template for signature checks.
22031       Local<v8::ObjectTemplate> signature_template;
22032       Local<v8::Signature> signature;
22033       {
22034         Local<v8::FunctionTemplate> parent_template =
22035           FunctionTemplate::New(isolate);
22036         parent_template->SetHiddenPrototype(true);
22037         Local<v8::FunctionTemplate> function_template
22038             = FunctionTemplate::New(isolate);
22039         function_template->Inherit(parent_template);
22040         switch (signature_type) {
22041           case kNoSignature:
22042             break;
22043           case kSignatureOnReceiver:
22044             signature = v8::Signature::New(isolate, function_template);
22045             break;
22046           case kSignatureOnPrototype:
22047             signature = v8::Signature::New(isolate, parent_template);
22048             break;
22049         }
22050         signature_template = function_template->InstanceTemplate();
22051       }
22052       // Global object must pass checks.
22053       Local<v8::Context> context =
22054           v8::Context::New(isolate, NULL, signature_template);
22055       v8::Context::Scope context_scope(context);
22056       // Install regular object that can pass signature checks.
22057       Local<Object> function_receiver = signature_template->NewInstance();
22058       context->Global()->Set(v8_str("function_receiver"), function_receiver);
22059       // Get the holder objects.
22060       Local<Object> inner_global =
22061           Local<Object>::Cast(context->Global()->GetPrototype());
22062       // Install functions on hidden prototype object if there is one.
22063       data = Object::New(isolate);
22064       Local<FunctionTemplate> function_template = FunctionTemplate::New(
22065           isolate, OptimizationCallback, data, signature);
22066       Local<Function> function = function_template->GetFunction();
22067       Local<Object> global_holder = inner_global;
22068       Local<Object> function_holder = function_receiver;
22069       if (signature_type == kSignatureOnPrototype) {
22070         function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22071         global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22072       }
22073       global_holder->Set(v8_str("g_f"), function);
22074       global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22075       function_holder->Set(v8_str("f"), function);
22076       function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22077       // Initialize expected values.
22078       callee = function;
22079       count = 0;
22080       if (global) {
22081         receiver = context->Global();
22082         holder = inner_global;
22083       } else {
22084         holder = function_receiver;
22085         // If not using a signature, add something else to the prototype chain
22086         // to test the case that holder != receiver
22087         if (signature_type == kNoSignature) {
22088           receiver = Local<Object>::Cast(CompileRun(
22089               "var receiver_subclass = {};\n"
22090               "receiver_subclass.__proto__ = function_receiver;\n"
22091               "receiver_subclass"));
22092         } else {
22093           receiver = Local<Object>::Cast(CompileRun(
22094             "var receiver_subclass = function_receiver;\n"
22095             "receiver_subclass"));
22096         }
22097       }
22098       // With no signature, the holder is not set.
22099       if (signature_type == kNoSignature) holder = receiver;
22100       // build wrap_function
22101       i::ScopedVector<char> wrap_function(200);
22102       if (global) {
22103         i::OS::SNPrintF(
22104             wrap_function,
22105             "function wrap_f_%d() { var f = g_f; return f(); }\n"
22106             "function wrap_get_%d() { return this.g_acc; }\n"
22107             "function wrap_set_%d() { return this.g_acc = 1; }\n",
22108             key, key, key);
22109       } else {
22110         i::OS::SNPrintF(
22111             wrap_function,
22112             "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22113             "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22114             "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22115             key, key, key);
22116       }
22117       // build source string
22118       i::ScopedVector<char> source(1000);
22119       i::OS::SNPrintF(
22120           source,
22121           "%s\n"  // wrap functions
22122           "function wrap_f() { return wrap_f_%d(); }\n"
22123           "function wrap_get() { return wrap_get_%d(); }\n"
22124           "function wrap_set() { return wrap_set_%d(); }\n"
22125           "check = function(returned) {\n"
22126           "  if (returned !== 'returned') { throw returned; }\n"
22127           "}\n"
22128           "\n"
22129           "check(wrap_f());\n"
22130           "check(wrap_f());\n"
22131           "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22132           "check(wrap_f());\n"
22133           "\n"
22134           "check(wrap_get());\n"
22135           "check(wrap_get());\n"
22136           "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22137           "check(wrap_get());\n"
22138           "\n"
22139           "check = function(returned) {\n"
22140           "  if (returned !== 1) { throw returned; }\n"
22141           "}\n"
22142           "check(wrap_set());\n"
22143           "check(wrap_set());\n"
22144           "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22145           "check(wrap_set());\n",
22146           wrap_function.start(), key, key, key, key, key, key);
22147       v8::TryCatch try_catch;
22148       CompileRun(source.start());
22149       ASSERT(!try_catch.HasCaught());
22150       CHECK_EQ(9, count);
22151     }
22152 };
22153
22154
22155 Local<Object> ApiCallOptimizationChecker::data;
22156 Local<Object> ApiCallOptimizationChecker::receiver;
22157 Local<Object> ApiCallOptimizationChecker::holder;
22158 Local<Object> ApiCallOptimizationChecker::callee;
22159 int ApiCallOptimizationChecker::count = 0;
22160
22161
22162 TEST(TestFunctionCallOptimization) {
22163   i::FLAG_allow_natives_syntax = true;
22164   ApiCallOptimizationChecker checker;
22165   checker.RunAll();
22166 }
22167
22168
22169 static const char* last_event_message;
22170 static int last_event_status;
22171 void StoringEventLoggerCallback(const char* message, int status) {
22172     last_event_message = message;
22173     last_event_status = status;
22174 }
22175
22176
22177 TEST(EventLogging) {
22178   v8::Isolate* isolate = CcTest::isolate();
22179   isolate->SetEventLogger(StoringEventLoggerCallback);
22180   v8::internal::HistogramTimer* histogramTimer =
22181       new v8::internal::HistogramTimer(
22182           "V8.Test", 0, 10000, 50,
22183           reinterpret_cast<v8::internal::Isolate*>(isolate));
22184   histogramTimer->Start();
22185   CHECK_EQ("V8.Test", last_event_message);
22186   CHECK_EQ(0, last_event_status);
22187   histogramTimer->Stop();
22188   CHECK_EQ("V8.Test", last_event_message);
22189   CHECK_EQ(1, last_event_status);
22190 }
22191
22192
22193 TEST(Promises) {
22194   i::FLAG_harmony_promises = true;
22195
22196   LocalContext context;
22197   v8::Isolate* isolate = context->GetIsolate();
22198   v8::HandleScope scope(isolate);
22199   Handle<Object> global = context->Global();
22200
22201   // Creation.
22202   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22203   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22204   Handle<v8::Promise> p = pr->GetPromise();
22205   Handle<v8::Promise> r = rr->GetPromise();
22206
22207   // IsPromise predicate.
22208   CHECK(p->IsPromise());
22209   CHECK(r->IsPromise());
22210   Handle<Value> o = v8::Object::New(isolate);
22211   CHECK(!o->IsPromise());
22212
22213   // Resolution and rejection.
22214   pr->Resolve(v8::Integer::New(isolate, 1));
22215   CHECK(p->IsPromise());
22216   rr->Reject(v8::Integer::New(isolate, 2));
22217   CHECK(r->IsPromise());
22218
22219   // Chaining non-pending promises.
22220   CompileRun(
22221       "var x1 = 0;\n"
22222       "var x2 = 0;\n"
22223       "function f1(x) { x1 = x; return x+1 };\n"
22224       "function f2(x) { x2 = x; return x+1 };\n");
22225   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22226   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22227
22228   p->Chain(f1);
22229   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22230   V8::RunMicrotasks(isolate);
22231   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22232
22233   p->Catch(f2);
22234   V8::RunMicrotasks(isolate);
22235   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22236
22237   r->Catch(f2);
22238   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22239   V8::RunMicrotasks(isolate);
22240   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22241
22242   r->Chain(f1);
22243   V8::RunMicrotasks(isolate);
22244   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22245
22246   // Chaining pending promises.
22247   CompileRun("x1 = x2 = 0;");
22248   pr = v8::Promise::Resolver::New(isolate);
22249   rr = v8::Promise::Resolver::New(isolate);
22250
22251   pr->GetPromise()->Chain(f1);
22252   rr->GetPromise()->Catch(f2);
22253   V8::RunMicrotasks(isolate);
22254   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22255   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22256
22257   pr->Resolve(v8::Integer::New(isolate, 1));
22258   rr->Reject(v8::Integer::New(isolate, 2));
22259   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22260   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22261
22262   V8::RunMicrotasks(isolate);
22263   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22264   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22265
22266   // Multi-chaining.
22267   CompileRun("x1 = x2 = 0;");
22268   pr = v8::Promise::Resolver::New(isolate);
22269   pr->GetPromise()->Chain(f1)->Chain(f2);
22270   pr->Resolve(v8::Integer::New(isolate, 3));
22271   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22272   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22273   V8::RunMicrotasks(isolate);
22274   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22275   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22276
22277   CompileRun("x1 = x2 = 0;");
22278   rr = v8::Promise::Resolver::New(isolate);
22279   rr->GetPromise()->Catch(f1)->Chain(f2);
22280   rr->Reject(v8::Integer::New(isolate, 3));
22281   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22282   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22283   V8::RunMicrotasks(isolate);
22284   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22285   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22286 }
22287
22288
22289 TEST(DisallowJavascriptExecutionScope) {
22290   LocalContext context;
22291   v8::Isolate* isolate = context->GetIsolate();
22292   v8::HandleScope scope(isolate);
22293   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22294       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22295   CompileRun("2+2");
22296 }
22297
22298
22299 TEST(AllowJavascriptExecutionScope) {
22300   LocalContext context;
22301   v8::Isolate* isolate = context->GetIsolate();
22302   v8::HandleScope scope(isolate);
22303   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22304       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22305   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22306       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22307   { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22308     CompileRun("1+1");
22309   }
22310 }
22311
22312
22313 TEST(ThrowOnJavascriptExecution) {
22314   LocalContext context;
22315   v8::Isolate* isolate = context->GetIsolate();
22316   v8::HandleScope scope(isolate);
22317   v8::TryCatch try_catch;
22318   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22319       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22320   CompileRun("1+1");
22321   CHECK(try_catch.HasCaught());
22322 }
22323
22324
22325 TEST(Regress354123) {
22326   LocalContext current;
22327   v8::Isolate* isolate = current->GetIsolate();
22328   v8::HandleScope scope(isolate);
22329
22330   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22331   templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22332   current->Global()->Set(v8_str("friend"), templ->NewInstance());
22333
22334   // Test access using __proto__ from the prototype chain.
22335   named_access_count = 0;
22336   CompileRun("friend.__proto__ = {};");
22337   CHECK_EQ(2, named_access_count);
22338   CompileRun("friend.__proto__;");
22339   CHECK_EQ(4, named_access_count);
22340
22341   // Test access using __proto__ as a hijacked function (A).
22342   named_access_count = 0;
22343   CompileRun("var p = Object.prototype;"
22344              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22345              "f.call(friend, {});");
22346   CHECK_EQ(1, named_access_count);
22347   CompileRun("var p = Object.prototype;"
22348              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22349              "f.call(friend);");
22350   CHECK_EQ(2, named_access_count);
22351
22352   // Test access using __proto__ as a hijacked function (B).
22353   named_access_count = 0;
22354   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22355              "f.call(friend, {});");
22356   CHECK_EQ(1, named_access_count);
22357   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22358              "f.call(friend);");
22359   CHECK_EQ(2, named_access_count);
22360
22361   // Test access using Object.setPrototypeOf reflective method.
22362   named_access_count = 0;
22363   CompileRun("Object.setPrototypeOf(friend, {});");
22364   CHECK_EQ(1, named_access_count);
22365   CompileRun("Object.getPrototypeOf(friend);");
22366   CHECK_EQ(2, named_access_count);
22367 }