test-api.cc revision 4515c472dc3e5ed2448a564600976759e569a0a8
1// Copyright 2007-2009 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 <limits.h>
29
30#include "v8.h"
31
32#include "api.h"
33#include "compilation-cache.h"
34#include "execution.h"
35#include "snapshot.h"
36#include "platform.h"
37#include "top.h"
38#include "utils.h"
39#include "cctest.h"
40
41static const bool kLogThreading = false;
42
43static bool IsNaN(double x) {
44#ifdef WIN32
45  return _isnan(x);
46#else
47  return isnan(x);
48#endif
49}
50
51using ::v8::ObjectTemplate;
52using ::v8::Value;
53using ::v8::Context;
54using ::v8::Local;
55using ::v8::String;
56using ::v8::Script;
57using ::v8::Function;
58using ::v8::AccessorInfo;
59using ::v8::Extension;
60
61namespace i = ::v8::internal;
62
63
64static void ExpectString(const char* code, const char* expected) {
65  Local<Value> result = CompileRun(code);
66  CHECK(result->IsString());
67  String::AsciiValue ascii(result);
68  CHECK_EQ(expected, *ascii);
69}
70
71
72static void ExpectBoolean(const char* code, bool expected) {
73  Local<Value> result = CompileRun(code);
74  CHECK(result->IsBoolean());
75  CHECK_EQ(expected, result->BooleanValue());
76}
77
78
79static void ExpectObject(const char* code, Local<Value> expected) {
80  Local<Value> result = CompileRun(code);
81  CHECK(result->Equals(expected));
82}
83
84
85static int signature_callback_count;
86static v8::Handle<Value> IncrementingSignatureCallback(
87    const v8::Arguments& args) {
88  ApiTestFuzzer::Fuzz();
89  signature_callback_count++;
90  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
91  for (int i = 0; i < args.Length(); i++)
92    result->Set(v8::Integer::New(i), args[i]);
93  return result;
94}
95
96
97static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
98  ApiTestFuzzer::Fuzz();
99  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
100  for (int i = 0; i < args.Length(); i++) {
101    result->Set(v8::Integer::New(i), args[i]);
102  }
103  return result;
104}
105
106
107THREADED_TEST(Handles) {
108  v8::HandleScope scope;
109  Local<Context> local_env;
110  {
111    LocalContext env;
112    local_env = env.local();
113  }
114
115  // Local context should still be live.
116  CHECK(!local_env.IsEmpty());
117  local_env->Enter();
118
119  v8::Handle<v8::Primitive> undef = v8::Undefined();
120  CHECK(!undef.IsEmpty());
121  CHECK(undef->IsUndefined());
122
123  const char* c_source = "1 + 2 + 3";
124  Local<String> source = String::New(c_source);
125  Local<Script> script = Script::Compile(source);
126  CHECK_EQ(6, script->Run()->Int32Value());
127
128  local_env->Exit();
129}
130
131
132THREADED_TEST(ReceiverSignature) {
133  v8::HandleScope scope;
134  LocalContext env;
135  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
136  v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
137  fun->PrototypeTemplate()->Set(
138      v8_str("m"),
139      v8::FunctionTemplate::New(IncrementingSignatureCallback,
140                                v8::Handle<Value>(),
141                                sig));
142  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
143  signature_callback_count = 0;
144  CompileRun(
145      "var o = new Fun();"
146      "o.m();");
147  CHECK_EQ(1, signature_callback_count);
148  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
149  sub_fun->Inherit(fun);
150  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
151  CompileRun(
152      "var o = new SubFun();"
153      "o.m();");
154  CHECK_EQ(2, signature_callback_count);
155
156  v8::TryCatch try_catch;
157  CompileRun(
158      "var o = { };"
159      "o.m = Fun.prototype.m;"
160      "o.m();");
161  CHECK_EQ(2, signature_callback_count);
162  CHECK(try_catch.HasCaught());
163  try_catch.Reset();
164  v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
165  sub_fun->Inherit(fun);
166  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
167  CompileRun(
168      "var o = new UnrelFun();"
169      "o.m = Fun.prototype.m;"
170      "o.m();");
171  CHECK_EQ(2, signature_callback_count);
172  CHECK(try_catch.HasCaught());
173}
174
175
176
177
178THREADED_TEST(ArgumentSignature) {
179  v8::HandleScope scope;
180  LocalContext env;
181  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
182  cons->SetClassName(v8_str("Cons"));
183  v8::Handle<v8::Signature> sig =
184      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
185  v8::Handle<v8::FunctionTemplate> fun =
186      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
187  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
188  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
189
190  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
191  CHECK(value1->IsTrue());
192
193  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
194  CHECK(value2->IsTrue());
195
196  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
197  CHECK(value3->IsTrue());
198
199  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
200  cons1->SetClassName(v8_str("Cons1"));
201  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
202  cons2->SetClassName(v8_str("Cons2"));
203  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
204  cons3->SetClassName(v8_str("Cons3"));
205
206  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
207  v8::Handle<v8::Signature> wsig =
208      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
209  v8::Handle<v8::FunctionTemplate> fun2 =
210      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
211
212  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
213  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
214  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
215  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
216  v8::Handle<Value> value4 = CompileRun(
217      "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
218      "'[object Cons1],[object Cons2],[object Cons3]'");
219  CHECK(value4->IsTrue());
220
221  v8::Handle<Value> value5 = CompileRun(
222      "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
223  CHECK(value5->IsTrue());
224
225  v8::Handle<Value> value6 = CompileRun(
226      "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
227  CHECK(value6->IsTrue());
228
229  v8::Handle<Value> value7 = CompileRun(
230      "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
231      "'[object Cons1],[object Cons2],[object Cons3],d';");
232  CHECK(value7->IsTrue());
233
234  v8::Handle<Value> value8 = CompileRun(
235      "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
236  CHECK(value8->IsTrue());
237}
238
239
240THREADED_TEST(HulIgennem) {
241  v8::HandleScope scope;
242  LocalContext env;
243  v8::Handle<v8::Primitive> undef = v8::Undefined();
244  Local<String> undef_str = undef->ToString();
245  char* value = i::NewArray<char>(undef_str->Length() + 1);
246  undef_str->WriteAscii(value);
247  CHECK_EQ(0, strcmp(value, "undefined"));
248  i::DeleteArray(value);
249}
250
251
252THREADED_TEST(Access) {
253  v8::HandleScope scope;
254  LocalContext env;
255  Local<v8::Object> obj = v8::Object::New();
256  Local<Value> foo_before = obj->Get(v8_str("foo"));
257  CHECK(foo_before->IsUndefined());
258  Local<String> bar_str = v8_str("bar");
259  obj->Set(v8_str("foo"), bar_str);
260  Local<Value> foo_after = obj->Get(v8_str("foo"));
261  CHECK(!foo_after->IsUndefined());
262  CHECK(foo_after->IsString());
263  CHECK_EQ(bar_str, foo_after);
264}
265
266
267THREADED_TEST(Script) {
268  v8::HandleScope scope;
269  LocalContext env;
270  const char* c_source = "1 + 2 + 3";
271  Local<String> source = String::New(c_source);
272  Local<Script> script = Script::Compile(source);
273  CHECK_EQ(6, script->Run()->Int32Value());
274}
275
276
277static uint16_t* AsciiToTwoByteString(const char* source) {
278  int array_length = i::StrLength(source) + 1;
279  uint16_t* converted = i::NewArray<uint16_t>(array_length);
280  for (int i = 0; i < array_length; i++) converted[i] = source[i];
281  return converted;
282}
283
284
285class TestResource: public String::ExternalStringResource {
286 public:
287  static int dispose_count;
288
289  explicit TestResource(uint16_t* data)
290      : data_(data), length_(0) {
291    while (data[length_]) ++length_;
292  }
293
294  ~TestResource() {
295    i::DeleteArray(data_);
296    ++dispose_count;
297  }
298
299  const uint16_t* data() const {
300    return data_;
301  }
302
303  size_t length() const {
304    return length_;
305  }
306 private:
307  uint16_t* data_;
308  size_t length_;
309};
310
311
312int TestResource::dispose_count = 0;
313
314
315class TestAsciiResource: public String::ExternalAsciiStringResource {
316 public:
317  static int dispose_count;
318
319  explicit TestAsciiResource(const char* data)
320      : data_(data),
321        length_(strlen(data)) { }
322
323  ~TestAsciiResource() {
324    i::DeleteArray(data_);
325    ++dispose_count;
326  }
327
328  const char* data() const {
329    return data_;
330  }
331
332  size_t length() const {
333    return length_;
334  }
335 private:
336  const char* data_;
337  size_t length_;
338};
339
340
341int TestAsciiResource::dispose_count = 0;
342
343
344THREADED_TEST(ScriptUsingStringResource) {
345  TestResource::dispose_count = 0;
346  const char* c_source = "1 + 2 * 3";
347  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
348  {
349    v8::HandleScope scope;
350    LocalContext env;
351    TestResource* resource = new TestResource(two_byte_source);
352    Local<String> source = String::NewExternal(resource);
353    Local<Script> script = Script::Compile(source);
354    Local<Value> value = script->Run();
355    CHECK(value->IsNumber());
356    CHECK_EQ(7, value->Int32Value());
357    CHECK(source->IsExternal());
358    CHECK_EQ(resource,
359             static_cast<TestResource*>(source->GetExternalStringResource()));
360    v8::internal::Heap::CollectAllGarbage(false);
361    CHECK_EQ(0, TestResource::dispose_count);
362  }
363  v8::internal::CompilationCache::Clear();
364  v8::internal::Heap::CollectAllGarbage(false);
365  CHECK_EQ(1, TestResource::dispose_count);
366}
367
368
369THREADED_TEST(ScriptUsingAsciiStringResource) {
370  TestAsciiResource::dispose_count = 0;
371  const char* c_source = "1 + 2 * 3";
372  {
373    v8::HandleScope scope;
374    LocalContext env;
375    Local<String> source =
376        String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
377    Local<Script> script = Script::Compile(source);
378    Local<Value> value = script->Run();
379    CHECK(value->IsNumber());
380    CHECK_EQ(7, value->Int32Value());
381    v8::internal::Heap::CollectAllGarbage(false);
382    CHECK_EQ(0, TestAsciiResource::dispose_count);
383  }
384  v8::internal::CompilationCache::Clear();
385  v8::internal::Heap::CollectAllGarbage(false);
386  CHECK_EQ(1, TestAsciiResource::dispose_count);
387}
388
389
390THREADED_TEST(ScriptMakingExternalString) {
391  TestResource::dispose_count = 0;
392  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
393  {
394    v8::HandleScope scope;
395    LocalContext env;
396    Local<String> source = String::New(two_byte_source);
397    bool success = source->MakeExternal(new TestResource(two_byte_source));
398    CHECK(success);
399    Local<Script> script = Script::Compile(source);
400    Local<Value> value = script->Run();
401    CHECK(value->IsNumber());
402    CHECK_EQ(7, value->Int32Value());
403    v8::internal::Heap::CollectAllGarbage(false);
404    CHECK_EQ(0, TestResource::dispose_count);
405  }
406  v8::internal::CompilationCache::Clear();
407  v8::internal::Heap::CollectAllGarbage(false);
408  CHECK_EQ(1, TestResource::dispose_count);
409}
410
411
412THREADED_TEST(ScriptMakingExternalAsciiString) {
413  TestAsciiResource::dispose_count = 0;
414  const char* c_source = "1 + 2 * 3";
415  {
416    v8::HandleScope scope;
417    LocalContext env;
418    Local<String> source = v8_str(c_source);
419    bool success = source->MakeExternal(
420        new TestAsciiResource(i::StrDup(c_source)));
421    CHECK(success);
422    Local<Script> script = Script::Compile(source);
423    Local<Value> value = script->Run();
424    CHECK(value->IsNumber());
425    CHECK_EQ(7, value->Int32Value());
426    v8::internal::Heap::CollectAllGarbage(false);
427    CHECK_EQ(0, TestAsciiResource::dispose_count);
428  }
429  v8::internal::CompilationCache::Clear();
430  v8::internal::Heap::CollectAllGarbage(false);
431  CHECK_EQ(1, TestAsciiResource::dispose_count);
432}
433
434
435THREADED_TEST(UsingExternalString) {
436  {
437    v8::HandleScope scope;
438    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
439    Local<String> string =
440        String::NewExternal(new TestResource(two_byte_string));
441    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
442    // Trigger GCs so that the newly allocated string moves to old gen.
443    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
444    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
445    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
446    CHECK(isymbol->IsSymbol());
447  }
448  i::Heap::CollectAllGarbage(false);
449  i::Heap::CollectAllGarbage(false);
450}
451
452
453THREADED_TEST(UsingExternalAsciiString) {
454  {
455    v8::HandleScope scope;
456    const char* one_byte_string = "test string";
457    Local<String> string = String::NewExternal(
458        new TestAsciiResource(i::StrDup(one_byte_string)));
459    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
460    // Trigger GCs so that the newly allocated string moves to old gen.
461    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
462    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
463    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
464    CHECK(isymbol->IsSymbol());
465  }
466  i::Heap::CollectAllGarbage(false);
467  i::Heap::CollectAllGarbage(false);
468}
469
470
471THREADED_TEST(ScavengeExternalString) {
472  TestResource::dispose_count = 0;
473  {
474    v8::HandleScope scope;
475    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
476    Local<String> string =
477        String::NewExternal(new TestResource(two_byte_string));
478    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
479    i::Heap::CollectGarbage(0, i::NEW_SPACE);
480    CHECK(i::Heap::InNewSpace(*istring));
481    CHECK_EQ(0, TestResource::dispose_count);
482  }
483  i::Heap::CollectGarbage(0, i::NEW_SPACE);
484  CHECK_EQ(1, TestResource::dispose_count);
485}
486
487
488THREADED_TEST(ScavengeExternalAsciiString) {
489  TestAsciiResource::dispose_count = 0;
490  {
491    v8::HandleScope scope;
492    const char* one_byte_string = "test string";
493    Local<String> string = String::NewExternal(
494        new TestAsciiResource(i::StrDup(one_byte_string)));
495    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
496    i::Heap::CollectGarbage(0, i::NEW_SPACE);
497    CHECK(i::Heap::InNewSpace(*istring));
498    CHECK_EQ(0, TestAsciiResource::dispose_count);
499  }
500  i::Heap::CollectGarbage(0, i::NEW_SPACE);
501  CHECK_EQ(1, TestAsciiResource::dispose_count);
502}
503
504
505THREADED_TEST(StringConcat) {
506  {
507    v8::HandleScope scope;
508    LocalContext env;
509    const char* one_byte_string_1 = "function a_times_t";
510    const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
511    const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
512    const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
513    const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
514    const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
515    const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
516    Local<String> left = v8_str(one_byte_string_1);
517    Local<String> right = String::New(AsciiToTwoByteString(two_byte_string_1));
518    Local<String> source = String::Concat(left, right);
519    right = String::NewExternal(
520        new TestAsciiResource(i::StrDup(one_byte_extern_1)));
521    source = String::Concat(source, right);
522    right = String::NewExternal(
523        new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
524    source = String::Concat(source, right);
525    right = v8_str(one_byte_string_2);
526    source = String::Concat(source, right);
527    right = String::New(AsciiToTwoByteString(two_byte_string_2));
528    source = String::Concat(source, right);
529    right = String::NewExternal(
530        new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
531    source = String::Concat(source, right);
532    Local<Script> script = Script::Compile(source);
533    Local<Value> value = script->Run();
534    CHECK(value->IsNumber());
535    CHECK_EQ(68, value->Int32Value());
536  }
537  v8::internal::CompilationCache::Clear();
538  i::Heap::CollectAllGarbage(false);
539  i::Heap::CollectAllGarbage(false);
540}
541
542
543THREADED_TEST(GlobalProperties) {
544  v8::HandleScope scope;
545  LocalContext env;
546  v8::Handle<v8::Object> global = env->Global();
547  global->Set(v8_str("pi"), v8_num(3.1415926));
548  Local<Value> pi = global->Get(v8_str("pi"));
549  CHECK_EQ(3.1415926, pi->NumberValue());
550}
551
552
553static v8::Handle<Value> handle_call(const v8::Arguments& args) {
554  ApiTestFuzzer::Fuzz();
555  return v8_num(102);
556}
557
558
559static v8::Handle<Value> construct_call(const v8::Arguments& args) {
560  ApiTestFuzzer::Fuzz();
561  args.This()->Set(v8_str("x"), v8_num(1));
562  args.This()->Set(v8_str("y"), v8_num(2));
563  return args.This();
564}
565
566THREADED_TEST(FunctionTemplate) {
567  v8::HandleScope scope;
568  LocalContext env;
569  {
570    Local<v8::FunctionTemplate> fun_templ =
571        v8::FunctionTemplate::New(handle_call);
572    Local<Function> fun = fun_templ->GetFunction();
573    env->Global()->Set(v8_str("obj"), fun);
574    Local<Script> script = v8_compile("obj()");
575    CHECK_EQ(102, script->Run()->Int32Value());
576  }
577  // Use SetCallHandler to initialize a function template, should work like the
578  // previous one.
579  {
580    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
581    fun_templ->SetCallHandler(handle_call);
582    Local<Function> fun = fun_templ->GetFunction();
583    env->Global()->Set(v8_str("obj"), fun);
584    Local<Script> script = v8_compile("obj()");
585    CHECK_EQ(102, script->Run()->Int32Value());
586  }
587  // Test constructor calls.
588  {
589    Local<v8::FunctionTemplate> fun_templ =
590        v8::FunctionTemplate::New(construct_call);
591    fun_templ->SetClassName(v8_str("funky"));
592    Local<Function> fun = fun_templ->GetFunction();
593    env->Global()->Set(v8_str("obj"), fun);
594    Local<Script> script = v8_compile("var s = new obj(); s.x");
595    CHECK_EQ(1, script->Run()->Int32Value());
596
597    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
598    CHECK_EQ(v8_str("[object funky]"), result);
599  }
600}
601
602
603THREADED_TEST(FindInstanceInPrototypeChain) {
604  v8::HandleScope scope;
605  LocalContext env;
606
607  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
608  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
609  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
610  derived->Inherit(base);
611
612  Local<v8::Function> base_function = base->GetFunction();
613  Local<v8::Function> derived_function = derived->GetFunction();
614  Local<v8::Function> other_function = other->GetFunction();
615
616  Local<v8::Object> base_instance = base_function->NewInstance();
617  Local<v8::Object> derived_instance = derived_function->NewInstance();
618  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
619  Local<v8::Object> other_instance = other_function->NewInstance();
620  derived_instance2->Set(v8_str("__proto__"), derived_instance);
621  other_instance->Set(v8_str("__proto__"), derived_instance2);
622
623  // base_instance is only an instance of base.
624  CHECK_EQ(base_instance,
625           base_instance->FindInstanceInPrototypeChain(base));
626  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
627  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
628
629  // derived_instance is an instance of base and derived.
630  CHECK_EQ(derived_instance,
631           derived_instance->FindInstanceInPrototypeChain(base));
632  CHECK_EQ(derived_instance,
633           derived_instance->FindInstanceInPrototypeChain(derived));
634  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
635
636  // other_instance is an instance of other and its immediate
637  // prototype derived_instance2 is an instance of base and derived.
638  // Note, derived_instance is an instance of base and derived too,
639  // but it comes after derived_instance2 in the prototype chain of
640  // other_instance.
641  CHECK_EQ(derived_instance2,
642           other_instance->FindInstanceInPrototypeChain(base));
643  CHECK_EQ(derived_instance2,
644           other_instance->FindInstanceInPrototypeChain(derived));
645  CHECK_EQ(other_instance,
646           other_instance->FindInstanceInPrototypeChain(other));
647}
648
649
650THREADED_TEST(TinyInteger) {
651  v8::HandleScope scope;
652  LocalContext env;
653  int32_t value = 239;
654  Local<v8::Integer> value_obj = v8::Integer::New(value);
655  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
656}
657
658
659THREADED_TEST(BigSmiInteger) {
660  v8::HandleScope scope;
661  LocalContext env;
662  int32_t value = i::Smi::kMaxValue;
663  // We cannot add one to a Smi::kMaxValue without wrapping.
664  if (i::kSmiValueSize < 32) {
665    CHECK(i::Smi::IsValid(value));
666    CHECK(!i::Smi::IsValid(value + 1));
667    Local<v8::Integer> value_obj = v8::Integer::New(value);
668    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
669  }
670}
671
672
673THREADED_TEST(BigInteger) {
674  v8::HandleScope scope;
675  LocalContext env;
676  // We cannot add one to a Smi::kMaxValue without wrapping.
677  if (i::kSmiValueSize < 32) {
678    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
679    // The code will not be run in that case, due to the "if" guard.
680    int32_t value =
681        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
682    CHECK(value > i::Smi::kMaxValue);
683    CHECK(!i::Smi::IsValid(value));
684    Local<v8::Integer> value_obj = v8::Integer::New(value);
685    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
686  }
687}
688
689
690THREADED_TEST(TinyUnsignedInteger) {
691  v8::HandleScope scope;
692  LocalContext env;
693  uint32_t value = 239;
694  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
695  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
696}
697
698
699THREADED_TEST(BigUnsignedSmiInteger) {
700  v8::HandleScope scope;
701  LocalContext env;
702  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
703  CHECK(i::Smi::IsValid(value));
704  CHECK(!i::Smi::IsValid(value + 1));
705  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
706  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
707}
708
709
710THREADED_TEST(BigUnsignedInteger) {
711  v8::HandleScope scope;
712  LocalContext env;
713  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
714  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
715  CHECK(!i::Smi::IsValid(value));
716  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
717  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
718}
719
720
721THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
722  v8::HandleScope scope;
723  LocalContext env;
724  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
725  uint32_t value = INT32_MAX_AS_UINT + 1;
726  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
727  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
728  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
729}
730
731
732THREADED_TEST(Number) {
733  v8::HandleScope scope;
734  LocalContext env;
735  double PI = 3.1415926;
736  Local<v8::Number> pi_obj = v8::Number::New(PI);
737  CHECK_EQ(PI, pi_obj->NumberValue());
738}
739
740
741THREADED_TEST(ToNumber) {
742  v8::HandleScope scope;
743  LocalContext env;
744  Local<String> str = v8_str("3.1415926");
745  CHECK_EQ(3.1415926, str->NumberValue());
746  v8::Handle<v8::Boolean> t = v8::True();
747  CHECK_EQ(1.0, t->NumberValue());
748  v8::Handle<v8::Boolean> f = v8::False();
749  CHECK_EQ(0.0, f->NumberValue());
750}
751
752
753THREADED_TEST(Date) {
754  v8::HandleScope scope;
755  LocalContext env;
756  double PI = 3.1415926;
757  Local<Value> date_obj = v8::Date::New(PI);
758  CHECK_EQ(3.0, date_obj->NumberValue());
759}
760
761
762THREADED_TEST(Boolean) {
763  v8::HandleScope scope;
764  LocalContext env;
765  v8::Handle<v8::Boolean> t = v8::True();
766  CHECK(t->Value());
767  v8::Handle<v8::Boolean> f = v8::False();
768  CHECK(!f->Value());
769  v8::Handle<v8::Primitive> u = v8::Undefined();
770  CHECK(!u->BooleanValue());
771  v8::Handle<v8::Primitive> n = v8::Null();
772  CHECK(!n->BooleanValue());
773  v8::Handle<String> str1 = v8_str("");
774  CHECK(!str1->BooleanValue());
775  v8::Handle<String> str2 = v8_str("x");
776  CHECK(str2->BooleanValue());
777  CHECK(!v8::Number::New(0)->BooleanValue());
778  CHECK(v8::Number::New(-1)->BooleanValue());
779  CHECK(v8::Number::New(1)->BooleanValue());
780  CHECK(v8::Number::New(42)->BooleanValue());
781  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
782}
783
784
785static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
786  ApiTestFuzzer::Fuzz();
787  return v8_num(13.4);
788}
789
790
791static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
792  ApiTestFuzzer::Fuzz();
793  return v8_num(876);
794}
795
796
797THREADED_TEST(GlobalPrototype) {
798  v8::HandleScope scope;
799  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
800  func_templ->PrototypeTemplate()->Set(
801      "dummy",
802      v8::FunctionTemplate::New(DummyCallHandler));
803  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
804  templ->Set("x", v8_num(200));
805  templ->SetAccessor(v8_str("m"), GetM);
806  LocalContext env(0, templ);
807  v8::Handle<v8::Object> obj = env->Global();
808  v8::Handle<Script> script = v8_compile("dummy()");
809  v8::Handle<Value> result = script->Run();
810  CHECK_EQ(13.4, result->NumberValue());
811  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
812  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
813}
814
815
816THREADED_TEST(ObjectTemplate) {
817  v8::HandleScope scope;
818  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
819  templ1->Set("x", v8_num(10));
820  templ1->Set("y", v8_num(13));
821  LocalContext env;
822  Local<v8::Object> instance1 = templ1->NewInstance();
823  env->Global()->Set(v8_str("p"), instance1);
824  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
825  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
826  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
827  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
828  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
829  templ2->Set("a", v8_num(12));
830  templ2->Set("b", templ1);
831  Local<v8::Object> instance2 = templ2->NewInstance();
832  env->Global()->Set(v8_str("q"), instance2);
833  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
834  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
835  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
836  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
837}
838
839
840static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
841  ApiTestFuzzer::Fuzz();
842  return v8_num(17.2);
843}
844
845
846static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
847  ApiTestFuzzer::Fuzz();
848  return v8_num(15.2);
849}
850
851
852THREADED_TEST(DescriptorInheritance) {
853  v8::HandleScope scope;
854  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
855  super->PrototypeTemplate()->Set("flabby",
856                                  v8::FunctionTemplate::New(GetFlabby));
857  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
858
859  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
860
861  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
862  base1->Inherit(super);
863  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
864
865  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
866  base2->Inherit(super);
867  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
868
869  LocalContext env;
870
871  env->Global()->Set(v8_str("s"), super->GetFunction());
872  env->Global()->Set(v8_str("base1"), base1->GetFunction());
873  env->Global()->Set(v8_str("base2"), base2->GetFunction());
874
875  // Checks right __proto__ chain.
876  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
877  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
878
879  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
880
881  // Instance accessor should not be visible on function object or its prototype
882  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
883  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
884  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
885
886  env->Global()->Set(v8_str("obj"),
887                     base1->GetFunction()->NewInstance());
888  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
889  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
890  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
891  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
892  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
893
894  env->Global()->Set(v8_str("obj2"),
895                     base2->GetFunction()->NewInstance());
896  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
897  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
898  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
899  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
900  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
901
902  // base1 and base2 cannot cross reference to each's prototype
903  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
904  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
905}
906
907
908int echo_named_call_count;
909
910
911static v8::Handle<Value> EchoNamedProperty(Local<String> name,
912                                           const AccessorInfo& info) {
913  ApiTestFuzzer::Fuzz();
914  CHECK_EQ(v8_str("data"), info.Data());
915  echo_named_call_count++;
916  return name;
917}
918
919
920THREADED_TEST(NamedPropertyHandlerGetter) {
921  echo_named_call_count = 0;
922  v8::HandleScope scope;
923  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
924  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
925                                                     0, 0, 0, 0,
926                                                     v8_str("data"));
927  LocalContext env;
928  env->Global()->Set(v8_str("obj"),
929                     templ->GetFunction()->NewInstance());
930  CHECK_EQ(echo_named_call_count, 0);
931  v8_compile("obj.x")->Run();
932  CHECK_EQ(echo_named_call_count, 1);
933  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
934  v8::Handle<Value> str = CompileRun(code);
935  String::AsciiValue value(str);
936  CHECK_EQ(*value, "oddlepoddle");
937  // Check default behavior
938  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
939  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
940  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
941}
942
943
944int echo_indexed_call_count = 0;
945
946
947static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
948                                             const AccessorInfo& info) {
949  ApiTestFuzzer::Fuzz();
950  CHECK_EQ(v8_num(637), info.Data());
951  echo_indexed_call_count++;
952  return v8_num(index);
953}
954
955
956THREADED_TEST(IndexedPropertyHandlerGetter) {
957  v8::HandleScope scope;
958  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
959  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
960                                                       0, 0, 0, 0,
961                                                       v8_num(637));
962  LocalContext env;
963  env->Global()->Set(v8_str("obj"),
964                     templ->GetFunction()->NewInstance());
965  Local<Script> script = v8_compile("obj[900]");
966  CHECK_EQ(script->Run()->Int32Value(), 900);
967}
968
969
970v8::Handle<v8::Object> bottom;
971
972static v8::Handle<Value> CheckThisIndexedPropertyHandler(
973    uint32_t index,
974    const AccessorInfo& info) {
975  ApiTestFuzzer::Fuzz();
976  CHECK(info.This()->Equals(bottom));
977  return v8::Handle<Value>();
978}
979
980static v8::Handle<Value> CheckThisNamedPropertyHandler(
981    Local<String> name,
982    const AccessorInfo& info) {
983  ApiTestFuzzer::Fuzz();
984  CHECK(info.This()->Equals(bottom));
985  return v8::Handle<Value>();
986}
987
988
989v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
990                                                 Local<Value> value,
991                                                 const AccessorInfo& info) {
992  ApiTestFuzzer::Fuzz();
993  CHECK(info.This()->Equals(bottom));
994  return v8::Handle<Value>();
995}
996
997
998v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
999                                               Local<Value> value,
1000                                               const AccessorInfo& info) {
1001  ApiTestFuzzer::Fuzz();
1002  CHECK(info.This()->Equals(bottom));
1003  return v8::Handle<Value>();
1004}
1005
1006v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
1007    uint32_t index,
1008    const AccessorInfo& info) {
1009  ApiTestFuzzer::Fuzz();
1010  CHECK(info.This()->Equals(bottom));
1011  return v8::Handle<v8::Boolean>();
1012}
1013
1014
1015v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
1016                                                    const AccessorInfo& info) {
1017  ApiTestFuzzer::Fuzz();
1018  CHECK(info.This()->Equals(bottom));
1019  return v8::Handle<v8::Boolean>();
1020}
1021
1022
1023v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1024    uint32_t index,
1025    const AccessorInfo& info) {
1026  ApiTestFuzzer::Fuzz();
1027  CHECK(info.This()->Equals(bottom));
1028  return v8::Handle<v8::Boolean>();
1029}
1030
1031
1032v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1033    Local<String> property,
1034    const AccessorInfo& info) {
1035  ApiTestFuzzer::Fuzz();
1036  CHECK(info.This()->Equals(bottom));
1037  return v8::Handle<v8::Boolean>();
1038}
1039
1040
1041v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1042    const AccessorInfo& info) {
1043  ApiTestFuzzer::Fuzz();
1044  CHECK(info.This()->Equals(bottom));
1045  return v8::Handle<v8::Array>();
1046}
1047
1048
1049v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1050    const AccessorInfo& info) {
1051  ApiTestFuzzer::Fuzz();
1052  CHECK(info.This()->Equals(bottom));
1053  return v8::Handle<v8::Array>();
1054}
1055
1056
1057THREADED_TEST(PropertyHandlerInPrototype) {
1058  v8::HandleScope scope;
1059  LocalContext env;
1060
1061  // Set up a prototype chain with three interceptors.
1062  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1063  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1064      CheckThisIndexedPropertyHandler,
1065      CheckThisIndexedPropertySetter,
1066      CheckThisIndexedPropertyQuery,
1067      CheckThisIndexedPropertyDeleter,
1068      CheckThisIndexedPropertyEnumerator);
1069
1070  templ->InstanceTemplate()->SetNamedPropertyHandler(
1071      CheckThisNamedPropertyHandler,
1072      CheckThisNamedPropertySetter,
1073      CheckThisNamedPropertyQuery,
1074      CheckThisNamedPropertyDeleter,
1075      CheckThisNamedPropertyEnumerator);
1076
1077  bottom = templ->GetFunction()->NewInstance();
1078  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1079  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1080
1081  bottom->Set(v8_str("__proto__"), middle);
1082  middle->Set(v8_str("__proto__"), top);
1083  env->Global()->Set(v8_str("obj"), bottom);
1084
1085  // Indexed and named get.
1086  Script::Compile(v8_str("obj[0]"))->Run();
1087  Script::Compile(v8_str("obj.x"))->Run();
1088
1089  // Indexed and named set.
1090  Script::Compile(v8_str("obj[1] = 42"))->Run();
1091  Script::Compile(v8_str("obj.y = 42"))->Run();
1092
1093  // Indexed and named query.
1094  Script::Compile(v8_str("0 in obj"))->Run();
1095  Script::Compile(v8_str("'x' in obj"))->Run();
1096
1097  // Indexed and named deleter.
1098  Script::Compile(v8_str("delete obj[0]"))->Run();
1099  Script::Compile(v8_str("delete obj.x"))->Run();
1100
1101  // Enumerators.
1102  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1103}
1104
1105
1106static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1107                                               const AccessorInfo& info) {
1108  ApiTestFuzzer::Fuzz();
1109  if (v8_str("pre")->Equals(key)) {
1110    return v8_str("PrePropertyHandler: pre");
1111  }
1112  return v8::Handle<String>();
1113}
1114
1115
1116static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
1117                                                     const AccessorInfo&) {
1118  if (v8_str("pre")->Equals(key)) {
1119    return v8::True();
1120  }
1121
1122  return v8::Handle<v8::Boolean>();  // do not intercept the call
1123}
1124
1125
1126THREADED_TEST(PrePropertyHandler) {
1127  v8::HandleScope scope;
1128  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1129  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1130                                                    0,
1131                                                    PrePropertyHandlerHas);
1132  LocalContext env(NULL, desc->InstanceTemplate());
1133  Script::Compile(v8_str(
1134      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1135  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1136  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1137  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1138  CHECK_EQ(v8_str("Object: on"), result_on);
1139  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1140  CHECK(result_post.IsEmpty());
1141}
1142
1143
1144THREADED_TEST(UndefinedIsNotEnumerable) {
1145  v8::HandleScope scope;
1146  LocalContext env;
1147  v8::Handle<Value> result = Script::Compile(v8_str(
1148      "this.propertyIsEnumerable(undefined)"))->Run();
1149  CHECK(result->IsFalse());
1150}
1151
1152
1153v8::Handle<Script> call_recursively_script;
1154static const int kTargetRecursionDepth = 200;  // near maximum
1155
1156
1157static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1158  ApiTestFuzzer::Fuzz();
1159  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1160  if (depth == kTargetRecursionDepth) return v8::Undefined();
1161  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1162  return call_recursively_script->Run();
1163}
1164
1165
1166static v8::Handle<Value> CallFunctionRecursivelyCall(
1167    const v8::Arguments& args) {
1168  ApiTestFuzzer::Fuzz();
1169  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1170  if (depth == kTargetRecursionDepth) {
1171    printf("[depth = %d]\n", depth);
1172    return v8::Undefined();
1173  }
1174  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1175  v8::Handle<Value> function =
1176      args.This()->Get(v8_str("callFunctionRecursively"));
1177  return v8::Handle<Function>::Cast(function)->Call(args.This(), 0, NULL);
1178}
1179
1180
1181THREADED_TEST(DeepCrossLanguageRecursion) {
1182  v8::HandleScope scope;
1183  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1184  global->Set(v8_str("callScriptRecursively"),
1185              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1186  global->Set(v8_str("callFunctionRecursively"),
1187              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1188  LocalContext env(NULL, global);
1189
1190  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1191  call_recursively_script = v8_compile("callScriptRecursively()");
1192  v8::Handle<Value> result = call_recursively_script->Run();
1193  call_recursively_script = v8::Handle<Script>();
1194
1195  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1196  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1197}
1198
1199
1200static v8::Handle<Value>
1201    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1202  ApiTestFuzzer::Fuzz();
1203  return v8::ThrowException(key);
1204}
1205
1206
1207static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1208                                                    Local<Value>,
1209                                                    const AccessorInfo&) {
1210  v8::ThrowException(key);
1211  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1212}
1213
1214
1215THREADED_TEST(CallbackExceptionRegression) {
1216  v8::HandleScope scope;
1217  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1218  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1219                               ThrowingPropertyHandlerSet);
1220  LocalContext env;
1221  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1222  v8::Handle<Value> otto = Script::Compile(v8_str(
1223      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1224  CHECK_EQ(v8_str("otto"), otto);
1225  v8::Handle<Value> netto = Script::Compile(v8_str(
1226      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1227  CHECK_EQ(v8_str("netto"), netto);
1228}
1229
1230
1231THREADED_TEST(FunctionPrototype) {
1232  v8::HandleScope scope;
1233  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1234  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1235  LocalContext env;
1236  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1237  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1238  CHECK_EQ(script->Run()->Int32Value(), 321);
1239}
1240
1241
1242THREADED_TEST(InternalFields) {
1243  v8::HandleScope scope;
1244  LocalContext env;
1245
1246  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1247  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1248  instance_templ->SetInternalFieldCount(1);
1249  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1250  CHECK_EQ(1, obj->InternalFieldCount());
1251  CHECK(obj->GetInternalField(0)->IsUndefined());
1252  obj->SetInternalField(0, v8_num(17));
1253  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1254}
1255
1256
1257THREADED_TEST(InternalFieldsNativePointers) {
1258  v8::HandleScope scope;
1259  LocalContext env;
1260
1261  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1262  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1263  instance_templ->SetInternalFieldCount(1);
1264  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1265  CHECK_EQ(1, obj->InternalFieldCount());
1266  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1267
1268  char* data = new char[100];
1269
1270  void* aligned = data;
1271  CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1272  void* unaligned = data + 1;
1273  CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1274
1275  // Check reading and writing aligned pointers.
1276  obj->SetPointerInInternalField(0, aligned);
1277  i::Heap::CollectAllGarbage(false);
1278  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1279
1280  // Check reading and writing unaligned pointers.
1281  obj->SetPointerInInternalField(0, unaligned);
1282  i::Heap::CollectAllGarbage(false);
1283  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1284
1285  delete[] data;
1286}
1287
1288
1289THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1290  v8::HandleScope scope;
1291  LocalContext env;
1292
1293  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1294  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1295  instance_templ->SetInternalFieldCount(1);
1296  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1297  CHECK_EQ(1, obj->InternalFieldCount());
1298  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1299
1300  char* data = new char[100];
1301
1302  void* aligned = data;
1303  CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1304  void* unaligned = data + 1;
1305  CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1306
1307  obj->SetPointerInInternalField(0, aligned);
1308  i::Heap::CollectAllGarbage(false);
1309  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1310
1311  obj->SetPointerInInternalField(0, unaligned);
1312  i::Heap::CollectAllGarbage(false);
1313  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1314
1315  obj->SetInternalField(0, v8::External::Wrap(aligned));
1316  i::Heap::CollectAllGarbage(false);
1317  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1318
1319  obj->SetInternalField(0, v8::External::Wrap(unaligned));
1320  i::Heap::CollectAllGarbage(false);
1321  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1322
1323  delete[] data;
1324}
1325
1326
1327THREADED_TEST(IdentityHash) {
1328  v8::HandleScope scope;
1329  LocalContext env;
1330
1331  // Ensure that the test starts with an fresh heap to test whether the hash
1332  // code is based on the address.
1333  i::Heap::CollectAllGarbage(false);
1334  Local<v8::Object> obj = v8::Object::New();
1335  int hash = obj->GetIdentityHash();
1336  int hash1 = obj->GetIdentityHash();
1337  CHECK_EQ(hash, hash1);
1338  int hash2 = v8::Object::New()->GetIdentityHash();
1339  // Since the identity hash is essentially a random number two consecutive
1340  // objects should not be assigned the same hash code. If the test below fails
1341  // the random number generator should be evaluated.
1342  CHECK_NE(hash, hash2);
1343  i::Heap::CollectAllGarbage(false);
1344  int hash3 = v8::Object::New()->GetIdentityHash();
1345  // Make sure that the identity hash is not based on the initial address of
1346  // the object alone. If the test below fails the random number generator
1347  // should be evaluated.
1348  CHECK_NE(hash, hash3);
1349  int hash4 = obj->GetIdentityHash();
1350  CHECK_EQ(hash, hash4);
1351}
1352
1353
1354THREADED_TEST(HiddenProperties) {
1355  v8::HandleScope scope;
1356  LocalContext env;
1357
1358  v8::Local<v8::Object> obj = v8::Object::New();
1359  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1360  v8::Local<v8::String> empty = v8_str("");
1361  v8::Local<v8::String> prop_name = v8_str("prop_name");
1362
1363  i::Heap::CollectAllGarbage(false);
1364
1365  // Make sure delete of a non-existent hidden value works
1366  CHECK(obj->DeleteHiddenValue(key));
1367
1368  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1369  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1370  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1371  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1372
1373  i::Heap::CollectAllGarbage(false);
1374
1375  // Make sure we do not find the hidden property.
1376  CHECK(!obj->Has(empty));
1377  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1378  CHECK(obj->Get(empty)->IsUndefined());
1379  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1380  CHECK(obj->Set(empty, v8::Integer::New(2003)));
1381  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1382  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1383
1384  i::Heap::CollectAllGarbage(false);
1385
1386  // Add another property and delete it afterwards to force the object in
1387  // slow case.
1388  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1389  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1390  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1391  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1392  CHECK(obj->Delete(prop_name));
1393  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1394
1395  i::Heap::CollectAllGarbage(false);
1396
1397  CHECK(obj->DeleteHiddenValue(key));
1398  CHECK(obj->GetHiddenValue(key).IsEmpty());
1399}
1400
1401
1402static bool interceptor_for_hidden_properties_called;
1403static v8::Handle<Value> InterceptorForHiddenProperties(
1404    Local<String> name, const AccessorInfo& info) {
1405  interceptor_for_hidden_properties_called = true;
1406  return v8::Handle<Value>();
1407}
1408
1409
1410THREADED_TEST(HiddenPropertiesWithInterceptors) {
1411  v8::HandleScope scope;
1412  LocalContext context;
1413
1414  interceptor_for_hidden_properties_called = false;
1415
1416  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1417
1418  // Associate an interceptor with an object and start setting hidden values.
1419  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1420  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1421  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1422  Local<v8::Function> function = fun_templ->GetFunction();
1423  Local<v8::Object> obj = function->NewInstance();
1424  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1425  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1426  CHECK(!interceptor_for_hidden_properties_called);
1427}
1428
1429
1430THREADED_TEST(External) {
1431  v8::HandleScope scope;
1432  int x = 3;
1433  Local<v8::External> ext = v8::External::New(&x);
1434  LocalContext env;
1435  env->Global()->Set(v8_str("ext"), ext);
1436  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1437  v8::Handle<v8::External> reext = v8::Handle<v8::External>::Cast(reext_obj);
1438  int* ptr = static_cast<int*>(reext->Value());
1439  CHECK_EQ(x, 3);
1440  *ptr = 10;
1441  CHECK_EQ(x, 10);
1442
1443  // Make sure unaligned pointers are wrapped properly.
1444  char* data = i::StrDup("0123456789");
1445  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1446  Local<v8::Value> one = v8::External::Wrap(&data[1]);
1447  Local<v8::Value> two = v8::External::Wrap(&data[2]);
1448  Local<v8::Value> three = v8::External::Wrap(&data[3]);
1449
1450  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1451  CHECK_EQ('0', *char_ptr);
1452  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1453  CHECK_EQ('1', *char_ptr);
1454  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1455  CHECK_EQ('2', *char_ptr);
1456  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1457  CHECK_EQ('3', *char_ptr);
1458  i::DeleteArray(data);
1459}
1460
1461
1462THREADED_TEST(GlobalHandle) {
1463  v8::Persistent<String> global;
1464  {
1465    v8::HandleScope scope;
1466    Local<String> str = v8_str("str");
1467    global = v8::Persistent<String>::New(str);
1468  }
1469  CHECK_EQ(global->Length(), 3);
1470  global.Dispose();
1471}
1472
1473
1474THREADED_TEST(ScriptException) {
1475  v8::HandleScope scope;
1476  LocalContext env;
1477  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1478  v8::TryCatch try_catch;
1479  Local<Value> result = script->Run();
1480  CHECK(result.IsEmpty());
1481  CHECK(try_catch.HasCaught());
1482  String::AsciiValue exception_value(try_catch.Exception());
1483  CHECK_EQ(*exception_value, "panama!");
1484}
1485
1486
1487bool message_received;
1488
1489
1490static void check_message(v8::Handle<v8::Message> message,
1491                          v8::Handle<Value> data) {
1492  CHECK_EQ(5.76, data->NumberValue());
1493  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1494  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1495  message_received = true;
1496}
1497
1498
1499THREADED_TEST(MessageHandlerData) {
1500  message_received = false;
1501  v8::HandleScope scope;
1502  CHECK(!message_received);
1503  v8::V8::AddMessageListener(check_message, v8_num(5.76));
1504  LocalContext context;
1505  v8::ScriptOrigin origin =
1506      v8::ScriptOrigin(v8_str("6.75"));
1507  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1508                                                  &origin);
1509  script->SetData(v8_str("7.56"));
1510  script->Run();
1511  CHECK(message_received);
1512  // clear out the message listener
1513  v8::V8::RemoveMessageListeners(check_message);
1514}
1515
1516
1517THREADED_TEST(GetSetProperty) {
1518  v8::HandleScope scope;
1519  LocalContext context;
1520  context->Global()->Set(v8_str("foo"), v8_num(14));
1521  context->Global()->Set(v8_str("12"), v8_num(92));
1522  context->Global()->Set(v8::Integer::New(16), v8_num(32));
1523  context->Global()->Set(v8_num(13), v8_num(56));
1524  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1525  CHECK_EQ(14, foo->Int32Value());
1526  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1527  CHECK_EQ(92, twelve->Int32Value());
1528  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1529  CHECK_EQ(32, sixteen->Int32Value());
1530  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1531  CHECK_EQ(56, thirteen->Int32Value());
1532  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1533  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1534  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1535  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1536  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1537  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1538  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1539  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1540  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1541}
1542
1543
1544THREADED_TEST(PropertyAttributes) {
1545  v8::HandleScope scope;
1546  LocalContext context;
1547  // read-only
1548  Local<String> prop = v8_str("read_only");
1549  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1550  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1551  Script::Compile(v8_str("read_only = 9"))->Run();
1552  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1553  context->Global()->Set(prop, v8_num(10));
1554  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1555  // dont-delete
1556  prop = v8_str("dont_delete");
1557  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1558  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1559  Script::Compile(v8_str("delete dont_delete"))->Run();
1560  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1561}
1562
1563
1564THREADED_TEST(Array) {
1565  v8::HandleScope scope;
1566  LocalContext context;
1567  Local<v8::Array> array = v8::Array::New();
1568  CHECK_EQ(0, array->Length());
1569  CHECK(array->Get(v8::Integer::New(0))->IsUndefined());
1570  CHECK(!array->Has(0));
1571  CHECK(array->Get(v8::Integer::New(100))->IsUndefined());
1572  CHECK(!array->Has(100));
1573  array->Set(v8::Integer::New(2), v8_num(7));
1574  CHECK_EQ(3, array->Length());
1575  CHECK(!array->Has(0));
1576  CHECK(!array->Has(1));
1577  CHECK(array->Has(2));
1578  CHECK_EQ(7, array->Get(v8::Integer::New(2))->Int32Value());
1579  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1580  Local<v8::Array> arr = Local<v8::Array>::Cast(obj);
1581  CHECK_EQ(3, arr->Length());
1582  CHECK_EQ(1, arr->Get(v8::Integer::New(0))->Int32Value());
1583  CHECK_EQ(2, arr->Get(v8::Integer::New(1))->Int32Value());
1584  CHECK_EQ(3, arr->Get(v8::Integer::New(2))->Int32Value());
1585}
1586
1587
1588v8::Handle<Value> HandleF(const v8::Arguments& args) {
1589  v8::HandleScope scope;
1590  ApiTestFuzzer::Fuzz();
1591  Local<v8::Array> result = v8::Array::New(args.Length());
1592  for (int i = 0; i < args.Length(); i++)
1593    result->Set(v8::Integer::New(i), args[i]);
1594  return scope.Close(result);
1595}
1596
1597
1598THREADED_TEST(Vector) {
1599  v8::HandleScope scope;
1600  Local<ObjectTemplate> global = ObjectTemplate::New();
1601  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1602  LocalContext context(0, global);
1603
1604  const char* fun = "f()";
1605  Local<v8::Array> a0 =
1606      Local<v8::Array>::Cast(Script::Compile(String::New(fun))->Run());
1607  CHECK_EQ(0, a0->Length());
1608
1609  const char* fun2 = "f(11)";
1610  Local<v8::Array> a1 =
1611      Local<v8::Array>::Cast(Script::Compile(String::New(fun2))->Run());
1612  CHECK_EQ(1, a1->Length());
1613  CHECK_EQ(11, a1->Get(v8::Integer::New(0))->Int32Value());
1614
1615  const char* fun3 = "f(12, 13)";
1616  Local<v8::Array> a2 =
1617      Local<v8::Array>::Cast(Script::Compile(String::New(fun3))->Run());
1618  CHECK_EQ(2, a2->Length());
1619  CHECK_EQ(12, a2->Get(v8::Integer::New(0))->Int32Value());
1620  CHECK_EQ(13, a2->Get(v8::Integer::New(1))->Int32Value());
1621
1622  const char* fun4 = "f(14, 15, 16)";
1623  Local<v8::Array> a3 =
1624      Local<v8::Array>::Cast(Script::Compile(String::New(fun4))->Run());
1625  CHECK_EQ(3, a3->Length());
1626  CHECK_EQ(14, a3->Get(v8::Integer::New(0))->Int32Value());
1627  CHECK_EQ(15, a3->Get(v8::Integer::New(1))->Int32Value());
1628  CHECK_EQ(16, a3->Get(v8::Integer::New(2))->Int32Value());
1629
1630  const char* fun5 = "f(17, 18, 19, 20)";
1631  Local<v8::Array> a4 =
1632      Local<v8::Array>::Cast(Script::Compile(String::New(fun5))->Run());
1633  CHECK_EQ(4, a4->Length());
1634  CHECK_EQ(17, a4->Get(v8::Integer::New(0))->Int32Value());
1635  CHECK_EQ(18, a4->Get(v8::Integer::New(1))->Int32Value());
1636  CHECK_EQ(19, a4->Get(v8::Integer::New(2))->Int32Value());
1637  CHECK_EQ(20, a4->Get(v8::Integer::New(3))->Int32Value());
1638}
1639
1640
1641THREADED_TEST(FunctionCall) {
1642  v8::HandleScope scope;
1643  LocalContext context;
1644  CompileRun(
1645    "function Foo() {"
1646    "  var result = [];"
1647    "  for (var i = 0; i < arguments.length; i++) {"
1648    "    result.push(arguments[i]);"
1649    "  }"
1650    "  return result;"
1651    "}");
1652  Local<Function> Foo =
1653      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1654
1655  v8::Handle<Value>* args0 = NULL;
1656  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1657  CHECK_EQ(0, a0->Length());
1658
1659  v8::Handle<Value> args1[] = { v8_num(1.1) };
1660  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1661  CHECK_EQ(1, a1->Length());
1662  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1663
1664  v8::Handle<Value> args2[] = { v8_num(2.2),
1665                                v8_num(3.3) };
1666  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1667  CHECK_EQ(2, a2->Length());
1668  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1669  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1670
1671  v8::Handle<Value> args3[] = { v8_num(4.4),
1672                                v8_num(5.5),
1673                                v8_num(6.6) };
1674  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1675  CHECK_EQ(3, a3->Length());
1676  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1677  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1678  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1679
1680  v8::Handle<Value> args4[] = { v8_num(7.7),
1681                                v8_num(8.8),
1682                                v8_num(9.9),
1683                                v8_num(10.11) };
1684  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1685  CHECK_EQ(4, a4->Length());
1686  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1687  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1688  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1689  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1690}
1691
1692
1693static const char* js_code_causing_out_of_memory =
1694    "var a = new Array(); while(true) a.push(a);";
1695
1696
1697// These tests run for a long time and prevent us from running tests
1698// that come after them so they cannot run in parallel.
1699TEST(OutOfMemory) {
1700  // It's not possible to read a snapshot into a heap with different dimensions.
1701  if (v8::internal::Snapshot::IsEnabled()) return;
1702  // Set heap limits.
1703  static const int K = 1024;
1704  v8::ResourceConstraints constraints;
1705  constraints.set_max_young_space_size(256 * K);
1706  constraints.set_max_old_space_size(4 * K * K);
1707  v8::SetResourceConstraints(&constraints);
1708
1709  // Execute a script that causes out of memory.
1710  v8::HandleScope scope;
1711  LocalContext context;
1712  v8::V8::IgnoreOutOfMemoryException();
1713  Local<Script> script =
1714      Script::Compile(String::New(js_code_causing_out_of_memory));
1715  Local<Value> result = script->Run();
1716
1717  // Check for out of memory state.
1718  CHECK(result.IsEmpty());
1719  CHECK(context->HasOutOfMemoryException());
1720}
1721
1722
1723v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1724  ApiTestFuzzer::Fuzz();
1725
1726  v8::HandleScope scope;
1727  LocalContext context;
1728  Local<Script> script =
1729      Script::Compile(String::New(js_code_causing_out_of_memory));
1730  Local<Value> result = script->Run();
1731
1732  // Check for out of memory state.
1733  CHECK(result.IsEmpty());
1734  CHECK(context->HasOutOfMemoryException());
1735
1736  return result;
1737}
1738
1739
1740TEST(OutOfMemoryNested) {
1741  // It's not possible to read a snapshot into a heap with different dimensions.
1742  if (v8::internal::Snapshot::IsEnabled()) return;
1743  // Set heap limits.
1744  static const int K = 1024;
1745  v8::ResourceConstraints constraints;
1746  constraints.set_max_young_space_size(256 * K);
1747  constraints.set_max_old_space_size(4 * K * K);
1748  v8::SetResourceConstraints(&constraints);
1749
1750  v8::HandleScope scope;
1751  Local<ObjectTemplate> templ = ObjectTemplate::New();
1752  templ->Set(v8_str("ProvokeOutOfMemory"),
1753             v8::FunctionTemplate::New(ProvokeOutOfMemory));
1754  LocalContext context(0, templ);
1755  v8::V8::IgnoreOutOfMemoryException();
1756  Local<Value> result = CompileRun(
1757    "var thrown = false;"
1758    "try {"
1759    "  ProvokeOutOfMemory();"
1760    "} catch (e) {"
1761    "  thrown = true;"
1762    "}");
1763  // Check for out of memory state.
1764  CHECK(result.IsEmpty());
1765  CHECK(context->HasOutOfMemoryException());
1766}
1767
1768
1769TEST(HugeConsStringOutOfMemory) {
1770  // It's not possible to read a snapshot into a heap with different dimensions.
1771  if (v8::internal::Snapshot::IsEnabled()) return;
1772  v8::HandleScope scope;
1773  LocalContext context;
1774  // Set heap limits.
1775  static const int K = 1024;
1776  v8::ResourceConstraints constraints;
1777  constraints.set_max_young_space_size(256 * K);
1778  constraints.set_max_old_space_size(2 * K * K);
1779  v8::SetResourceConstraints(&constraints);
1780
1781  // Execute a script that causes out of memory.
1782  v8::V8::IgnoreOutOfMemoryException();
1783
1784  // Build huge string. This should fail with out of memory exception.
1785  Local<Value> result = CompileRun(
1786    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
1787    "for (var i = 0; i < 22; i++) { str = str + str; }");
1788
1789  // Check for out of memory state.
1790  CHECK(result.IsEmpty());
1791  CHECK(context->HasOutOfMemoryException());
1792}
1793
1794
1795THREADED_TEST(ConstructCall) {
1796  v8::HandleScope scope;
1797  LocalContext context;
1798  CompileRun(
1799    "function Foo() {"
1800    "  var result = [];"
1801    "  for (var i = 0; i < arguments.length; i++) {"
1802    "    result.push(arguments[i]);"
1803    "  }"
1804    "  return result;"
1805    "}");
1806  Local<Function> Foo =
1807      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1808
1809  v8::Handle<Value>* args0 = NULL;
1810  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
1811  CHECK_EQ(0, a0->Length());
1812
1813  v8::Handle<Value> args1[] = { v8_num(1.1) };
1814  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
1815  CHECK_EQ(1, a1->Length());
1816  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1817
1818  v8::Handle<Value> args2[] = { v8_num(2.2),
1819                                v8_num(3.3) };
1820  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
1821  CHECK_EQ(2, a2->Length());
1822  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1823  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1824
1825  v8::Handle<Value> args3[] = { v8_num(4.4),
1826                                v8_num(5.5),
1827                                v8_num(6.6) };
1828  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
1829  CHECK_EQ(3, a3->Length());
1830  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1831  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1832  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1833
1834  v8::Handle<Value> args4[] = { v8_num(7.7),
1835                                v8_num(8.8),
1836                                v8_num(9.9),
1837                                v8_num(10.11) };
1838  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
1839  CHECK_EQ(4, a4->Length());
1840  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1841  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1842  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1843  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1844}
1845
1846
1847static void CheckUncle(v8::TryCatch* try_catch) {
1848  CHECK(try_catch->HasCaught());
1849  String::AsciiValue str_value(try_catch->Exception());
1850  CHECK_EQ(*str_value, "uncle?");
1851  try_catch->Reset();
1852}
1853
1854
1855THREADED_TEST(ConversionException) {
1856  v8::HandleScope scope;
1857  LocalContext env;
1858  CompileRun(
1859    "function TestClass() { };"
1860    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
1861    "var obj = new TestClass();");
1862  Local<Value> obj = env->Global()->Get(v8_str("obj"));
1863
1864  v8::TryCatch try_catch;
1865
1866  Local<Value> to_string_result = obj->ToString();
1867  CHECK(to_string_result.IsEmpty());
1868  CheckUncle(&try_catch);
1869
1870  Local<Value> to_number_result = obj->ToNumber();
1871  CHECK(to_number_result.IsEmpty());
1872  CheckUncle(&try_catch);
1873
1874  Local<Value> to_integer_result = obj->ToInteger();
1875  CHECK(to_integer_result.IsEmpty());
1876  CheckUncle(&try_catch);
1877
1878  Local<Value> to_uint32_result = obj->ToUint32();
1879  CHECK(to_uint32_result.IsEmpty());
1880  CheckUncle(&try_catch);
1881
1882  Local<Value> to_int32_result = obj->ToInt32();
1883  CHECK(to_int32_result.IsEmpty());
1884  CheckUncle(&try_catch);
1885
1886  Local<Value> to_object_result = v8::Undefined()->ToObject();
1887  CHECK(to_object_result.IsEmpty());
1888  CHECK(try_catch.HasCaught());
1889  try_catch.Reset();
1890
1891  int32_t int32_value = obj->Int32Value();
1892  CHECK_EQ(0, int32_value);
1893  CheckUncle(&try_catch);
1894
1895  uint32_t uint32_value = obj->Uint32Value();
1896  CHECK_EQ(0, uint32_value);
1897  CheckUncle(&try_catch);
1898
1899  double number_value = obj->NumberValue();
1900  CHECK_NE(0, IsNaN(number_value));
1901  CheckUncle(&try_catch);
1902
1903  int64_t integer_value = obj->IntegerValue();
1904  CHECK_EQ(0.0, static_cast<double>(integer_value));
1905  CheckUncle(&try_catch);
1906}
1907
1908
1909v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
1910  ApiTestFuzzer::Fuzz();
1911  return v8::ThrowException(v8_str("konto"));
1912}
1913
1914
1915v8::Handle<Value> CCatcher(const v8::Arguments& args) {
1916  if (args.Length() < 1) return v8::Boolean::New(false);
1917  v8::HandleScope scope;
1918  v8::TryCatch try_catch;
1919  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
1920  CHECK(!try_catch.HasCaught() || result.IsEmpty());
1921  return v8::Boolean::New(try_catch.HasCaught());
1922}
1923
1924
1925THREADED_TEST(APICatch) {
1926  v8::HandleScope scope;
1927  Local<ObjectTemplate> templ = ObjectTemplate::New();
1928  templ->Set(v8_str("ThrowFromC"),
1929             v8::FunctionTemplate::New(ThrowFromC));
1930  LocalContext context(0, templ);
1931  CompileRun(
1932    "var thrown = false;"
1933    "try {"
1934    "  ThrowFromC();"
1935    "} catch (e) {"
1936    "  thrown = true;"
1937    "}");
1938  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
1939  CHECK(thrown->BooleanValue());
1940}
1941
1942
1943THREADED_TEST(APIThrowTryCatch) {
1944  v8::HandleScope scope;
1945  Local<ObjectTemplate> templ = ObjectTemplate::New();
1946  templ->Set(v8_str("ThrowFromC"),
1947             v8::FunctionTemplate::New(ThrowFromC));
1948  LocalContext context(0, templ);
1949  v8::TryCatch try_catch;
1950  CompileRun("ThrowFromC();");
1951  CHECK(try_catch.HasCaught());
1952}
1953
1954
1955// Test that a try-finally block doesn't shadow a try-catch block
1956// when setting up an external handler.
1957//
1958// BUG(271): Some of the exception propagation does not work on the
1959// ARM simulator because the simulator separates the C++ stack and the
1960// JS stack.  This test therefore fails on the simulator.  The test is
1961// not threaded to allow the threading tests to run on the simulator.
1962TEST(TryCatchInTryFinally) {
1963  v8::HandleScope scope;
1964  Local<ObjectTemplate> templ = ObjectTemplate::New();
1965  templ->Set(v8_str("CCatcher"),
1966             v8::FunctionTemplate::New(CCatcher));
1967  LocalContext context(0, templ);
1968  Local<Value> result = CompileRun("try {"
1969                                   "  try {"
1970                                   "    CCatcher('throw 7;');"
1971                                   "  } finally {"
1972                                   "  }"
1973                                   "} catch (e) {"
1974                                   "}");
1975  CHECK(result->IsTrue());
1976}
1977
1978
1979static void receive_message(v8::Handle<v8::Message> message,
1980                            v8::Handle<v8::Value> data) {
1981  message->Get();
1982  message_received = true;
1983}
1984
1985
1986TEST(APIThrowMessage) {
1987  message_received = false;
1988  v8::HandleScope scope;
1989  v8::V8::AddMessageListener(receive_message);
1990  Local<ObjectTemplate> templ = ObjectTemplate::New();
1991  templ->Set(v8_str("ThrowFromC"),
1992             v8::FunctionTemplate::New(ThrowFromC));
1993  LocalContext context(0, templ);
1994  CompileRun("ThrowFromC();");
1995  CHECK(message_received);
1996  v8::V8::RemoveMessageListeners(check_message);
1997}
1998
1999
2000TEST(APIThrowMessageAndVerboseTryCatch) {
2001  message_received = false;
2002  v8::HandleScope scope;
2003  v8::V8::AddMessageListener(receive_message);
2004  Local<ObjectTemplate> templ = ObjectTemplate::New();
2005  templ->Set(v8_str("ThrowFromC"),
2006             v8::FunctionTemplate::New(ThrowFromC));
2007  LocalContext context(0, templ);
2008  v8::TryCatch try_catch;
2009  try_catch.SetVerbose(true);
2010  Local<Value> result = CompileRun("ThrowFromC();");
2011  CHECK(try_catch.HasCaught());
2012  CHECK(result.IsEmpty());
2013  CHECK(message_received);
2014  v8::V8::RemoveMessageListeners(check_message);
2015}
2016
2017
2018THREADED_TEST(ExternalScriptException) {
2019  v8::HandleScope scope;
2020  Local<ObjectTemplate> templ = ObjectTemplate::New();
2021  templ->Set(v8_str("ThrowFromC"),
2022             v8::FunctionTemplate::New(ThrowFromC));
2023  LocalContext context(0, templ);
2024
2025  v8::TryCatch try_catch;
2026  Local<Script> script
2027      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2028  Local<Value> result = script->Run();
2029  CHECK(result.IsEmpty());
2030  CHECK(try_catch.HasCaught());
2031  String::AsciiValue exception_value(try_catch.Exception());
2032  CHECK_EQ("konto", *exception_value);
2033}
2034
2035
2036
2037v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2038  ApiTestFuzzer::Fuzz();
2039  CHECK_EQ(4, args.Length());
2040  int count = args[0]->Int32Value();
2041  int cInterval = args[2]->Int32Value();
2042  if (count == 0) {
2043    return v8::ThrowException(v8_str("FromC"));
2044  } else {
2045    Local<v8::Object> global = Context::GetCurrent()->Global();
2046    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2047    v8::Handle<Value> argv[] = { v8_num(count - 1),
2048                                 args[1],
2049                                 args[2],
2050                                 args[3] };
2051    if (count % cInterval == 0) {
2052      v8::TryCatch try_catch;
2053      Local<Value> result =
2054          v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
2055      int expected = args[3]->Int32Value();
2056      if (try_catch.HasCaught()) {
2057        CHECK_EQ(expected, count);
2058        CHECK(result.IsEmpty());
2059        CHECK(!i::Top::has_scheduled_exception());
2060      } else {
2061        CHECK_NE(expected, count);
2062      }
2063      return result;
2064    } else {
2065      return v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
2066    }
2067  }
2068}
2069
2070
2071v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2072  ApiTestFuzzer::Fuzz();
2073  CHECK_EQ(3, args.Length());
2074  bool equality = args[0]->BooleanValue();
2075  int count = args[1]->Int32Value();
2076  int expected = args[2]->Int32Value();
2077  if (equality) {
2078    CHECK_EQ(count, expected);
2079  } else {
2080    CHECK_NE(count, expected);
2081  }
2082  return v8::Undefined();
2083}
2084
2085
2086THREADED_TEST(EvalInTryFinally) {
2087  v8::HandleScope scope;
2088  LocalContext context;
2089  v8::TryCatch try_catch;
2090  CompileRun("(function() {"
2091             "  try {"
2092             "    eval('asldkf (*&^&*^');"
2093             "  } finally {"
2094             "    return;"
2095             "  }"
2096             "})()");
2097  CHECK(!try_catch.HasCaught());
2098}
2099
2100
2101// This test works by making a stack of alternating JavaScript and C
2102// activations.  These activations set up exception handlers with regular
2103// intervals, one interval for C activations and another for JavaScript
2104// activations.  When enough activations have been created an exception is
2105// thrown and we check that the right activation catches the exception and that
2106// no other activations do.  The right activation is always the topmost one with
2107// a handler, regardless of whether it is in JavaScript or C.
2108//
2109// The notation used to describe a test case looks like this:
2110//
2111//    *JS[4] *C[3] @JS[2] C[1] JS[0]
2112//
2113// Each entry is an activation, either JS or C.  The index is the count at that
2114// level.  Stars identify activations with exception handlers, the @ identifies
2115// the exception handler that should catch the exception.
2116//
2117// BUG(271): Some of the exception propagation does not work on the
2118// ARM simulator because the simulator separates the C++ stack and the
2119// JS stack.  This test therefore fails on the simulator.  The test is
2120// not threaded to allow the threading tests to run on the simulator.
2121TEST(ExceptionOrder) {
2122  v8::HandleScope scope;
2123  Local<ObjectTemplate> templ = ObjectTemplate::New();
2124  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2125  templ->Set(v8_str("CThrowCountDown"),
2126             v8::FunctionTemplate::New(CThrowCountDown));
2127  LocalContext context(0, templ);
2128  CompileRun(
2129    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2130    "  if (count == 0) throw 'FromJS';"
2131    "  if (count % jsInterval == 0) {"
2132    "    try {"
2133    "      var value = CThrowCountDown(count - 1,"
2134    "                                  jsInterval,"
2135    "                                  cInterval,"
2136    "                                  expected);"
2137    "      check(false, count, expected);"
2138    "      return value;"
2139    "    } catch (e) {"
2140    "      check(true, count, expected);"
2141    "    }"
2142    "  } else {"
2143    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2144    "  }"
2145    "}");
2146  Local<Function> fun =
2147      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2148
2149  const int argc = 4;
2150  //                             count      jsInterval cInterval  expected
2151
2152  // *JS[4] *C[3] @JS[2] C[1] JS[0]
2153  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2154  fun->Call(fun, argc, a0);
2155
2156  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2157  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2158  fun->Call(fun, argc, a1);
2159
2160  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2161  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2162  fun->Call(fun, argc, a2);
2163
2164  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2165  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2166  fun->Call(fun, argc, a3);
2167
2168  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2169  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2170  fun->Call(fun, argc, a4);
2171
2172  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2173  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2174  fun->Call(fun, argc, a5);
2175}
2176
2177
2178v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2179  ApiTestFuzzer::Fuzz();
2180  CHECK_EQ(1, args.Length());
2181  return v8::ThrowException(args[0]);
2182}
2183
2184
2185THREADED_TEST(ThrowValues) {
2186  v8::HandleScope scope;
2187  Local<ObjectTemplate> templ = ObjectTemplate::New();
2188  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2189  LocalContext context(0, templ);
2190  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2191    "function Run(obj) {"
2192    "  try {"
2193    "    Throw(obj);"
2194    "  } catch (e) {"
2195    "    return e;"
2196    "  }"
2197    "  return 'no exception';"
2198    "}"
2199    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2200  CHECK_EQ(5, result->Length());
2201  CHECK(result->Get(v8::Integer::New(0))->IsString());
2202  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2203  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2204  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2205  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2206  CHECK(result->Get(v8::Integer::New(3))->IsNull());
2207  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2208}
2209
2210
2211THREADED_TEST(CatchZero) {
2212  v8::HandleScope scope;
2213  LocalContext context;
2214  v8::TryCatch try_catch;
2215  CHECK(!try_catch.HasCaught());
2216  Script::Compile(v8_str("throw 10"))->Run();
2217  CHECK(try_catch.HasCaught());
2218  CHECK_EQ(10, try_catch.Exception()->Int32Value());
2219  try_catch.Reset();
2220  CHECK(!try_catch.HasCaught());
2221  Script::Compile(v8_str("throw 0"))->Run();
2222  CHECK(try_catch.HasCaught());
2223  CHECK_EQ(0, try_catch.Exception()->Int32Value());
2224}
2225
2226
2227THREADED_TEST(CatchExceptionFromWith) {
2228  v8::HandleScope scope;
2229  LocalContext context;
2230  v8::TryCatch try_catch;
2231  CHECK(!try_catch.HasCaught());
2232  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2233  CHECK(try_catch.HasCaught());
2234}
2235
2236
2237THREADED_TEST(Equality) {
2238  v8::HandleScope scope;
2239  LocalContext context;
2240  // Check that equality works at all before relying on CHECK_EQ
2241  CHECK(v8_str("a")->Equals(v8_str("a")));
2242  CHECK(!v8_str("a")->Equals(v8_str("b")));
2243
2244  CHECK_EQ(v8_str("a"), v8_str("a"));
2245  CHECK_NE(v8_str("a"), v8_str("b"));
2246  CHECK_EQ(v8_num(1), v8_num(1));
2247  CHECK_EQ(v8_num(1.00), v8_num(1));
2248  CHECK_NE(v8_num(1), v8_num(2));
2249
2250  // Assume String is not symbol.
2251  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2252  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2253  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2254  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2255  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2256  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2257  Local<Value> not_a_number = v8_num(i::OS::nan_value());
2258  CHECK(!not_a_number->StrictEquals(not_a_number));
2259  CHECK(v8::False()->StrictEquals(v8::False()));
2260  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2261
2262  v8::Handle<v8::Object> obj = v8::Object::New();
2263  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2264  CHECK(alias->StrictEquals(obj));
2265  alias.Dispose();
2266}
2267
2268
2269THREADED_TEST(MultiRun) {
2270  v8::HandleScope scope;
2271  LocalContext context;
2272  Local<Script> script = Script::Compile(v8_str("x"));
2273  for (int i = 0; i < 10; i++)
2274    script->Run();
2275}
2276
2277
2278static v8::Handle<Value> GetXValue(Local<String> name,
2279                                   const AccessorInfo& info) {
2280  ApiTestFuzzer::Fuzz();
2281  CHECK_EQ(info.Data(), v8_str("donut"));
2282  CHECK_EQ(name, v8_str("x"));
2283  return name;
2284}
2285
2286
2287THREADED_TEST(SimplePropertyRead) {
2288  v8::HandleScope scope;
2289  Local<ObjectTemplate> templ = ObjectTemplate::New();
2290  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2291  LocalContext context;
2292  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2293  Local<Script> script = Script::Compile(v8_str("obj.x"));
2294  for (int i = 0; i < 10; i++) {
2295    Local<Value> result = script->Run();
2296    CHECK_EQ(result, v8_str("x"));
2297  }
2298}
2299
2300
2301v8::Persistent<Value> xValue;
2302
2303
2304static void SetXValue(Local<String> name,
2305                      Local<Value> value,
2306                      const AccessorInfo& info) {
2307  CHECK_EQ(value, v8_num(4));
2308  CHECK_EQ(info.Data(), v8_str("donut"));
2309  CHECK_EQ(name, v8_str("x"));
2310  CHECK(xValue.IsEmpty());
2311  xValue = v8::Persistent<Value>::New(value);
2312}
2313
2314
2315THREADED_TEST(SimplePropertyWrite) {
2316  v8::HandleScope scope;
2317  Local<ObjectTemplate> templ = ObjectTemplate::New();
2318  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2319  LocalContext context;
2320  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2321  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2322  for (int i = 0; i < 10; i++) {
2323    CHECK(xValue.IsEmpty());
2324    script->Run();
2325    CHECK_EQ(v8_num(4), xValue);
2326    xValue.Dispose();
2327    xValue = v8::Persistent<Value>();
2328  }
2329}
2330
2331
2332static v8::Handle<Value> XPropertyGetter(Local<String> property,
2333                                         const AccessorInfo& info) {
2334  ApiTestFuzzer::Fuzz();
2335  CHECK(info.Data()->IsUndefined());
2336  return property;
2337}
2338
2339
2340THREADED_TEST(NamedInterceptorPropertyRead) {
2341  v8::HandleScope scope;
2342  Local<ObjectTemplate> templ = ObjectTemplate::New();
2343  templ->SetNamedPropertyHandler(XPropertyGetter);
2344  LocalContext context;
2345  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2346  Local<Script> script = Script::Compile(v8_str("obj.x"));
2347  for (int i = 0; i < 10; i++) {
2348    Local<Value> result = script->Run();
2349    CHECK_EQ(result, v8_str("x"));
2350  }
2351}
2352
2353
2354static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
2355                                               const AccessorInfo& info) {
2356  ApiTestFuzzer::Fuzz();
2357  if (index == 37) {
2358    return v8::Handle<Value>(v8_num(625));
2359  }
2360  return v8::Handle<Value>();
2361}
2362
2363
2364static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
2365                                               Local<Value> value,
2366                                               const AccessorInfo& info) {
2367  ApiTestFuzzer::Fuzz();
2368  if (index == 39) {
2369    return value;
2370  }
2371  return v8::Handle<Value>();
2372}
2373
2374
2375THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
2376  v8::HandleScope scope;
2377  Local<ObjectTemplate> templ = ObjectTemplate::New();
2378  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
2379                                   IndexedPropertySetter);
2380  LocalContext context;
2381  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2382  Local<Script> getter_script = Script::Compile(v8_str(
2383      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
2384  Local<Script> setter_script = Script::Compile(v8_str(
2385      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
2386      "obj[17] = 23;"
2387      "obj.foo;"));
2388  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
2389      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
2390      "obj[39] = 47;"
2391      "obj.foo;"));  // This setter should not run, due to the interceptor.
2392  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
2393      "obj[37];"));
2394  Local<Value> result = getter_script->Run();
2395  CHECK_EQ(v8_num(5), result);
2396  result = setter_script->Run();
2397  CHECK_EQ(v8_num(23), result);
2398  result = interceptor_setter_script->Run();
2399  CHECK_EQ(v8_num(23), result);
2400  result = interceptor_getter_script->Run();
2401  CHECK_EQ(v8_num(625), result);
2402}
2403
2404
2405static v8::Handle<Value> IdentityIndexedPropertyGetter(
2406    uint32_t index,
2407    const AccessorInfo& info) {
2408  return v8::Integer::New(index);
2409}
2410
2411
2412THREADED_TEST(IndexedInterceptorWithNoSetter) {
2413  v8::HandleScope scope;
2414  Local<ObjectTemplate> templ = ObjectTemplate::New();
2415  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2416
2417  LocalContext context;
2418  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2419
2420  const char* code =
2421      "try {"
2422      "  obj[0] = 239;"
2423      "  for (var i = 0; i < 100; i++) {"
2424      "    var v = obj[0];"
2425      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
2426      "  }"
2427      "  'PASSED'"
2428      "} catch(e) {"
2429      "  e"
2430      "}";
2431  ExpectString(code, "PASSED");
2432}
2433
2434
2435THREADED_TEST(MultiContexts) {
2436  v8::HandleScope scope;
2437  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
2438  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
2439
2440  Local<String> password = v8_str("Password");
2441
2442  // Create an environment
2443  LocalContext context0(0, templ);
2444  context0->SetSecurityToken(password);
2445  v8::Handle<v8::Object> global0 = context0->Global();
2446  global0->Set(v8_str("custom"), v8_num(1234));
2447  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2448
2449  // Create an independent environment
2450  LocalContext context1(0, templ);
2451  context1->SetSecurityToken(password);
2452  v8::Handle<v8::Object> global1 = context1->Global();
2453  global1->Set(v8_str("custom"), v8_num(1234));
2454  CHECK_NE(global0, global1);
2455  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2456  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
2457
2458  // Now create a new context with the old global
2459  LocalContext context2(0, templ, global1);
2460  context2->SetSecurityToken(password);
2461  v8::Handle<v8::Object> global2 = context2->Global();
2462  CHECK_EQ(global1, global2);
2463  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
2464  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
2465}
2466
2467
2468THREADED_TEST(FunctionPrototypeAcrossContexts) {
2469  // Make sure that functions created by cloning boilerplates cannot
2470  // communicate through their __proto__ field.
2471
2472  v8::HandleScope scope;
2473
2474  LocalContext env0;
2475  v8::Handle<v8::Object> global0 =
2476      env0->Global();
2477  v8::Handle<v8::Object> object0 =
2478      v8::Handle<v8::Object>::Cast(global0->Get(v8_str("Object")));
2479  v8::Handle<v8::Object> tostring0 =
2480      v8::Handle<v8::Object>::Cast(object0->Get(v8_str("toString")));
2481  v8::Handle<v8::Object> proto0 =
2482      v8::Handle<v8::Object>::Cast(tostring0->Get(v8_str("__proto__")));
2483  proto0->Set(v8_str("custom"), v8_num(1234));
2484
2485  LocalContext env1;
2486  v8::Handle<v8::Object> global1 =
2487      env1->Global();
2488  v8::Handle<v8::Object> object1 =
2489      v8::Handle<v8::Object>::Cast(global1->Get(v8_str("Object")));
2490  v8::Handle<v8::Object> tostring1 =
2491      v8::Handle<v8::Object>::Cast(object1->Get(v8_str("toString")));
2492  v8::Handle<v8::Object> proto1 =
2493      v8::Handle<v8::Object>::Cast(tostring1->Get(v8_str("__proto__")));
2494  CHECK(!proto1->Has(v8_str("custom")));
2495}
2496
2497
2498THREADED_TEST(Regress892105) {
2499  // Make sure that object and array literals created by cloning
2500  // boilerplates cannot communicate through their __proto__
2501  // field. This is rather difficult to check, but we try to add stuff
2502  // to Object.prototype and Array.prototype and create a new
2503  // environment. This should succeed.
2504
2505  v8::HandleScope scope;
2506
2507  Local<String> source = v8_str("Object.prototype.obj = 1234;"
2508                                "Array.prototype.arr = 4567;"
2509                                "8901");
2510
2511  LocalContext env0;
2512  Local<Script> script0 = Script::Compile(source);
2513  CHECK_EQ(8901.0, script0->Run()->NumberValue());
2514
2515  LocalContext env1;
2516  Local<Script> script1 = Script::Compile(source);
2517  CHECK_EQ(8901.0, script1->Run()->NumberValue());
2518}
2519
2520
2521THREADED_TEST(UndetectableObject) {
2522  v8::HandleScope scope;
2523  LocalContext env;
2524
2525  Local<v8::FunctionTemplate> desc =
2526      v8::FunctionTemplate::New(0, v8::Handle<Value>());
2527  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
2528
2529  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
2530  env->Global()->Set(v8_str("undetectable"), obj);
2531
2532  ExpectString("undetectable.toString()", "[object Object]");
2533  ExpectString("typeof undetectable", "undefined");
2534  ExpectString("typeof(undetectable)", "undefined");
2535  ExpectBoolean("typeof undetectable == 'undefined'", true);
2536  ExpectBoolean("typeof undetectable == 'object'", false);
2537  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2538  ExpectBoolean("!undetectable", true);
2539
2540  ExpectObject("true&&undetectable", obj);
2541  ExpectBoolean("false&&undetectable", false);
2542  ExpectBoolean("true||undetectable", true);
2543  ExpectObject("false||undetectable", obj);
2544
2545  ExpectObject("undetectable&&true", obj);
2546  ExpectObject("undetectable&&false", obj);
2547  ExpectBoolean("undetectable||true", true);
2548  ExpectBoolean("undetectable||false", false);
2549
2550  ExpectBoolean("undetectable==null", true);
2551  ExpectBoolean("null==undetectable", true);
2552  ExpectBoolean("undetectable==undefined", true);
2553  ExpectBoolean("undefined==undetectable", true);
2554  ExpectBoolean("undetectable==undetectable", true);
2555
2556
2557  ExpectBoolean("undetectable===null", false);
2558  ExpectBoolean("null===undetectable", false);
2559  ExpectBoolean("undetectable===undefined", false);
2560  ExpectBoolean("undefined===undetectable", false);
2561  ExpectBoolean("undetectable===undetectable", true);
2562}
2563
2564
2565THREADED_TEST(UndetectableString) {
2566  v8::HandleScope scope;
2567  LocalContext env;
2568
2569  Local<String> obj = String::NewUndetectable("foo");
2570  env->Global()->Set(v8_str("undetectable"), obj);
2571
2572  ExpectString("undetectable", "foo");
2573  ExpectString("typeof undetectable", "undefined");
2574  ExpectString("typeof(undetectable)", "undefined");
2575  ExpectBoolean("typeof undetectable == 'undefined'", true);
2576  ExpectBoolean("typeof undetectable == 'string'", false);
2577  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2578  ExpectBoolean("!undetectable", true);
2579
2580  ExpectObject("true&&undetectable", obj);
2581  ExpectBoolean("false&&undetectable", false);
2582  ExpectBoolean("true||undetectable", true);
2583  ExpectObject("false||undetectable", obj);
2584
2585  ExpectObject("undetectable&&true", obj);
2586  ExpectObject("undetectable&&false", obj);
2587  ExpectBoolean("undetectable||true", true);
2588  ExpectBoolean("undetectable||false", false);
2589
2590  ExpectBoolean("undetectable==null", true);
2591  ExpectBoolean("null==undetectable", true);
2592  ExpectBoolean("undetectable==undefined", true);
2593  ExpectBoolean("undefined==undetectable", true);
2594  ExpectBoolean("undetectable==undetectable", true);
2595
2596
2597  ExpectBoolean("undetectable===null", false);
2598  ExpectBoolean("null===undetectable", false);
2599  ExpectBoolean("undetectable===undefined", false);
2600  ExpectBoolean("undefined===undetectable", false);
2601  ExpectBoolean("undetectable===undetectable", true);
2602}
2603
2604
2605template <typename T> static void USE(T) { }
2606
2607
2608// This test is not intended to be run, just type checked.
2609static void PersistentHandles() {
2610  USE(PersistentHandles);
2611  Local<String> str = v8_str("foo");
2612  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
2613  USE(p_str);
2614  Local<Script> scr = Script::Compile(v8_str(""));
2615  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
2616  USE(p_scr);
2617  Local<ObjectTemplate> templ = ObjectTemplate::New();
2618  v8::Persistent<ObjectTemplate> p_templ =
2619    v8::Persistent<ObjectTemplate>::New(templ);
2620  USE(p_templ);
2621}
2622
2623
2624static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
2625  ApiTestFuzzer::Fuzz();
2626  return v8::Undefined();
2627}
2628
2629
2630THREADED_TEST(GlobalObjectTemplate) {
2631  v8::HandleScope handle_scope;
2632  Local<ObjectTemplate> global_template = ObjectTemplate::New();
2633  global_template->Set(v8_str("JSNI_Log"),
2634                       v8::FunctionTemplate::New(HandleLogDelegator));
2635  v8::Persistent<Context> context = Context::New(0, global_template);
2636  Context::Scope context_scope(context);
2637  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
2638  context.Dispose();
2639}
2640
2641
2642static const char* kSimpleExtensionSource =
2643  "function Foo() {"
2644  "  return 4;"
2645  "}";
2646
2647
2648THREADED_TEST(SimpleExtensions) {
2649  v8::HandleScope handle_scope;
2650  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
2651  const char* extension_names[] = { "simpletest" };
2652  v8::ExtensionConfiguration extensions(1, extension_names);
2653  v8::Handle<Context> context = Context::New(&extensions);
2654  Context::Scope lock(context);
2655  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
2656  CHECK_EQ(result, v8::Integer::New(4));
2657}
2658
2659
2660static const char* kEvalExtensionSource1 =
2661  "function UseEval1() {"
2662  "  var x = 42;"
2663  "  return eval('x');"
2664  "}";
2665
2666
2667static const char* kEvalExtensionSource2 =
2668  "(function() {"
2669  "  var x = 42;"
2670  "  function e() {"
2671  "    return eval('x');"
2672  "  }"
2673  "  this.UseEval2 = e;"
2674  "})()";
2675
2676
2677THREADED_TEST(UseEvalFromExtension) {
2678  v8::HandleScope handle_scope;
2679  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
2680  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
2681  const char* extension_names[] = { "evaltest1", "evaltest2" };
2682  v8::ExtensionConfiguration extensions(2, extension_names);
2683  v8::Handle<Context> context = Context::New(&extensions);
2684  Context::Scope lock(context);
2685  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
2686  CHECK_EQ(result, v8::Integer::New(42));
2687  result = Script::Compile(v8_str("UseEval2()"))->Run();
2688  CHECK_EQ(result, v8::Integer::New(42));
2689}
2690
2691
2692static const char* kWithExtensionSource1 =
2693  "function UseWith1() {"
2694  "  var x = 42;"
2695  "  with({x:87}) { return x; }"
2696  "}";
2697
2698
2699
2700static const char* kWithExtensionSource2 =
2701  "(function() {"
2702  "  var x = 42;"
2703  "  function e() {"
2704  "    with ({x:87}) { return x; }"
2705  "  }"
2706  "  this.UseWith2 = e;"
2707  "})()";
2708
2709
2710THREADED_TEST(UseWithFromExtension) {
2711  v8::HandleScope handle_scope;
2712  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
2713  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
2714  const char* extension_names[] = { "withtest1", "withtest2" };
2715  v8::ExtensionConfiguration extensions(2, extension_names);
2716  v8::Handle<Context> context = Context::New(&extensions);
2717  Context::Scope lock(context);
2718  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
2719  CHECK_EQ(result, v8::Integer::New(87));
2720  result = Script::Compile(v8_str("UseWith2()"))->Run();
2721  CHECK_EQ(result, v8::Integer::New(87));
2722}
2723
2724
2725THREADED_TEST(AutoExtensions) {
2726  v8::HandleScope handle_scope;
2727  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
2728  extension->set_auto_enable(true);
2729  v8::RegisterExtension(extension);
2730  v8::Handle<Context> context = Context::New();
2731  Context::Scope lock(context);
2732  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
2733  CHECK_EQ(result, v8::Integer::New(4));
2734}
2735
2736
2737static const char* kSyntaxErrorInExtensionSource =
2738    "[";
2739
2740
2741// Test that a syntax error in an extension does not cause a fatal
2742// error but results in an empty context.
2743THREADED_TEST(SyntaxErrorExtensions) {
2744  v8::HandleScope handle_scope;
2745  v8::RegisterExtension(new Extension("syntaxerror",
2746                                      kSyntaxErrorInExtensionSource));
2747  const char* extension_names[] = { "syntaxerror" };
2748  v8::ExtensionConfiguration extensions(1, extension_names);
2749  v8::Handle<Context> context = Context::New(&extensions);
2750  CHECK(context.IsEmpty());
2751}
2752
2753
2754static const char* kExceptionInExtensionSource =
2755    "throw 42";
2756
2757
2758// Test that an exception when installing an extension does not cause
2759// a fatal error but results in an empty context.
2760THREADED_TEST(ExceptionExtensions) {
2761  v8::HandleScope handle_scope;
2762  v8::RegisterExtension(new Extension("exception",
2763                                      kExceptionInExtensionSource));
2764  const char* extension_names[] = { "exception" };
2765  v8::ExtensionConfiguration extensions(1, extension_names);
2766  v8::Handle<Context> context = Context::New(&extensions);
2767  CHECK(context.IsEmpty());
2768}
2769
2770
2771static void CheckDependencies(const char* name, const char* expected) {
2772  v8::HandleScope handle_scope;
2773  v8::ExtensionConfiguration config(1, &name);
2774  LocalContext context(&config);
2775  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
2776}
2777
2778
2779/*
2780 * Configuration:
2781 *
2782 *     /-- B <--\
2783 * A <-          -- D <-- E
2784 *     \-- C <--/
2785 */
2786THREADED_TEST(ExtensionDependency) {
2787  static const char* kEDeps[] = { "D" };
2788  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
2789  static const char* kDDeps[] = { "B", "C" };
2790  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
2791  static const char* kBCDeps[] = { "A" };
2792  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
2793  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
2794  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
2795  CheckDependencies("A", "undefinedA");
2796  CheckDependencies("B", "undefinedAB");
2797  CheckDependencies("C", "undefinedAC");
2798  CheckDependencies("D", "undefinedABCD");
2799  CheckDependencies("E", "undefinedABCDE");
2800  v8::HandleScope handle_scope;
2801  static const char* exts[2] = { "C", "E" };
2802  v8::ExtensionConfiguration config(2, exts);
2803  LocalContext context(&config);
2804  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
2805}
2806
2807
2808static const char* kExtensionTestScript =
2809  "native function A();"
2810  "native function B();"
2811  "native function C();"
2812  "function Foo(i) {"
2813  "  if (i == 0) return A();"
2814  "  if (i == 1) return B();"
2815  "  if (i == 2) return C();"
2816  "}";
2817
2818
2819static v8::Handle<Value> CallFun(const v8::Arguments& args) {
2820  ApiTestFuzzer::Fuzz();
2821  if (args.IsConstructCall()) {
2822    args.This()->Set(v8_str("data"), args.Data());
2823    return v8::Null();
2824  }
2825  return args.Data();
2826}
2827
2828
2829class FunctionExtension : public Extension {
2830 public:
2831  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
2832  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
2833      v8::Handle<String> name);
2834};
2835
2836
2837static int lookup_count = 0;
2838v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
2839      v8::Handle<String> name) {
2840  lookup_count++;
2841  if (name->Equals(v8_str("A"))) {
2842    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
2843  } else if (name->Equals(v8_str("B"))) {
2844    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
2845  } else if (name->Equals(v8_str("C"))) {
2846    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
2847  } else {
2848    return v8::Handle<v8::FunctionTemplate>();
2849  }
2850}
2851
2852
2853THREADED_TEST(FunctionLookup) {
2854  v8::RegisterExtension(new FunctionExtension());
2855  v8::HandleScope handle_scope;
2856  static const char* exts[1] = { "functiontest" };
2857  v8::ExtensionConfiguration config(1, exts);
2858  LocalContext context(&config);
2859  CHECK_EQ(3, lookup_count);
2860  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
2861  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
2862  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
2863}
2864
2865
2866THREADED_TEST(NativeFunctionConstructCall) {
2867  v8::RegisterExtension(new FunctionExtension());
2868  v8::HandleScope handle_scope;
2869  static const char* exts[1] = { "functiontest" };
2870  v8::ExtensionConfiguration config(1, exts);
2871  LocalContext context(&config);
2872  for (int i = 0; i < 10; i++) {
2873    // Run a few times to ensure that allocation of objects doesn't
2874    // change behavior of a constructor function.
2875    CHECK_EQ(v8::Integer::New(8),
2876             Script::Compile(v8_str("(new A()).data"))->Run());
2877    CHECK_EQ(v8::Integer::New(7),
2878             Script::Compile(v8_str("(new B()).data"))->Run());
2879    CHECK_EQ(v8::Integer::New(6),
2880             Script::Compile(v8_str("(new C()).data"))->Run());
2881  }
2882}
2883
2884
2885static const char* last_location;
2886static const char* last_message;
2887void StoringErrorCallback(const char* location, const char* message) {
2888  if (last_location == NULL) {
2889    last_location = location;
2890    last_message = message;
2891  }
2892}
2893
2894
2895// ErrorReporting creates a circular extensions configuration and
2896// tests that the fatal error handler gets called.  This renders V8
2897// unusable and therefore this test cannot be run in parallel.
2898TEST(ErrorReporting) {
2899  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
2900  static const char* aDeps[] = { "B" };
2901  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
2902  static const char* bDeps[] = { "A" };
2903  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
2904  last_location = NULL;
2905  v8::ExtensionConfiguration config(1, bDeps);
2906  v8::Handle<Context> context = Context::New(&config);
2907  CHECK(context.IsEmpty());
2908  CHECK_NE(last_location, NULL);
2909}
2910
2911
2912static const char* js_code_causing_huge_string_flattening =
2913    "var str = 'X';"
2914    "for (var i = 0; i < 30; i++) {"
2915    "  str = str + str;"
2916    "}"
2917    "str.match(/X/);";
2918
2919
2920void OOMCallback(const char* location, const char* message) {
2921  exit(0);
2922}
2923
2924
2925TEST(RegexpOutOfMemory) {
2926  // Execute a script that causes out of memory when flattening a string.
2927  v8::HandleScope scope;
2928  v8::V8::SetFatalErrorHandler(OOMCallback);
2929  LocalContext context;
2930  Local<Script> script =
2931      Script::Compile(String::New(js_code_causing_huge_string_flattening));
2932  last_location = NULL;
2933  Local<Value> result = script->Run();
2934
2935  CHECK(false);  // Should not return.
2936}
2937
2938
2939static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
2940                                             v8::Handle<Value> data) {
2941  CHECK_EQ(v8::Undefined(), data);
2942  CHECK(message->GetScriptResourceName()->IsUndefined());
2943  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
2944  message->GetLineNumber();
2945  message->GetSourceLine();
2946}
2947
2948
2949THREADED_TEST(ErrorWithMissingScriptInfo) {
2950  v8::HandleScope scope;
2951  LocalContext context;
2952  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
2953  Script::Compile(v8_str("throw Error()"))->Run();
2954  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
2955}
2956
2957
2958int global_index = 0;
2959
2960class Snorkel {
2961 public:
2962  Snorkel() { index_ = global_index++; }
2963  int index_;
2964};
2965
2966class Whammy {
2967 public:
2968  Whammy() {
2969    cursor_ = 0;
2970  }
2971  ~Whammy() {
2972    script_.Dispose();
2973  }
2974  v8::Handle<Script> getScript() {
2975    if (script_.IsEmpty())
2976      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
2977    return Local<Script>(*script_);
2978  }
2979
2980 public:
2981  static const int kObjectCount = 256;
2982  int cursor_;
2983  v8::Persistent<v8::Object> objects_[kObjectCount];
2984  v8::Persistent<Script> script_;
2985};
2986
2987static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
2988  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
2989  delete snorkel;
2990  obj.ClearWeak();
2991}
2992
2993v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
2994                                       const AccessorInfo& info) {
2995  Whammy* whammy =
2996    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
2997
2998  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
2999
3000  v8::Handle<v8::Object> obj = v8::Object::New();
3001  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
3002  if (!prev.IsEmpty()) {
3003    prev->Set(v8_str("next"), obj);
3004    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
3005    whammy->objects_[whammy->cursor_].Clear();
3006  }
3007  whammy->objects_[whammy->cursor_] = global;
3008  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
3009  return whammy->getScript()->Run();
3010}
3011
3012THREADED_TEST(WeakReference) {
3013  v8::HandleScope handle_scope;
3014  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
3015  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
3016                                 0, 0, 0, 0,
3017                                 v8::External::New(new Whammy()));
3018  const char* extension_list[] = { "v8/gc" };
3019  v8::ExtensionConfiguration extensions(1, extension_list);
3020  v8::Persistent<Context> context = Context::New(&extensions);
3021  Context::Scope context_scope(context);
3022
3023  v8::Handle<v8::Object> interceptor = templ->NewInstance();
3024  context->Global()->Set(v8_str("whammy"), interceptor);
3025  const char* code =
3026      "var last;"
3027      "for (var i = 0; i < 10000; i++) {"
3028      "  var obj = whammy.length;"
3029      "  if (last) last.next = obj;"
3030      "  last = obj;"
3031      "}"
3032      "gc();"
3033      "4";
3034  v8::Handle<Value> result = CompileRun(code);
3035  CHECK_EQ(4.0, result->NumberValue());
3036
3037  context.Dispose();
3038}
3039
3040
3041static bool in_scavenge = false;
3042static int last = -1;
3043
3044static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
3045  CHECK_EQ(-1, last);
3046  last = 0;
3047  obj.Dispose();
3048  obj.Clear();
3049  in_scavenge = true;
3050  i::Heap::PerformScavenge();
3051  in_scavenge = false;
3052  *(reinterpret_cast<bool*>(data)) = true;
3053}
3054
3055static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
3056                                        void* data) {
3057  CHECK_EQ(0, last);
3058  last = 1;
3059  *(reinterpret_cast<bool*>(data)) = in_scavenge;
3060  obj.Dispose();
3061  obj.Clear();
3062}
3063
3064THREADED_TEST(NoWeakRefCallbacksInScavenge) {
3065  // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
3066  // Calling callbacks from scavenges is unsafe as objects held by those
3067  // handlers might have become strongly reachable, but scavenge doesn't
3068  // check that.
3069  v8::Persistent<Context> context = Context::New();
3070  Context::Scope context_scope(context);
3071
3072  v8::Persistent<v8::Object> object_a;
3073  v8::Persistent<v8::Object> object_b;
3074
3075  {
3076    v8::HandleScope handle_scope;
3077    object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
3078    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
3079  }
3080
3081  bool object_a_disposed = false;
3082  object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
3083  bool released_in_scavenge = false;
3084  object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
3085
3086  while (!object_a_disposed) {
3087    i::Heap::CollectAllGarbage(false);
3088  }
3089  CHECK(!released_in_scavenge);
3090}
3091
3092
3093v8::Handle<Function> args_fun;
3094
3095
3096static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
3097  ApiTestFuzzer::Fuzz();
3098  CHECK_EQ(args_fun, args.Callee());
3099  CHECK_EQ(3, args.Length());
3100  CHECK_EQ(v8::Integer::New(1), args[0]);
3101  CHECK_EQ(v8::Integer::New(2), args[1]);
3102  CHECK_EQ(v8::Integer::New(3), args[2]);
3103  CHECK_EQ(v8::Undefined(), args[3]);
3104  v8::HandleScope scope;
3105  i::Heap::CollectAllGarbage(false);
3106  return v8::Undefined();
3107}
3108
3109
3110THREADED_TEST(Arguments) {
3111  v8::HandleScope scope;
3112  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
3113  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
3114  LocalContext context(NULL, global);
3115  args_fun = v8::Handle<Function>::Cast(context->Global()->Get(v8_str("f")));
3116  v8_compile("f(1, 2, 3)")->Run();
3117}
3118
3119
3120static v8::Handle<Value> NoBlockGetterX(Local<String> name,
3121                                        const AccessorInfo&) {
3122  return v8::Handle<Value>();
3123}
3124
3125
3126static v8::Handle<Value> NoBlockGetterI(uint32_t index,
3127                                        const AccessorInfo&) {
3128  return v8::Handle<Value>();
3129}
3130
3131
3132static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
3133                                        const AccessorInfo&) {
3134  if (!name->Equals(v8_str("foo"))) {
3135    return v8::Handle<v8::Boolean>();  // not intercepted
3136  }
3137
3138  return v8::False();  // intercepted, and don't delete the property
3139}
3140
3141
3142static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
3143  if (index != 2) {
3144    return v8::Handle<v8::Boolean>();  // not intercepted
3145  }
3146
3147  return v8::False();  // intercepted, and don't delete the property
3148}
3149
3150
3151THREADED_TEST(Deleter) {
3152  v8::HandleScope scope;
3153  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3154  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
3155  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
3156  LocalContext context;
3157  context->Global()->Set(v8_str("k"), obj->NewInstance());
3158  CompileRun(
3159    "k.foo = 'foo';"
3160    "k.bar = 'bar';"
3161    "k[2] = 2;"
3162    "k[4] = 4;");
3163  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
3164  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
3165
3166  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
3167  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
3168
3169  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
3170  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
3171
3172  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
3173  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
3174}
3175
3176
3177static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
3178  ApiTestFuzzer::Fuzz();
3179  if (name->Equals(v8_str("foo")) ||
3180      name->Equals(v8_str("bar")) ||
3181      name->Equals(v8_str("baz"))) {
3182    return v8::Undefined();
3183  }
3184  return v8::Handle<Value>();
3185}
3186
3187
3188static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
3189  ApiTestFuzzer::Fuzz();
3190  if (index == 0 || index == 1) return v8::Undefined();
3191  return v8::Handle<Value>();
3192}
3193
3194
3195static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
3196  ApiTestFuzzer::Fuzz();
3197  v8::Handle<v8::Array> result = v8::Array::New(3);
3198  result->Set(v8::Integer::New(0), v8_str("foo"));
3199  result->Set(v8::Integer::New(1), v8_str("bar"));
3200  result->Set(v8::Integer::New(2), v8_str("baz"));
3201  return result;
3202}
3203
3204
3205static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
3206  ApiTestFuzzer::Fuzz();
3207  v8::Handle<v8::Array> result = v8::Array::New(2);
3208  result->Set(v8::Integer::New(0), v8_str("0"));
3209  result->Set(v8::Integer::New(1), v8_str("1"));
3210  return result;
3211}
3212
3213
3214THREADED_TEST(Enumerators) {
3215  v8::HandleScope scope;
3216  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3217  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
3218  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
3219  LocalContext context;
3220  context->Global()->Set(v8_str("k"), obj->NewInstance());
3221  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3222    "k[10] = 0;"
3223    "k.a = 0;"
3224    "k[5] = 0;"
3225    "k.b = 0;"
3226    "k[4294967295] = 0;"
3227    "k.c = 0;"
3228    "k[4294967296] = 0;"
3229    "k.d = 0;"
3230    "k[140000] = 0;"
3231    "k.e = 0;"
3232    "k[30000000000] = 0;"
3233    "k.f = 0;"
3234    "var result = [];"
3235    "for (var prop in k) {"
3236    "  result.push(prop);"
3237    "}"
3238    "result"));
3239  // Check that we get all the property names returned including the
3240  // ones from the enumerators in the right order: indexed properties
3241  // in numerical order, indexed interceptor properties, named
3242  // properties in insertion order, named interceptor properties.
3243  // This order is not mandated by the spec, so this test is just
3244  // documenting our behavior.
3245  CHECK_EQ(17, result->Length());
3246  // Indexed properties in numerical order.
3247  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
3248  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
3249  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
3250  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
3251  // Indexed interceptor properties in the order they are returned
3252  // from the enumerator interceptor.
3253  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
3254  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
3255  // Named properties in insertion order.
3256  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
3257  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
3258  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
3259  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
3260  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
3261  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
3262  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
3263  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
3264  // Named interceptor properties.
3265  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
3266  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
3267  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
3268}
3269
3270
3271int p_getter_count;
3272int p_getter_count2;
3273
3274
3275static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
3276  ApiTestFuzzer::Fuzz();
3277  p_getter_count++;
3278  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3279  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3280  if (name->Equals(v8_str("p1"))) {
3281    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3282  } else if (name->Equals(v8_str("p2"))) {
3283    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3284  } else if (name->Equals(v8_str("p3"))) {
3285    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3286  } else if (name->Equals(v8_str("p4"))) {
3287    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3288  }
3289  return v8::Undefined();
3290}
3291
3292
3293static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
3294  ApiTestFuzzer::Fuzz();
3295  LocalContext context;
3296  context->Global()->Set(v8_str("o1"), obj->NewInstance());
3297  CompileRun(
3298    "o1.__proto__ = { };"
3299    "var o2 = { __proto__: o1 };"
3300    "var o3 = { __proto__: o2 };"
3301    "var o4 = { __proto__: o3 };"
3302    "for (var i = 0; i < 10; i++) o4.p4;"
3303    "for (var i = 0; i < 10; i++) o3.p3;"
3304    "for (var i = 0; i < 10; i++) o2.p2;"
3305    "for (var i = 0; i < 10; i++) o1.p1;");
3306}
3307
3308
3309static v8::Handle<Value> PGetter2(Local<String> name,
3310                                  const AccessorInfo& info) {
3311  ApiTestFuzzer::Fuzz();
3312  p_getter_count2++;
3313  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3314  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3315  if (name->Equals(v8_str("p1"))) {
3316    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3317  } else if (name->Equals(v8_str("p2"))) {
3318    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3319  } else if (name->Equals(v8_str("p3"))) {
3320    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3321  } else if (name->Equals(v8_str("p4"))) {
3322    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3323  }
3324  return v8::Undefined();
3325}
3326
3327
3328THREADED_TEST(GetterHolders) {
3329  v8::HandleScope scope;
3330  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3331  obj->SetAccessor(v8_str("p1"), PGetter);
3332  obj->SetAccessor(v8_str("p2"), PGetter);
3333  obj->SetAccessor(v8_str("p3"), PGetter);
3334  obj->SetAccessor(v8_str("p4"), PGetter);
3335  p_getter_count = 0;
3336  RunHolderTest(obj);
3337  CHECK_EQ(40, p_getter_count);
3338}
3339
3340
3341THREADED_TEST(PreInterceptorHolders) {
3342  v8::HandleScope scope;
3343  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3344  obj->SetNamedPropertyHandler(PGetter2);
3345  p_getter_count2 = 0;
3346  RunHolderTest(obj);
3347  CHECK_EQ(40, p_getter_count2);
3348}
3349
3350
3351THREADED_TEST(ObjectInstantiation) {
3352  v8::HandleScope scope;
3353  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
3354  templ->SetAccessor(v8_str("t"), PGetter2);
3355  LocalContext context;
3356  context->Global()->Set(v8_str("o"), templ->NewInstance());
3357  for (int i = 0; i < 100; i++) {
3358    v8::HandleScope inner_scope;
3359    v8::Handle<v8::Object> obj = templ->NewInstance();
3360    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
3361    context->Global()->Set(v8_str("o2"), obj);
3362    v8::Handle<Value> value =
3363        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
3364    CHECK_EQ(v8::True(), value);
3365    context->Global()->Set(v8_str("o"), obj);
3366  }
3367}
3368
3369
3370THREADED_TEST(StringWrite) {
3371  v8::HandleScope scope;
3372  v8::Handle<String> str = v8_str("abcde");
3373
3374  char buf[100];
3375  int len;
3376
3377  memset(buf, 0x1, sizeof(buf));
3378  len = str->WriteAscii(buf);
3379  CHECK_EQ(len, 5);
3380  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3381
3382  memset(buf, 0x1, sizeof(buf));
3383  len = str->WriteAscii(buf, 0, 4);
3384  CHECK_EQ(len, 4);
3385  CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
3386
3387  memset(buf, 0x1, sizeof(buf));
3388  len = str->WriteAscii(buf, 0, 5);
3389  CHECK_EQ(len, 5);
3390  CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
3391
3392  memset(buf, 0x1, sizeof(buf));
3393  len = str->WriteAscii(buf, 0, 6);
3394  CHECK_EQ(len, 5);
3395  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3396
3397  memset(buf, 0x1, sizeof(buf));
3398  len = str->WriteAscii(buf, 4, -1);
3399  CHECK_EQ(len, 1);
3400  CHECK_EQ(strncmp("e\0", buf, 2), 0);
3401
3402  memset(buf, 0x1, sizeof(buf));
3403  len = str->WriteAscii(buf, 4, 6);
3404  CHECK_EQ(len, 1);
3405  CHECK_EQ(strncmp("e\0", buf, 2), 0);
3406
3407  memset(buf, 0x1, sizeof(buf));
3408  len = str->WriteAscii(buf, 4, 1);
3409  CHECK_EQ(len, 1);
3410  CHECK_EQ(strncmp("e\1", buf, 2), 0);
3411}
3412
3413
3414THREADED_TEST(ToArrayIndex) {
3415  v8::HandleScope scope;
3416  LocalContext context;
3417
3418  v8::Handle<String> str = v8_str("42");
3419  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
3420  CHECK(!index.IsEmpty());
3421  CHECK_EQ(42.0, index->Uint32Value());
3422  str = v8_str("42asdf");
3423  index = str->ToArrayIndex();
3424  CHECK(index.IsEmpty());
3425  str = v8_str("-42");
3426  index = str->ToArrayIndex();
3427  CHECK(index.IsEmpty());
3428  str = v8_str("4294967295");
3429  index = str->ToArrayIndex();
3430  CHECK(!index.IsEmpty());
3431  CHECK_EQ(4294967295.0, index->Uint32Value());
3432  v8::Handle<v8::Number> num = v8::Number::New(1);
3433  index = num->ToArrayIndex();
3434  CHECK(!index.IsEmpty());
3435  CHECK_EQ(1.0, index->Uint32Value());
3436  num = v8::Number::New(-1);
3437  index = num->ToArrayIndex();
3438  CHECK(index.IsEmpty());
3439  v8::Handle<v8::Object> obj = v8::Object::New();
3440  index = obj->ToArrayIndex();
3441  CHECK(index.IsEmpty());
3442}
3443
3444
3445THREADED_TEST(ErrorConstruction) {
3446  v8::HandleScope scope;
3447  LocalContext context;
3448
3449  v8::Handle<String> foo = v8_str("foo");
3450  v8::Handle<String> message = v8_str("message");
3451  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
3452  CHECK(range_error->IsObject());
3453  v8::Handle<v8::Object> range_obj(v8::Handle<v8::Object>::Cast(range_error));
3454  CHECK(v8::Handle<v8::Object>::Cast(range_error)->Get(message)->Equals(foo));
3455  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
3456  CHECK(reference_error->IsObject());
3457  CHECK(
3458      v8::Handle<v8::Object>::Cast(reference_error)->Get(message)->Equals(foo));
3459  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
3460  CHECK(syntax_error->IsObject());
3461  CHECK(v8::Handle<v8::Object>::Cast(syntax_error)->Get(message)->Equals(foo));
3462  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
3463  CHECK(type_error->IsObject());
3464  CHECK(v8::Handle<v8::Object>::Cast(type_error)->Get(message)->Equals(foo));
3465  v8::Handle<Value> error = v8::Exception::Error(foo);
3466  CHECK(error->IsObject());
3467  CHECK(v8::Handle<v8::Object>::Cast(error)->Get(message)->Equals(foo));
3468}
3469
3470
3471static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
3472  ApiTestFuzzer::Fuzz();
3473  return v8_num(10);
3474}
3475
3476
3477static void YSetter(Local<String> name,
3478                    Local<Value> value,
3479                    const AccessorInfo& info) {
3480  if (info.This()->Has(name)) {
3481    info.This()->Delete(name);
3482  }
3483  info.This()->Set(name, value);
3484}
3485
3486
3487THREADED_TEST(DeleteAccessor) {
3488  v8::HandleScope scope;
3489  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3490  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
3491  LocalContext context;
3492  v8::Handle<v8::Object> holder = obj->NewInstance();
3493  context->Global()->Set(v8_str("holder"), holder);
3494  v8::Handle<Value> result = CompileRun(
3495      "holder.y = 11; holder.y = 12; holder.y");
3496  CHECK_EQ(12, result->Uint32Value());
3497}
3498
3499
3500THREADED_TEST(TypeSwitch) {
3501  v8::HandleScope scope;
3502  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
3503  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
3504  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
3505  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
3506  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
3507  LocalContext context;
3508  v8::Handle<v8::Object> obj0 = v8::Object::New();
3509  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
3510  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
3511  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
3512  for (int i = 0; i < 10; i++) {
3513    CHECK_EQ(0, type_switch->match(obj0));
3514    CHECK_EQ(1, type_switch->match(obj1));
3515    CHECK_EQ(2, type_switch->match(obj2));
3516    CHECK_EQ(3, type_switch->match(obj3));
3517    CHECK_EQ(3, type_switch->match(obj3));
3518    CHECK_EQ(2, type_switch->match(obj2));
3519    CHECK_EQ(1, type_switch->match(obj1));
3520    CHECK_EQ(0, type_switch->match(obj0));
3521  }
3522}
3523
3524
3525// For use within the TestSecurityHandler() test.
3526static bool g_security_callback_result = false;
3527static bool NamedSecurityTestCallback(Local<v8::Object> global,
3528                                      Local<Value> name,
3529                                      v8::AccessType type,
3530                                      Local<Value> data) {
3531  // Always allow read access.
3532  if (type == v8::ACCESS_GET)
3533    return true;
3534
3535  // Sometimes allow other access.
3536  return g_security_callback_result;
3537}
3538
3539
3540static bool IndexedSecurityTestCallback(Local<v8::Object> global,
3541                                        uint32_t key,
3542                                        v8::AccessType type,
3543                                        Local<Value> data) {
3544  // Always allow read access.
3545  if (type == v8::ACCESS_GET)
3546    return true;
3547
3548  // Sometimes allow other access.
3549  return g_security_callback_result;
3550}
3551
3552
3553static int trouble_nesting = 0;
3554static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
3555  ApiTestFuzzer::Fuzz();
3556  trouble_nesting++;
3557
3558  // Call a JS function that throws an uncaught exception.
3559  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
3560  Local<Value> trouble_callee = (trouble_nesting == 3) ?
3561    arg_this->Get(v8_str("trouble_callee")) :
3562    arg_this->Get(v8_str("trouble_caller"));
3563  CHECK(trouble_callee->IsFunction());
3564  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
3565}
3566
3567
3568static int report_count = 0;
3569static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
3570                                             v8::Handle<Value>) {
3571  report_count++;
3572}
3573
3574
3575// Counts uncaught exceptions, but other tests running in parallel
3576// also have uncaught exceptions.
3577TEST(ApiUncaughtException) {
3578  report_count = 0;
3579  v8::HandleScope scope;
3580  LocalContext env;
3581  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
3582
3583  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
3584  v8::Local<v8::Object> global = env->Global();
3585  global->Set(v8_str("trouble"), fun->GetFunction());
3586
3587  Script::Compile(v8_str("function trouble_callee() {"
3588                         "  var x = null;"
3589                         "  return x.foo;"
3590                         "};"
3591                         "function trouble_caller() {"
3592                         "  trouble();"
3593                         "};"))->Run();
3594  Local<Value> trouble = global->Get(v8_str("trouble"));
3595  CHECK(trouble->IsFunction());
3596  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
3597  CHECK(trouble_callee->IsFunction());
3598  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
3599  CHECK(trouble_caller->IsFunction());
3600  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
3601  CHECK_EQ(1, report_count);
3602  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
3603}
3604
3605static const char* script_resource_name = "ExceptionInNativeScript.js";
3606static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
3607                                                v8::Handle<Value>) {
3608  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
3609  CHECK(!name_val.IsEmpty() && name_val->IsString());
3610  v8::String::AsciiValue name(message->GetScriptResourceName());
3611  CHECK_EQ(script_resource_name, *name);
3612  CHECK_EQ(3, message->GetLineNumber());
3613  v8::String::AsciiValue source_line(message->GetSourceLine());
3614  CHECK_EQ("  new o.foo();", *source_line);
3615}
3616
3617TEST(ExceptionInNativeScript) {
3618  v8::HandleScope scope;
3619  LocalContext env;
3620  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
3621
3622  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
3623  v8::Local<v8::Object> global = env->Global();
3624  global->Set(v8_str("trouble"), fun->GetFunction());
3625
3626  Script::Compile(v8_str("function trouble() {\n"
3627                         "  var o = {};\n"
3628                         "  new o.foo();\n"
3629                         "};"), v8::String::New(script_resource_name))->Run();
3630  Local<Value> trouble = global->Get(v8_str("trouble"));
3631  CHECK(trouble->IsFunction());
3632  Function::Cast(*trouble)->Call(global, 0, NULL);
3633  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
3634}
3635
3636
3637TEST(CompilationErrorUsingTryCatchHandler) {
3638  v8::HandleScope scope;
3639  LocalContext env;
3640  v8::TryCatch try_catch;
3641  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
3642  CHECK_NE(NULL, *try_catch.Exception());
3643  CHECK(try_catch.HasCaught());
3644}
3645
3646
3647TEST(TryCatchFinallyUsingTryCatchHandler) {
3648  v8::HandleScope scope;
3649  LocalContext env;
3650  v8::TryCatch try_catch;
3651  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
3652  CHECK(!try_catch.HasCaught());
3653  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
3654  CHECK(try_catch.HasCaught());
3655  try_catch.Reset();
3656  Script::Compile(v8_str("(function() {"
3657                         "try { throw ''; } finally { return; }"
3658                         "})()"))->Run();
3659  CHECK(!try_catch.HasCaught());
3660  Script::Compile(v8_str("(function()"
3661                         "  { try { throw ''; } finally { throw 0; }"
3662                         "})()"))->Run();
3663  CHECK(try_catch.HasCaught());
3664}
3665
3666
3667// SecurityHandler can't be run twice
3668TEST(SecurityHandler) {
3669  v8::HandleScope scope0;
3670  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
3671  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
3672                                           IndexedSecurityTestCallback);
3673  // Create an environment
3674  v8::Persistent<Context> context0 =
3675    Context::New(NULL, global_template);
3676  context0->Enter();
3677
3678  v8::Handle<v8::Object> global0 = context0->Global();
3679  v8::Handle<Script> script0 = v8_compile("foo = 111");
3680  script0->Run();
3681  global0->Set(v8_str("0"), v8_num(999));
3682  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
3683  CHECK_EQ(111, foo0->Int32Value());
3684  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
3685  CHECK_EQ(999, z0->Int32Value());
3686
3687  // Create another environment, should fail security checks.
3688  v8::HandleScope scope1;
3689
3690  v8::Persistent<Context> context1 =
3691    Context::New(NULL, global_template);
3692  context1->Enter();
3693
3694  v8::Handle<v8::Object> global1 = context1->Global();
3695  global1->Set(v8_str("othercontext"), global0);
3696  // This set will fail the security check.
3697  v8::Handle<Script> script1 =
3698    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
3699  script1->Run();
3700  // This read will pass the security check.
3701  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
3702  CHECK_EQ(111, foo1->Int32Value());
3703  // This read will pass the security check.
3704  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
3705  CHECK_EQ(999, z1->Int32Value());
3706
3707  // Create another environment, should pass security checks.
3708  { g_security_callback_result = true;  // allow security handler to pass.
3709    v8::HandleScope scope2;
3710    LocalContext context2;
3711    v8::Handle<v8::Object> global2 = context2->Global();
3712    global2->Set(v8_str("othercontext"), global0);
3713    v8::Handle<Script> script2 =
3714        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
3715    script2->Run();
3716    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
3717    CHECK_EQ(333, foo2->Int32Value());
3718    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
3719    CHECK_EQ(888, z2->Int32Value());
3720  }
3721
3722  context1->Exit();
3723  context1.Dispose();
3724
3725  context0->Exit();
3726  context0.Dispose();
3727}
3728
3729
3730THREADED_TEST(SecurityChecks) {
3731  v8::HandleScope handle_scope;
3732  LocalContext env1;
3733  v8::Persistent<Context> env2 = Context::New();
3734
3735  Local<Value> foo = v8_str("foo");
3736  Local<Value> bar = v8_str("bar");
3737
3738  // Set to the same domain.
3739  env1->SetSecurityToken(foo);
3740
3741  // Create a function in env1.
3742  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
3743  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
3744  CHECK(spy->IsFunction());
3745
3746  // Create another function accessing global objects.
3747  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
3748  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
3749  CHECK(spy2->IsFunction());
3750
3751  // Switch to env2 in the same domain and invoke spy on env2.
3752  {
3753    env2->SetSecurityToken(foo);
3754    // Enter env2
3755    Context::Scope scope_env2(env2);
3756    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
3757    CHECK(result->IsFunction());
3758  }
3759
3760  {
3761    env2->SetSecurityToken(bar);
3762    Context::Scope scope_env2(env2);
3763
3764    // Call cross_domain_call, it should throw an exception
3765    v8::TryCatch try_catch;
3766    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
3767    CHECK(try_catch.HasCaught());
3768  }
3769
3770  env2.Dispose();
3771}
3772
3773
3774// Regression test case for issue 1183439.
3775THREADED_TEST(SecurityChecksForPrototypeChain) {
3776  v8::HandleScope scope;
3777  LocalContext current;
3778  v8::Persistent<Context> other = Context::New();
3779
3780  // Change context to be able to get to the Object function in the
3781  // other context without hitting the security checks.
3782  v8::Local<Value> other_object;
3783  { Context::Scope scope(other);
3784    other_object = other->Global()->Get(v8_str("Object"));
3785    other->Global()->Set(v8_num(42), v8_num(87));
3786  }
3787
3788  current->Global()->Set(v8_str("other"), other->Global());
3789  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
3790
3791  // Make sure the security check fails here and we get an undefined
3792  // result instead of getting the Object function. Repeat in a loop
3793  // to make sure to exercise the IC code.
3794  v8::Local<Script> access_other0 = v8_compile("other.Object");
3795  v8::Local<Script> access_other1 = v8_compile("other[42]");
3796  for (int i = 0; i < 5; i++) {
3797    CHECK(!access_other0->Run()->Equals(other_object));
3798    CHECK(access_other0->Run()->IsUndefined());
3799    CHECK(!access_other1->Run()->Equals(v8_num(87)));
3800    CHECK(access_other1->Run()->IsUndefined());
3801  }
3802
3803  // Create an object that has 'other' in its prototype chain and make
3804  // sure we cannot access the Object function indirectly through
3805  // that. Repeat in a loop to make sure to exercise the IC code.
3806  v8_compile("function F() { };"
3807             "F.prototype = other;"
3808             "var f = new F();")->Run();
3809  v8::Local<Script> access_f0 = v8_compile("f.Object");
3810  v8::Local<Script> access_f1 = v8_compile("f[42]");
3811  for (int j = 0; j < 5; j++) {
3812    CHECK(!access_f0->Run()->Equals(other_object));
3813    CHECK(access_f0->Run()->IsUndefined());
3814    CHECK(!access_f1->Run()->Equals(v8_num(87)));
3815    CHECK(access_f1->Run()->IsUndefined());
3816  }
3817
3818  // Now it gets hairy: Set the prototype for the other global object
3819  // to be the current global object. The prototype chain for 'f' now
3820  // goes through 'other' but ends up in the current global object.
3821  { Context::Scope scope(other);
3822    other->Global()->Set(v8_str("__proto__"), current->Global());
3823  }
3824  // Set a named and an index property on the current global
3825  // object. To force the lookup to go through the other global object,
3826  // the properties must not exist in the other global object.
3827  current->Global()->Set(v8_str("foo"), v8_num(100));
3828  current->Global()->Set(v8_num(99), v8_num(101));
3829  // Try to read the properties from f and make sure that the access
3830  // gets stopped by the security checks on the other global object.
3831  Local<Script> access_f2 = v8_compile("f.foo");
3832  Local<Script> access_f3 = v8_compile("f[99]");
3833  for (int k = 0; k < 5; k++) {
3834    CHECK(!access_f2->Run()->Equals(v8_num(100)));
3835    CHECK(access_f2->Run()->IsUndefined());
3836    CHECK(!access_f3->Run()->Equals(v8_num(101)));
3837    CHECK(access_f3->Run()->IsUndefined());
3838  }
3839  other.Dispose();
3840}
3841
3842
3843THREADED_TEST(CrossDomainDelete) {
3844  v8::HandleScope handle_scope;
3845  LocalContext env1;
3846  v8::Persistent<Context> env2 = Context::New();
3847
3848  Local<Value> foo = v8_str("foo");
3849  Local<Value> bar = v8_str("bar");
3850
3851  // Set to the same domain.
3852  env1->SetSecurityToken(foo);
3853  env2->SetSecurityToken(foo);
3854
3855  env1->Global()->Set(v8_str("prop"), v8_num(3));
3856  env2->Global()->Set(v8_str("env1"), env1->Global());
3857
3858  // Change env2 to a different domain and delete env1.prop.
3859  env2->SetSecurityToken(bar);
3860  {
3861    Context::Scope scope_env2(env2);
3862    Local<Value> result =
3863        Script::Compile(v8_str("delete env1.prop"))->Run();
3864    CHECK(result->IsFalse());
3865  }
3866
3867  // Check that env1.prop still exists.
3868  Local<Value> v = env1->Global()->Get(v8_str("prop"));
3869  CHECK(v->IsNumber());
3870  CHECK_EQ(3, v->Int32Value());
3871
3872  env2.Dispose();
3873}
3874
3875
3876THREADED_TEST(CrossDomainIsPropertyEnumerable) {
3877  v8::HandleScope handle_scope;
3878  LocalContext env1;
3879  v8::Persistent<Context> env2 = Context::New();
3880
3881  Local<Value> foo = v8_str("foo");
3882  Local<Value> bar = v8_str("bar");
3883
3884  // Set to the same domain.
3885  env1->SetSecurityToken(foo);
3886  env2->SetSecurityToken(foo);
3887
3888  env1->Global()->Set(v8_str("prop"), v8_num(3));
3889  env2->Global()->Set(v8_str("env1"), env1->Global());
3890
3891  // env1.prop is enumerable in env2.
3892  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
3893  {
3894    Context::Scope scope_env2(env2);
3895    Local<Value> result = Script::Compile(test)->Run();
3896    CHECK(result->IsTrue());
3897  }
3898
3899  // Change env2 to a different domain and test again.
3900  env2->SetSecurityToken(bar);
3901  {
3902    Context::Scope scope_env2(env2);
3903    Local<Value> result = Script::Compile(test)->Run();
3904    CHECK(result->IsFalse());
3905  }
3906
3907  env2.Dispose();
3908}
3909
3910
3911THREADED_TEST(CrossDomainForIn) {
3912  v8::HandleScope handle_scope;
3913  LocalContext env1;
3914  v8::Persistent<Context> env2 = Context::New();
3915
3916  Local<Value> foo = v8_str("foo");
3917  Local<Value> bar = v8_str("bar");
3918
3919  // Set to the same domain.
3920  env1->SetSecurityToken(foo);
3921  env2->SetSecurityToken(foo);
3922
3923  env1->Global()->Set(v8_str("prop"), v8_num(3));
3924  env2->Global()->Set(v8_str("env1"), env1->Global());
3925
3926  // Change env2 to a different domain and set env1's global object
3927  // as the __proto__ of an object in env2 and enumerate properties
3928  // in for-in. It shouldn't enumerate properties on env1's global
3929  // object.
3930  env2->SetSecurityToken(bar);
3931  {
3932    Context::Scope scope_env2(env2);
3933    Local<Value> result =
3934        CompileRun("(function(){var obj = {'__proto__':env1};"
3935                   "for (var p in obj)"
3936                   "   if (p == 'prop') return false;"
3937                   "return true;})()");
3938    CHECK(result->IsTrue());
3939  }
3940  env2.Dispose();
3941}
3942
3943
3944TEST(ContextDetachGlobal) {
3945  v8::HandleScope handle_scope;
3946  LocalContext env1;
3947  v8::Persistent<Context> env2 = Context::New();
3948
3949  Local<v8::Object> global1 = env1->Global();
3950
3951  Local<Value> foo = v8_str("foo");
3952
3953  // Set to the same domain.
3954  env1->SetSecurityToken(foo);
3955  env2->SetSecurityToken(foo);
3956
3957  // Enter env2
3958  env2->Enter();
3959
3960  // Create a function in env1
3961  Local<v8::Object> global2 = env2->Global();
3962  global2->Set(v8_str("prop"), v8::Integer::New(1));
3963  CompileRun("function getProp() {return prop;}");
3964
3965  env1->Global()->Set(v8_str("getProp"),
3966                      global2->Get(v8_str("getProp")));
3967
3968  // Detach env1's global, and reuse the global object of env1
3969  env2->Exit();
3970  env2->DetachGlobal();
3971  // env2 has a new global object.
3972  CHECK(!env2->Global()->Equals(global2));
3973
3974  v8::Persistent<Context> env3 =
3975      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
3976  env3->SetSecurityToken(v8_str("bar"));
3977  env3->Enter();
3978
3979  Local<v8::Object> global3 = env3->Global();
3980  CHECK_EQ(global2, global3);
3981  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
3982  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
3983  global3->Set(v8_str("prop"), v8::Integer::New(-1));
3984  global3->Set(v8_str("prop2"), v8::Integer::New(2));
3985  env3->Exit();
3986
3987  // Call getProp in env1, and it should return the value 1
3988  {
3989    Local<Value> get_prop = global1->Get(v8_str("getProp"));
3990    CHECK(get_prop->IsFunction());
3991    v8::TryCatch try_catch;
3992    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
3993    CHECK(!try_catch.HasCaught());
3994    CHECK_EQ(1, r->Int32Value());
3995  }
3996
3997  // Check that env3 is not accessible from env1
3998  {
3999    Local<Value> r = global3->Get(v8_str("prop2"));
4000    CHECK(r->IsUndefined());
4001  }
4002
4003  env2.Dispose();
4004  env3.Dispose();
4005}
4006
4007
4008static bool NamedAccessBlocker(Local<v8::Object> global,
4009                               Local<Value> name,
4010                               v8::AccessType type,
4011                               Local<Value> data) {
4012  return Context::GetCurrent()->Global()->Equals(global);
4013}
4014
4015
4016static bool IndexedAccessBlocker(Local<v8::Object> global,
4017                                 uint32_t key,
4018                                 v8::AccessType type,
4019                                 Local<Value> data) {
4020  return Context::GetCurrent()->Global()->Equals(global);
4021}
4022
4023
4024static int g_echo_value = -1;
4025static v8::Handle<Value> EchoGetter(Local<String> name,
4026                                    const AccessorInfo& info) {
4027  return v8_num(g_echo_value);
4028}
4029
4030
4031static void EchoSetter(Local<String> name,
4032                       Local<Value> value,
4033                       const AccessorInfo&) {
4034  if (value->IsNumber())
4035    g_echo_value = value->Int32Value();
4036}
4037
4038
4039static v8::Handle<Value> UnreachableGetter(Local<String> name,
4040                                           const AccessorInfo& info) {
4041  CHECK(false);  // This function should not be called..
4042  return v8::Undefined();
4043}
4044
4045
4046static void UnreachableSetter(Local<String>, Local<Value>,
4047                              const AccessorInfo&) {
4048  CHECK(false);  // This function should nto be called.
4049}
4050
4051
4052THREADED_TEST(AccessControl) {
4053  v8::HandleScope handle_scope;
4054  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4055
4056  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
4057                                           IndexedAccessBlocker);
4058
4059  // Add an accessor accessible by cross-domain JS code.
4060  global_template->SetAccessor(
4061      v8_str("accessible_prop"),
4062      EchoGetter, EchoSetter,
4063      v8::Handle<Value>(),
4064      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
4065
4066  // Add an accessor that is not accessible by cross-domain JS code.
4067  global_template->SetAccessor(v8_str("blocked_prop"),
4068                               UnreachableGetter, UnreachableSetter,
4069                               v8::Handle<Value>(),
4070                               v8::DEFAULT);
4071
4072  // Create an environment
4073  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4074  context0->Enter();
4075
4076  v8::Handle<v8::Object> global0 = context0->Global();
4077
4078  v8::HandleScope scope1;
4079
4080  v8::Persistent<Context> context1 = Context::New();
4081  context1->Enter();
4082
4083  v8::Handle<v8::Object> global1 = context1->Global();
4084  global1->Set(v8_str("other"), global0);
4085
4086  v8::Handle<Value> value;
4087
4088  // Access blocked property
4089  value = v8_compile("other.blocked_prop = 1")->Run();
4090  value = v8_compile("other.blocked_prop")->Run();
4091  CHECK(value->IsUndefined());
4092
4093  value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
4094  CHECK(value->IsFalse());
4095
4096  // Access accessible property
4097  value = v8_compile("other.accessible_prop = 3")->Run();
4098  CHECK(value->IsNumber());
4099  CHECK_EQ(3, value->Int32Value());
4100
4101  value = v8_compile("other.accessible_prop")->Run();
4102  CHECK(value->IsNumber());
4103  CHECK_EQ(3, value->Int32Value());
4104
4105  value =
4106    v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
4107  CHECK(value->IsTrue());
4108
4109  // Enumeration doesn't enumerate accessors from inaccessible objects in
4110  // the prototype chain even if the accessors are in themselves accessible.
4111  Local<Value> result =
4112      CompileRun("(function(){var obj = {'__proto__':other};"
4113                 "for (var p in obj)"
4114                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
4115                 "     return false;"
4116                 "   }"
4117                 "return true;})()");
4118  CHECK(result->IsTrue());
4119
4120  context1->Exit();
4121  context0->Exit();
4122  context1.Dispose();
4123  context0.Dispose();
4124}
4125
4126
4127static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
4128                                            Local<Value> name,
4129                                            v8::AccessType type,
4130                                            Local<Value> data) {
4131  return false;
4132}
4133
4134
4135static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
4136                                              uint32_t key,
4137                                              v8::AccessType type,
4138                                              Local<Value> data) {
4139  return false;
4140}
4141
4142
4143THREADED_TEST(AccessControlGetOwnPropertyNames) {
4144  v8::HandleScope handle_scope;
4145  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
4146
4147  obj_template->Set(v8_str("x"), v8::Integer::New(42));
4148  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
4149                                        GetOwnPropertyNamesIndexedBlocker);
4150
4151  // Create an environment
4152  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
4153  context0->Enter();
4154
4155  v8::Handle<v8::Object> global0 = context0->Global();
4156
4157  v8::HandleScope scope1;
4158
4159  v8::Persistent<Context> context1 = Context::New();
4160  context1->Enter();
4161
4162  v8::Handle<v8::Object> global1 = context1->Global();
4163  global1->Set(v8_str("other"), global0);
4164  global1->Set(v8_str("object"), obj_template->NewInstance());
4165
4166  v8::Handle<Value> value;
4167
4168  // Attempt to get the property names of the other global object and
4169  // of an object that requires access checks.  Accessing the other
4170  // global object should be blocked by access checks on the global
4171  // proxy object.  Accessing the object that requires access checks
4172  // is blocked by the access checks on the object itself.
4173  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
4174  CHECK(value->IsTrue());
4175
4176  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
4177  CHECK(value->IsTrue());
4178
4179  context1->Exit();
4180  context0->Exit();
4181  context1.Dispose();
4182  context0.Dispose();
4183}
4184
4185
4186static v8::Handle<Value> ConstTenGetter(Local<String> name,
4187                                        const AccessorInfo& info) {
4188  return v8_num(10);
4189}
4190
4191
4192THREADED_TEST(CrossDomainAccessors) {
4193  v8::HandleScope handle_scope;
4194
4195  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
4196
4197  v8::Handle<v8::ObjectTemplate> global_template =
4198      func_template->InstanceTemplate();
4199
4200  v8::Handle<v8::ObjectTemplate> proto_template =
4201      func_template->PrototypeTemplate();
4202
4203  // Add an accessor to proto that's accessible by cross-domain JS code.
4204  proto_template->SetAccessor(v8_str("accessible"),
4205                              ConstTenGetter, 0,
4206                              v8::Handle<Value>(),
4207                              v8::ALL_CAN_READ);
4208
4209  // Add an accessor that is not accessible by cross-domain JS code.
4210  global_template->SetAccessor(v8_str("unreachable"),
4211                               UnreachableGetter, 0,
4212                               v8::Handle<Value>(),
4213                               v8::DEFAULT);
4214
4215  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4216  context0->Enter();
4217
4218  Local<v8::Object> global = context0->Global();
4219  // Add a normal property that shadows 'accessible'
4220  global->Set(v8_str("accessible"), v8_num(11));
4221
4222  // Enter a new context.
4223  v8::HandleScope scope1;
4224  v8::Persistent<Context> context1 = Context::New();
4225  context1->Enter();
4226
4227  v8::Handle<v8::Object> global1 = context1->Global();
4228  global1->Set(v8_str("other"), global);
4229
4230  // Should return 10, instead of 11
4231  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
4232  CHECK(value->IsNumber());
4233  CHECK_EQ(10, value->Int32Value());
4234
4235  value = v8_compile("other.unreachable")->Run();
4236  CHECK(value->IsUndefined());
4237
4238  context1->Exit();
4239  context0->Exit();
4240  context1.Dispose();
4241  context0.Dispose();
4242}
4243
4244
4245static int named_access_count = 0;
4246static int indexed_access_count = 0;
4247
4248static bool NamedAccessCounter(Local<v8::Object> global,
4249                               Local<Value> name,
4250                               v8::AccessType type,
4251                               Local<Value> data) {
4252  named_access_count++;
4253  return true;
4254}
4255
4256
4257static bool IndexedAccessCounter(Local<v8::Object> global,
4258                                 uint32_t key,
4259                                 v8::AccessType type,
4260                                 Local<Value> data) {
4261  indexed_access_count++;
4262  return true;
4263}
4264
4265
4266// This one is too easily disturbed by other tests.
4267TEST(AccessControlIC) {
4268  named_access_count = 0;
4269  indexed_access_count = 0;
4270
4271  v8::HandleScope handle_scope;
4272
4273  // Create an environment.
4274  v8::Persistent<Context> context0 = Context::New();
4275  context0->Enter();
4276
4277  // Create an object that requires access-check functions to be
4278  // called for cross-domain access.
4279  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4280  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4281                                           IndexedAccessCounter);
4282  Local<v8::Object> object = object_template->NewInstance();
4283
4284  v8::HandleScope scope1;
4285
4286  // Create another environment.
4287  v8::Persistent<Context> context1 = Context::New();
4288  context1->Enter();
4289
4290  // Make easy access to the object from the other environment.
4291  v8::Handle<v8::Object> global1 = context1->Global();
4292  global1->Set(v8_str("obj"), object);
4293
4294  v8::Handle<Value> value;
4295
4296  // Check that the named access-control function is called every time.
4297  CompileRun("function testProp(obj) {"
4298             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
4299             "  for (var j = 0; j < 10; j++) obj.prop;"
4300             "  return obj.prop"
4301             "}");
4302  value = CompileRun("testProp(obj)");
4303  CHECK(value->IsNumber());
4304  CHECK_EQ(1, value->Int32Value());
4305  CHECK_EQ(21, named_access_count);
4306
4307  // Check that the named access-control function is called every time.
4308  CompileRun("var p = 'prop';"
4309             "function testKeyed(obj) {"
4310             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
4311             "  for (var j = 0; j < 10; j++) obj[p];"
4312             "  return obj[p];"
4313             "}");
4314  // Use obj which requires access checks.  No inline caching is used
4315  // in that case.
4316  value = CompileRun("testKeyed(obj)");
4317  CHECK(value->IsNumber());
4318  CHECK_EQ(1, value->Int32Value());
4319  CHECK_EQ(42, named_access_count);
4320  // Force the inline caches into generic state and try again.
4321  CompileRun("testKeyed({ a: 0 })");
4322  CompileRun("testKeyed({ b: 0 })");
4323  value = CompileRun("testKeyed(obj)");
4324  CHECK(value->IsNumber());
4325  CHECK_EQ(1, value->Int32Value());
4326  CHECK_EQ(63, named_access_count);
4327
4328  // Check that the indexed access-control function is called every time.
4329  CompileRun("function testIndexed(obj) {"
4330             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
4331             "  for (var j = 0; j < 10; j++) obj[0];"
4332             "  return obj[0]"
4333             "}");
4334  value = CompileRun("testIndexed(obj)");
4335  CHECK(value->IsNumber());
4336  CHECK_EQ(1, value->Int32Value());
4337  CHECK_EQ(21, indexed_access_count);
4338  // Force the inline caches into generic state.
4339  CompileRun("testIndexed(new Array(1))");
4340  // Test that the indexed access check is called.
4341  value = CompileRun("testIndexed(obj)");
4342  CHECK(value->IsNumber());
4343  CHECK_EQ(1, value->Int32Value());
4344  CHECK_EQ(42, indexed_access_count);
4345
4346  // Check that the named access check is called when invoking
4347  // functions on an object that requires access checks.
4348  CompileRun("obj.f = function() {}");
4349  CompileRun("function testCallNormal(obj) {"
4350             "  for (var i = 0; i < 10; i++) obj.f();"
4351             "}");
4352  CompileRun("testCallNormal(obj)");
4353  CHECK_EQ(74, named_access_count);
4354
4355  // Force obj into slow case.
4356  value = CompileRun("delete obj.prop");
4357  CHECK(value->BooleanValue());
4358  // Force inline caches into dictionary probing mode.
4359  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
4360  // Test that the named access check is called.
4361  value = CompileRun("testProp(obj);");
4362  CHECK(value->IsNumber());
4363  CHECK_EQ(1, value->Int32Value());
4364  CHECK_EQ(96, named_access_count);
4365
4366  // Force the call inline cache into dictionary probing mode.
4367  CompileRun("o.f = function() {}; testCallNormal(o)");
4368  // Test that the named access check is still called for each
4369  // invocation of the function.
4370  value = CompileRun("testCallNormal(obj)");
4371  CHECK_EQ(106, named_access_count);
4372
4373  context1->Exit();
4374  context0->Exit();
4375  context1.Dispose();
4376  context0.Dispose();
4377}
4378
4379
4380static bool NamedAccessFlatten(Local<v8::Object> global,
4381                               Local<Value> name,
4382                               v8::AccessType type,
4383                               Local<Value> data) {
4384  char buf[100];
4385  int len;
4386
4387  CHECK(name->IsString());
4388
4389  memset(buf, 0x1, sizeof(buf));
4390  len = Local<String>::Cast(name)->WriteAscii(buf);
4391  CHECK_EQ(4, len);
4392
4393  uint16_t buf2[100];
4394
4395  memset(buf, 0x1, sizeof(buf));
4396  len = Local<String>::Cast(name)->Write(buf2);
4397  CHECK_EQ(4, len);
4398
4399  return true;
4400}
4401
4402
4403static bool IndexedAccessFlatten(Local<v8::Object> global,
4404                                 uint32_t key,
4405                                 v8::AccessType type,
4406                                 Local<Value> data) {
4407  return true;
4408}
4409
4410
4411// Regression test.  In access checks, operations that may cause
4412// garbage collection are not allowed.  It used to be the case that
4413// using the Write operation on a string could cause a garbage
4414// collection due to flattening of the string.  This is no longer the
4415// case.
4416THREADED_TEST(AccessControlFlatten) {
4417  named_access_count = 0;
4418  indexed_access_count = 0;
4419
4420  v8::HandleScope handle_scope;
4421
4422  // Create an environment.
4423  v8::Persistent<Context> context0 = Context::New();
4424  context0->Enter();
4425
4426  // Create an object that requires access-check functions to be
4427  // called for cross-domain access.
4428  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4429  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
4430                                           IndexedAccessFlatten);
4431  Local<v8::Object> object = object_template->NewInstance();
4432
4433  v8::HandleScope scope1;
4434
4435  // Create another environment.
4436  v8::Persistent<Context> context1 = Context::New();
4437  context1->Enter();
4438
4439  // Make easy access to the object from the other environment.
4440  v8::Handle<v8::Object> global1 = context1->Global();
4441  global1->Set(v8_str("obj"), object);
4442
4443  v8::Handle<Value> value;
4444
4445  value = v8_compile("var p = 'as' + 'df';")->Run();
4446  value = v8_compile("obj[p];")->Run();
4447
4448  context1->Exit();
4449  context0->Exit();
4450  context1.Dispose();
4451  context0.Dispose();
4452}
4453
4454
4455static v8::Handle<Value> AccessControlNamedGetter(
4456    Local<String>, const AccessorInfo&) {
4457  return v8::Integer::New(42);
4458}
4459
4460
4461static v8::Handle<Value> AccessControlNamedSetter(
4462    Local<String>, Local<Value> value, const AccessorInfo&) {
4463  return value;
4464}
4465
4466
4467static v8::Handle<Value> AccessControlIndexedGetter(
4468      uint32_t index,
4469      const AccessorInfo& info) {
4470  return v8_num(42);
4471}
4472
4473
4474static v8::Handle<Value> AccessControlIndexedSetter(
4475    uint32_t, Local<Value> value, const AccessorInfo&) {
4476  return value;
4477}
4478
4479
4480THREADED_TEST(AccessControlInterceptorIC) {
4481  named_access_count = 0;
4482  indexed_access_count = 0;
4483
4484  v8::HandleScope handle_scope;
4485
4486  // Create an environment.
4487  v8::Persistent<Context> context0 = Context::New();
4488  context0->Enter();
4489
4490  // Create an object that requires access-check functions to be
4491  // called for cross-domain access.  The object also has interceptors
4492  // interceptor.
4493  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4494  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4495                                           IndexedAccessCounter);
4496  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
4497                                           AccessControlNamedSetter);
4498  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
4499                                             AccessControlIndexedSetter);
4500  Local<v8::Object> object = object_template->NewInstance();
4501
4502  v8::HandleScope scope1;
4503
4504  // Create another environment.
4505  v8::Persistent<Context> context1 = Context::New();
4506  context1->Enter();
4507
4508  // Make easy access to the object from the other environment.
4509  v8::Handle<v8::Object> global1 = context1->Global();
4510  global1->Set(v8_str("obj"), object);
4511
4512  v8::Handle<Value> value;
4513
4514  // Check that the named access-control function is called every time
4515  // eventhough there is an interceptor on the object.
4516  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
4517  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
4518                     "obj.x")->Run();
4519  CHECK(value->IsNumber());
4520  CHECK_EQ(42, value->Int32Value());
4521  CHECK_EQ(21, named_access_count);
4522
4523  value = v8_compile("var p = 'x';")->Run();
4524  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
4525  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
4526                     "obj[p]")->Run();
4527  CHECK(value->IsNumber());
4528  CHECK_EQ(42, value->Int32Value());
4529  CHECK_EQ(42, named_access_count);
4530
4531  // Check that the indexed access-control function is called every
4532  // time eventhough there is an interceptor on the object.
4533  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
4534  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
4535                     "obj[0]")->Run();
4536  CHECK(value->IsNumber());
4537  CHECK_EQ(42, value->Int32Value());
4538  CHECK_EQ(21, indexed_access_count);
4539
4540  context1->Exit();
4541  context0->Exit();
4542  context1.Dispose();
4543  context0.Dispose();
4544}
4545
4546
4547THREADED_TEST(Version) {
4548  v8::V8::GetVersion();
4549}
4550
4551
4552static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
4553  ApiTestFuzzer::Fuzz();
4554  return v8_num(12);
4555}
4556
4557
4558THREADED_TEST(InstanceProperties) {
4559  v8::HandleScope handle_scope;
4560  LocalContext context;
4561
4562  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4563  Local<ObjectTemplate> instance = t->InstanceTemplate();
4564
4565  instance->Set(v8_str("x"), v8_num(42));
4566  instance->Set(v8_str("f"),
4567                v8::FunctionTemplate::New(InstanceFunctionCallback));
4568
4569  Local<Value> o = t->GetFunction()->NewInstance();
4570
4571  context->Global()->Set(v8_str("i"), o);
4572  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
4573  CHECK_EQ(42, value->Int32Value());
4574
4575  value = Script::Compile(v8_str("i.f()"))->Run();
4576  CHECK_EQ(12, value->Int32Value());
4577}
4578
4579
4580static v8::Handle<Value>
4581GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
4582  ApiTestFuzzer::Fuzz();
4583  return v8::Handle<Value>();
4584}
4585
4586
4587THREADED_TEST(GlobalObjectInstanceProperties) {
4588  v8::HandleScope handle_scope;
4589
4590  Local<Value> global_object;
4591
4592  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4593  t->InstanceTemplate()->SetNamedPropertyHandler(
4594      GlobalObjectInstancePropertiesGet);
4595  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
4596  instance_template->Set(v8_str("x"), v8_num(42));
4597  instance_template->Set(v8_str("f"),
4598                         v8::FunctionTemplate::New(InstanceFunctionCallback));
4599
4600  {
4601    LocalContext env(NULL, instance_template);
4602    // Hold on to the global object so it can be used again in another
4603    // environment initialization.
4604    global_object = env->Global();
4605
4606    Local<Value> value = Script::Compile(v8_str("x"))->Run();
4607    CHECK_EQ(42, value->Int32Value());
4608    value = Script::Compile(v8_str("f()"))->Run();
4609    CHECK_EQ(12, value->Int32Value());
4610  }
4611
4612  {
4613    // Create new environment reusing the global object.
4614    LocalContext env(NULL, instance_template, global_object);
4615    Local<Value> value = Script::Compile(v8_str("x"))->Run();
4616    CHECK_EQ(42, value->Int32Value());
4617    value = Script::Compile(v8_str("f()"))->Run();
4618    CHECK_EQ(12, value->Int32Value());
4619  }
4620}
4621
4622
4623static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
4624  ApiTestFuzzer::Fuzz();
4625  return v8_num(42);
4626}
4627
4628
4629static int shadow_y;
4630static int shadow_y_setter_call_count;
4631static int shadow_y_getter_call_count;
4632
4633
4634static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
4635  shadow_y_setter_call_count++;
4636  shadow_y = 42;
4637}
4638
4639
4640static v8::Handle<Value> ShadowYGetter(Local<String> name,
4641                                       const AccessorInfo& info) {
4642  ApiTestFuzzer::Fuzz();
4643  shadow_y_getter_call_count++;
4644  return v8_num(shadow_y);
4645}
4646
4647
4648static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
4649                                          const AccessorInfo& info) {
4650  return v8::Handle<Value>();
4651}
4652
4653
4654static v8::Handle<Value> ShadowNamedGet(Local<String> key,
4655                                        const AccessorInfo&) {
4656  return v8::Handle<Value>();
4657}
4658
4659
4660THREADED_TEST(ShadowObject) {
4661  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
4662  v8::HandleScope handle_scope;
4663
4664  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
4665  LocalContext context(NULL, global_template);
4666
4667  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4668  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
4669  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
4670  Local<ObjectTemplate> proto = t->PrototypeTemplate();
4671  Local<ObjectTemplate> instance = t->InstanceTemplate();
4672
4673  // Only allow calls of f on instances of t.
4674  Local<v8::Signature> signature = v8::Signature::New(t);
4675  proto->Set(v8_str("f"),
4676             v8::FunctionTemplate::New(ShadowFunctionCallback,
4677                                       Local<Value>(),
4678                                       signature));
4679  proto->Set(v8_str("x"), v8_num(12));
4680
4681  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
4682
4683  Local<Value> o = t->GetFunction()->NewInstance();
4684  context->Global()->Set(v8_str("__proto__"), o);
4685
4686  Local<Value> value =
4687      Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
4688  CHECK(value->IsBoolean());
4689  CHECK(!value->BooleanValue());
4690
4691  value = Script::Compile(v8_str("x"))->Run();
4692  CHECK_EQ(12, value->Int32Value());
4693
4694  value = Script::Compile(v8_str("f()"))->Run();
4695  CHECK_EQ(42, value->Int32Value());
4696
4697  Script::Compile(v8_str("y = 42"))->Run();
4698  CHECK_EQ(1, shadow_y_setter_call_count);
4699  value = Script::Compile(v8_str("y"))->Run();
4700  CHECK_EQ(1, shadow_y_getter_call_count);
4701  CHECK_EQ(42, value->Int32Value());
4702}
4703
4704
4705THREADED_TEST(HiddenPrototype) {
4706  v8::HandleScope handle_scope;
4707  LocalContext context;
4708
4709  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4710  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
4711  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4712  t1->SetHiddenPrototype(true);
4713  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
4714  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
4715  t2->SetHiddenPrototype(true);
4716  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
4717  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
4718  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
4719
4720  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
4721  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
4722  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
4723  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
4724
4725  // Setting the prototype on an object skips hidden prototypes.
4726  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4727  o0->Set(v8_str("__proto__"), o1);
4728  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4729  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4730  o0->Set(v8_str("__proto__"), o2);
4731  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4732  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4733  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
4734  o0->Set(v8_str("__proto__"), o3);
4735  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4736  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4737  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
4738  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
4739
4740  // Getting the prototype of o0 should get the first visible one
4741  // which is o3.  Therefore, z should not be defined on the prototype
4742  // object.
4743  Local<Value> proto = o0->Get(v8_str("__proto__"));
4744  CHECK(proto->IsObject());
4745  CHECK(Local<v8::Object>::Cast(proto)->Get(v8_str("z"))->IsUndefined());
4746}
4747
4748
4749THREADED_TEST(GetterSetterExceptions) {
4750  v8::HandleScope handle_scope;
4751  LocalContext context;
4752  CompileRun(
4753    "function Foo() { };"
4754    "function Throw() { throw 5; };"
4755    "var x = { };"
4756    "x.__defineSetter__('set', Throw);"
4757    "x.__defineGetter__('get', Throw);");
4758  Local<v8::Object> x =
4759      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
4760  v8::TryCatch try_catch;
4761  x->Set(v8_str("set"), v8::Integer::New(8));
4762  x->Get(v8_str("get"));
4763  x->Set(v8_str("set"), v8::Integer::New(8));
4764  x->Get(v8_str("get"));
4765  x->Set(v8_str("set"), v8::Integer::New(8));
4766  x->Get(v8_str("get"));
4767  x->Set(v8_str("set"), v8::Integer::New(8));
4768  x->Get(v8_str("get"));
4769}
4770
4771
4772THREADED_TEST(Constructor) {
4773  v8::HandleScope handle_scope;
4774  LocalContext context;
4775  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4776  templ->SetClassName(v8_str("Fun"));
4777  Local<Function> cons = templ->GetFunction();
4778  context->Global()->Set(v8_str("Fun"), cons);
4779  Local<v8::Object> inst = cons->NewInstance();
4780  i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
4781  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
4782  CHECK(value->BooleanValue());
4783}
4784
4785THREADED_TEST(FunctionDescriptorException) {
4786  v8::HandleScope handle_scope;
4787  LocalContext context;
4788  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4789  templ->SetClassName(v8_str("Fun"));
4790  Local<Function> cons = templ->GetFunction();
4791  context->Global()->Set(v8_str("Fun"), cons);
4792  Local<Value> value = CompileRun(
4793    "function test() {"
4794    "  try {"
4795    "    (new Fun()).blah()"
4796    "  } catch (e) {"
4797    "    var str = String(e);"
4798    "    if (str.indexOf('TypeError') == -1) return 1;"
4799    "    if (str.indexOf('[object Fun]') != -1) return 2;"
4800    "    if (str.indexOf('#<a Fun>') == -1) return 3;"
4801    "    return 0;"
4802    "  }"
4803    "  return 4;"
4804    "}"
4805    "test();");
4806  CHECK_EQ(0, value->Int32Value());
4807}
4808
4809
4810THREADED_TEST(EvalAliasedDynamic) {
4811  v8::HandleScope scope;
4812  LocalContext current;
4813
4814  // Tests where aliased eval can only be resolved dynamically.
4815  Local<Script> script =
4816      Script::Compile(v8_str("function f(x) { "
4817                             "  var foo = 2;"
4818                             "  with (x) { return eval('foo'); }"
4819                             "}"
4820                             "foo = 0;"
4821                             "result1 = f(new Object());"
4822                             "result2 = f(this);"
4823                             "var x = new Object();"
4824                             "x.eval = function(x) { return 1; };"
4825                             "result3 = f(x);"));
4826  script->Run();
4827  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
4828  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
4829  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
4830
4831  v8::TryCatch try_catch;
4832  script =
4833    Script::Compile(v8_str("function f(x) { "
4834                           "  var bar = 2;"
4835                           "  with (x) { return eval('bar'); }"
4836                           "}"
4837                           "f(this)"));
4838  script->Run();
4839  CHECK(try_catch.HasCaught());
4840  try_catch.Reset();
4841}
4842
4843
4844THREADED_TEST(CrossEval) {
4845  v8::HandleScope scope;
4846  LocalContext other;
4847  LocalContext current;
4848
4849  Local<String> token = v8_str("<security token>");
4850  other->SetSecurityToken(token);
4851  current->SetSecurityToken(token);
4852
4853  // Setup reference from current to other.
4854  current->Global()->Set(v8_str("other"), other->Global());
4855
4856  // Check that new variables are introduced in other context.
4857  Local<Script> script =
4858      Script::Compile(v8_str("other.eval('var foo = 1234')"));
4859  script->Run();
4860  Local<Value> foo = other->Global()->Get(v8_str("foo"));
4861  CHECK_EQ(1234, foo->Int32Value());
4862  CHECK(!current->Global()->Has(v8_str("foo")));
4863
4864  // Check that writing to non-existing properties introduces them in
4865  // the other context.
4866  script =
4867      Script::Compile(v8_str("other.eval('na = 1234')"));
4868  script->Run();
4869  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
4870  CHECK(!current->Global()->Has(v8_str("na")));
4871
4872  // Check that global variables in current context are not visible in other
4873  // context.
4874  v8::TryCatch try_catch;
4875  script =
4876      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
4877  Local<Value> result = script->Run();
4878  CHECK(try_catch.HasCaught());
4879  try_catch.Reset();
4880
4881  // Check that local variables in current context are not visible in other
4882  // context.
4883  script =
4884      Script::Compile(v8_str("(function() { "
4885                             "  var baz = 87;"
4886                             "  return other.eval('baz');"
4887                             "})();"));
4888  result = script->Run();
4889  CHECK(try_catch.HasCaught());
4890  try_catch.Reset();
4891
4892  // Check that global variables in the other environment are visible
4893  // when evaluting code.
4894  other->Global()->Set(v8_str("bis"), v8_num(1234));
4895  script = Script::Compile(v8_str("other.eval('bis')"));
4896  CHECK_EQ(1234, script->Run()->Int32Value());
4897  CHECK(!try_catch.HasCaught());
4898
4899  // Check that the 'this' pointer points to the global object evaluating
4900  // code.
4901  other->Global()->Set(v8_str("t"), other->Global());
4902  script = Script::Compile(v8_str("other.eval('this == t')"));
4903  result = script->Run();
4904  CHECK(result->IsTrue());
4905  CHECK(!try_catch.HasCaught());
4906
4907  // Check that variables introduced in with-statement are not visible in
4908  // other context.
4909  script =
4910      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
4911  result = script->Run();
4912  CHECK(try_catch.HasCaught());
4913  try_catch.Reset();
4914
4915  // Check that you cannot use 'eval.call' with another object than the
4916  // current global object.
4917  script =
4918      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
4919  result = script->Run();
4920  CHECK(try_catch.HasCaught());
4921}
4922
4923
4924// Test that calling eval in a context which has been detached from
4925// its global throws an exception.  This behavior is consistent with
4926// other JavaScript implementations.
4927THREADED_TEST(EvalInDetachedGlobal) {
4928  v8::HandleScope scope;
4929
4930  v8::Persistent<Context> context0 = Context::New();
4931  v8::Persistent<Context> context1 = Context::New();
4932
4933  // Setup function in context0 that uses eval from context0.
4934  context0->Enter();
4935  v8::Handle<v8::Value> fun =
4936      CompileRun("var x = 42;"
4937                 "(function() {"
4938                 "  var e = eval;"
4939                 "  return function(s) { return e(s); }"
4940                 "})()");
4941  context0->Exit();
4942
4943  // Put the function into context1 and call it before and after
4944  // detaching the global.  Before detaching, the call succeeds and
4945  // after detaching and exception is thrown.
4946  context1->Enter();
4947  context1->Global()->Set(v8_str("fun"), fun);
4948  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
4949  CHECK_EQ(42, x_value->Int32Value());
4950  context0->DetachGlobal();
4951  v8::TryCatch catcher;
4952  x_value = CompileRun("fun('x')");
4953  CHECK(x_value.IsEmpty());
4954  CHECK(catcher.HasCaught());
4955  context1->Exit();
4956
4957  context1.Dispose();
4958  context0.Dispose();
4959}
4960
4961
4962THREADED_TEST(CrossLazyLoad) {
4963  v8::HandleScope scope;
4964  LocalContext other;
4965  LocalContext current;
4966
4967  Local<String> token = v8_str("<security token>");
4968  other->SetSecurityToken(token);
4969  current->SetSecurityToken(token);
4970
4971  // Setup reference from current to other.
4972  current->Global()->Set(v8_str("other"), other->Global());
4973
4974  // Trigger lazy loading in other context.
4975  Local<Script> script =
4976      Script::Compile(v8_str("other.eval('new Date(42)')"));
4977  Local<Value> value = script->Run();
4978  CHECK_EQ(42.0, value->NumberValue());
4979}
4980
4981
4982static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
4983  ApiTestFuzzer::Fuzz();
4984  if (args.IsConstructCall()) {
4985    if (args[0]->IsInt32()) {
4986       return v8_num(-args[0]->Int32Value());
4987    }
4988  }
4989
4990  return args[0];
4991}
4992
4993
4994// Test that a call handler can be set for objects which will allow
4995// non-function objects created through the API to be called as
4996// functions.
4997THREADED_TEST(CallAsFunction) {
4998  v8::HandleScope scope;
4999  LocalContext context;
5000
5001  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5002  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5003  instance_template->SetCallAsFunctionHandler(call_as_function);
5004  Local<v8::Object> instance = t->GetFunction()->NewInstance();
5005  context->Global()->Set(v8_str("obj"), instance);
5006  v8::TryCatch try_catch;
5007  Local<Value> value;
5008  CHECK(!try_catch.HasCaught());
5009
5010  value = CompileRun("obj(42)");
5011  CHECK(!try_catch.HasCaught());
5012  CHECK_EQ(42, value->Int32Value());
5013
5014  value = CompileRun("(function(o){return o(49)})(obj)");
5015  CHECK(!try_catch.HasCaught());
5016  CHECK_EQ(49, value->Int32Value());
5017
5018  // test special case of call as function
5019  value = CompileRun("[obj]['0'](45)");
5020  CHECK(!try_catch.HasCaught());
5021  CHECK_EQ(45, value->Int32Value());
5022
5023  value = CompileRun("obj.call = Function.prototype.call;"
5024                     "obj.call(null, 87)");
5025  CHECK(!try_catch.HasCaught());
5026  CHECK_EQ(87, value->Int32Value());
5027
5028  // Regression tests for bug #1116356: Calling call through call/apply
5029  // must work for non-function receivers.
5030  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
5031  value = CompileRun(apply_99);
5032  CHECK(!try_catch.HasCaught());
5033  CHECK_EQ(99, value->Int32Value());
5034
5035  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
5036  value = CompileRun(call_17);
5037  CHECK(!try_catch.HasCaught());
5038  CHECK_EQ(17, value->Int32Value());
5039
5040  // Check that the call-as-function handler can be called through
5041  // new.
5042  value = CompileRun("new obj(43)");
5043  CHECK(!try_catch.HasCaught());
5044  CHECK_EQ(-43, value->Int32Value());
5045}
5046
5047
5048static int CountHandles() {
5049  return v8::HandleScope::NumberOfHandles();
5050}
5051
5052
5053static int Recurse(int depth, int iterations) {
5054  v8::HandleScope scope;
5055  if (depth == 0) return CountHandles();
5056  for (int i = 0; i < iterations; i++) {
5057    Local<v8::Number> n = v8::Integer::New(42);
5058  }
5059  return Recurse(depth - 1, iterations);
5060}
5061
5062
5063THREADED_TEST(HandleIteration) {
5064  static const int kIterations = 500;
5065  static const int kNesting = 200;
5066  CHECK_EQ(0, CountHandles());
5067  {
5068    v8::HandleScope scope1;
5069    CHECK_EQ(0, CountHandles());
5070    for (int i = 0; i < kIterations; i++) {
5071      Local<v8::Number> n = v8::Integer::New(42);
5072      CHECK_EQ(i + 1, CountHandles());
5073    }
5074
5075    CHECK_EQ(kIterations, CountHandles());
5076    {
5077      v8::HandleScope scope2;
5078      for (int j = 0; j < kIterations; j++) {
5079        Local<v8::Number> n = v8::Integer::New(42);
5080        CHECK_EQ(j + 1 + kIterations, CountHandles());
5081      }
5082    }
5083    CHECK_EQ(kIterations, CountHandles());
5084  }
5085  CHECK_EQ(0, CountHandles());
5086  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
5087}
5088
5089
5090static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
5091    Local<String> name,
5092    const AccessorInfo& info) {
5093  ApiTestFuzzer::Fuzz();
5094  return v8::Handle<Value>();
5095}
5096
5097
5098THREADED_TEST(InterceptorHasOwnProperty) {
5099  v8::HandleScope scope;
5100  LocalContext context;
5101  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5102  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5103  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
5104  Local<Function> function = fun_templ->GetFunction();
5105  context->Global()->Set(v8_str("constructor"), function);
5106  v8::Handle<Value> value = CompileRun(
5107      "var o = new constructor();"
5108      "o.hasOwnProperty('ostehaps');");
5109  CHECK_EQ(false, value->BooleanValue());
5110  value = CompileRun(
5111      "o.ostehaps = 42;"
5112      "o.hasOwnProperty('ostehaps');");
5113  CHECK_EQ(true, value->BooleanValue());
5114  value = CompileRun(
5115      "var p = new constructor();"
5116      "p.hasOwnProperty('ostehaps');");
5117  CHECK_EQ(false, value->BooleanValue());
5118}
5119
5120
5121static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
5122    Local<String> name,
5123    const AccessorInfo& info) {
5124  ApiTestFuzzer::Fuzz();
5125  i::Heap::CollectAllGarbage(false);
5126  return v8::Handle<Value>();
5127}
5128
5129
5130THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
5131  v8::HandleScope scope;
5132  LocalContext context;
5133  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5134  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5135  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
5136  Local<Function> function = fun_templ->GetFunction();
5137  context->Global()->Set(v8_str("constructor"), function);
5138  // Let's first make some stuff so we can be sure to get a good GC.
5139  CompileRun(
5140      "function makestr(size) {"
5141      "  switch (size) {"
5142      "    case 1: return 'f';"
5143      "    case 2: return 'fo';"
5144      "    case 3: return 'foo';"
5145      "  }"
5146      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
5147      "}"
5148      "var x = makestr(12345);"
5149      "x = makestr(31415);"
5150      "x = makestr(23456);");
5151  v8::Handle<Value> value = CompileRun(
5152      "var o = new constructor();"
5153      "o.__proto__ = new String(x);"
5154      "o.hasOwnProperty('ostehaps');");
5155  CHECK_EQ(false, value->BooleanValue());
5156}
5157
5158
5159typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
5160                                                 const AccessorInfo& info);
5161
5162
5163static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
5164                                   const char* source,
5165                                   int expected) {
5166  v8::HandleScope scope;
5167  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5168  templ->SetNamedPropertyHandler(getter);
5169  LocalContext context;
5170  context->Global()->Set(v8_str("o"), templ->NewInstance());
5171  v8::Handle<Value> value = CompileRun(source);
5172  CHECK_EQ(expected, value->Int32Value());
5173}
5174
5175
5176static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
5177                                                 const AccessorInfo& info) {
5178  ApiTestFuzzer::Fuzz();
5179  CHECK(v8_str("x")->Equals(name));
5180  return v8::Integer::New(42);
5181}
5182
5183
5184// This test should hit the load IC for the interceptor case.
5185THREADED_TEST(InterceptorLoadIC) {
5186  CheckInterceptorLoadIC(InterceptorLoadICGetter,
5187    "var result = 0;"
5188    "for (var i = 0; i < 1000; i++) {"
5189    "  result = o.x;"
5190    "}",
5191    42);
5192}
5193
5194
5195// Below go several tests which verify that JITing for various
5196// configurations of interceptor and explicit fields works fine
5197// (those cases are special cased to get better performance).
5198
5199static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
5200                                                 const AccessorInfo& info) {
5201  ApiTestFuzzer::Fuzz();
5202  return v8_str("x")->Equals(name)
5203      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
5204}
5205
5206
5207THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
5208  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5209    "var result = 0;"
5210    "o.y = 239;"
5211    "for (var i = 0; i < 1000; i++) {"
5212    "  result = o.y;"
5213    "}",
5214    239);
5215}
5216
5217
5218THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
5219  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5220    "var result = 0;"
5221    "o.__proto__ = { 'y': 239 };"
5222    "for (var i = 0; i < 1000; i++) {"
5223    "  result = o.y + o.x;"
5224    "}",
5225    239 + 42);
5226}
5227
5228
5229THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
5230  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5231    "var result = 0;"
5232    "o.__proto__.y = 239;"
5233    "for (var i = 0; i < 1000; i++) {"
5234    "  result = o.y + o.x;"
5235    "}",
5236    239 + 42);
5237}
5238
5239
5240THREADED_TEST(InterceptorLoadICUndefined) {
5241  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5242    "var result = 0;"
5243    "for (var i = 0; i < 1000; i++) {"
5244    "  result = (o.y == undefined) ? 239 : 42;"
5245    "}",
5246    239);
5247}
5248
5249
5250THREADED_TEST(InterceptorLoadICWithOverride) {
5251  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5252    "fst = new Object();  fst.__proto__ = o;"
5253    "snd = new Object();  snd.__proto__ = fst;"
5254    "var result1 = 0;"
5255    "for (var i = 0; i < 1000;  i++) {"
5256    "  result1 = snd.x;"
5257    "}"
5258    "fst.x = 239;"
5259    "var result = 0;"
5260    "for (var i = 0; i < 1000; i++) {"
5261    "  result = snd.x;"
5262    "}"
5263    "result + result1",
5264    239 + 42);
5265}
5266
5267
5268// Test the case when we stored field into
5269// a stub, but interceptor produced value on its own.
5270THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
5271  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5272    "proto = new Object();"
5273    "o.__proto__ = proto;"
5274    "proto.x = 239;"
5275    "for (var i = 0; i < 1000; i++) {"
5276    "  o.x;"
5277    // Now it should be ICed and keep a reference to x defined on proto
5278    "}"
5279    "var result = 0;"
5280    "for (var i = 0; i < 1000; i++) {"
5281    "  result += o.x;"
5282    "}"
5283    "result;",
5284    42 * 1000);
5285}
5286
5287
5288// Test the case when we stored field into
5289// a stub, but it got invalidated later on.
5290THREADED_TEST(InterceptorLoadICInvalidatedField) {
5291  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5292    "proto1 = new Object();"
5293    "proto2 = new Object();"
5294    "o.__proto__ = proto1;"
5295    "proto1.__proto__ = proto2;"
5296    "proto2.y = 239;"
5297    "for (var i = 0; i < 1000; i++) {"
5298    "  o.y;"
5299    // Now it should be ICed and keep a reference to y defined on proto2
5300    "}"
5301    "proto1.y = 42;"
5302    "var result = 0;"
5303    "for (var i = 0; i < 1000; i++) {"
5304    "  result += o.y;"
5305    "}"
5306    "result;",
5307    42 * 1000);
5308}
5309
5310
5311// Test the case when we stored field into
5312// a stub, but it got invalidated later on due to override on
5313// global object which is between interceptor and fields' holders.
5314THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
5315  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5316    "o.__proto__ = this;"  // set a global to be a proto of o.
5317    "this.__proto__.y = 239;"
5318    "for (var i = 0; i < 10; i++) {"
5319    "  if (o.y != 239) throw 'oops: ' + o.y;"
5320    // Now it should be ICed and keep a reference to y defined on field_holder.
5321    "}"
5322    "this.y = 42;"  // Assign on a global.
5323    "var result = 0;"
5324    "for (var i = 0; i < 10; i++) {"
5325    "  result += o.y;"
5326    "}"
5327    "result;",
5328    42 * 10);
5329}
5330
5331
5332static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
5333  ApiTestFuzzer::Fuzz();
5334  return v8_num(239);
5335}
5336
5337
5338static void SetOnThis(Local<String> name,
5339                      Local<Value> value,
5340                      const AccessorInfo& info) {
5341  info.This()->ForceSet(name, value);
5342}
5343
5344
5345THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
5346  v8::HandleScope scope;
5347  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5348  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5349  templ->SetAccessor(v8_str("y"), Return239);
5350  LocalContext context;
5351  context->Global()->Set(v8_str("o"), templ->NewInstance());
5352  v8::Handle<Value> value = CompileRun(
5353      "var result = 0;"
5354      "for (var i = 0; i < 7; i++) {"
5355      "  result = o.y;"
5356      "}");
5357  CHECK_EQ(239, value->Int32Value());
5358}
5359
5360
5361THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
5362  v8::HandleScope scope;
5363  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5364  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5365  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5366  templ_p->SetAccessor(v8_str("y"), Return239);
5367
5368  LocalContext context;
5369  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5370  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5371
5372  v8::Handle<Value> value = CompileRun(
5373      "o.__proto__ = p;"
5374      "var result = 0;"
5375      "for (var i = 0; i < 7; i++) {"
5376      "  result = o.x + o.y;"
5377      "}");
5378  CHECK_EQ(239 + 42, value->Int32Value());
5379}
5380
5381
5382THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
5383  v8::HandleScope scope;
5384  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5385  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5386  templ->SetAccessor(v8_str("y"), Return239);
5387
5388  LocalContext context;
5389  context->Global()->Set(v8_str("o"), templ->NewInstance());
5390
5391  v8::Handle<Value> value = CompileRun(
5392    "fst = new Object();  fst.__proto__ = o;"
5393    "snd = new Object();  snd.__proto__ = fst;"
5394    "var result1 = 0;"
5395    "for (var i = 0; i < 7;  i++) {"
5396    "  result1 = snd.x;"
5397    "}"
5398    "fst.x = 239;"
5399    "var result = 0;"
5400    "for (var i = 0; i < 7; i++) {"
5401    "  result = snd.x;"
5402    "}"
5403    "result + result1");
5404  CHECK_EQ(239 + 42, value->Int32Value());
5405}
5406
5407
5408// Test the case when we stored callback into
5409// a stub, but interceptor produced value on its own.
5410THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
5411  v8::HandleScope scope;
5412  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5413  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5414  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5415  templ_p->SetAccessor(v8_str("y"), Return239);
5416
5417  LocalContext context;
5418  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5419  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5420
5421  v8::Handle<Value> value = CompileRun(
5422    "o.__proto__ = p;"
5423    "for (var i = 0; i < 7; i++) {"
5424    "  o.x;"
5425    // Now it should be ICed and keep a reference to x defined on p
5426    "}"
5427    "var result = 0;"
5428    "for (var i = 0; i < 7; i++) {"
5429    "  result += o.x;"
5430    "}"
5431    "result");
5432  CHECK_EQ(42 * 7, value->Int32Value());
5433}
5434
5435
5436// Test the case when we stored callback into
5437// a stub, but it got invalidated later on.
5438THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
5439  v8::HandleScope scope;
5440  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5441  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5442  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5443  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
5444
5445  LocalContext context;
5446  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5447  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5448
5449  v8::Handle<Value> value = CompileRun(
5450    "inbetween = new Object();"
5451    "o.__proto__ = inbetween;"
5452    "inbetween.__proto__ = p;"
5453    "for (var i = 0; i < 10; i++) {"
5454    "  o.y;"
5455    // Now it should be ICed and keep a reference to y defined on p
5456    "}"
5457    "inbetween.y = 42;"
5458    "var result = 0;"
5459    "for (var i = 0; i < 10; i++) {"
5460    "  result += o.y;"
5461    "}"
5462    "result");
5463  CHECK_EQ(42 * 10, value->Int32Value());
5464}
5465
5466
5467// Test the case when we stored callback into
5468// a stub, but it got invalidated later on due to override on
5469// global object which is between interceptor and callbacks' holders.
5470THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
5471  v8::HandleScope scope;
5472  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5473  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5474  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5475  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
5476
5477  LocalContext context;
5478  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5479  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5480
5481  v8::Handle<Value> value = CompileRun(
5482    "o.__proto__ = this;"
5483    "this.__proto__ = p;"
5484    "for (var i = 0; i < 10; i++) {"
5485    "  if (o.y != 239) throw 'oops: ' + o.y;"
5486    // Now it should be ICed and keep a reference to y defined on p
5487    "}"
5488    "this.y = 42;"
5489    "var result = 0;"
5490    "for (var i = 0; i < 10; i++) {"
5491    "  result += o.y;"
5492    "}"
5493    "result");
5494  CHECK_EQ(42 * 10, value->Int32Value());
5495}
5496
5497
5498static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
5499                                                  const AccessorInfo& info) {
5500  ApiTestFuzzer::Fuzz();
5501  CHECK(v8_str("x")->Equals(name));
5502  return v8::Integer::New(0);
5503}
5504
5505
5506THREADED_TEST(InterceptorReturningZero) {
5507  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
5508     "o.x == undefined ? 1 : 0",
5509     0);
5510}
5511
5512
5513static v8::Handle<Value> InterceptorStoreICSetter(
5514    Local<String> key, Local<Value> value, const AccessorInfo&) {
5515  CHECK(v8_str("x")->Equals(key));
5516  CHECK_EQ(42, value->Int32Value());
5517  return value;
5518}
5519
5520
5521// This test should hit the store IC for the interceptor case.
5522THREADED_TEST(InterceptorStoreIC) {
5523  v8::HandleScope scope;
5524  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5525  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
5526                                 InterceptorStoreICSetter);
5527  LocalContext context;
5528  context->Global()->Set(v8_str("o"), templ->NewInstance());
5529  v8::Handle<Value> value = CompileRun(
5530    "for (var i = 0; i < 1000; i++) {"
5531    "  o.x = 42;"
5532    "}");
5533}
5534
5535
5536THREADED_TEST(InterceptorStoreICWithNoSetter) {
5537  v8::HandleScope scope;
5538  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5539  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5540  LocalContext context;
5541  context->Global()->Set(v8_str("o"), templ->NewInstance());
5542  v8::Handle<Value> value = CompileRun(
5543    "for (var i = 0; i < 1000; i++) {"
5544    "  o.y = 239;"
5545    "}"
5546    "42 + o.y");
5547  CHECK_EQ(239 + 42, value->Int32Value());
5548}
5549
5550
5551
5552
5553v8::Handle<Value> call_ic_function;
5554v8::Handle<Value> call_ic_function2;
5555v8::Handle<Value> call_ic_function3;
5556
5557static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
5558                                                 const AccessorInfo& info) {
5559  ApiTestFuzzer::Fuzz();
5560  CHECK(v8_str("x")->Equals(name));
5561  return call_ic_function;
5562}
5563
5564
5565// This test should hit the call IC for the interceptor case.
5566THREADED_TEST(InterceptorCallIC) {
5567  v8::HandleScope scope;
5568  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5569  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
5570  LocalContext context;
5571  context->Global()->Set(v8_str("o"), templ->NewInstance());
5572  call_ic_function =
5573      v8_compile("function f(x) { return x + 1; }; f")->Run();
5574  v8::Handle<Value> value = CompileRun(
5575    "var result = 0;"
5576    "for (var i = 0; i < 1000; i++) {"
5577    "  result = o.x(41);"
5578    "}");
5579  CHECK_EQ(42, value->Int32Value());
5580}
5581
5582
5583// This test checks that if interceptor doesn't provide
5584// a value, we can fetch regular value.
5585THREADED_TEST(InterceptorCallICSeesOthers) {
5586  v8::HandleScope scope;
5587  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5588  templ->SetNamedPropertyHandler(NoBlockGetterX);
5589  LocalContext context;
5590  context->Global()->Set(v8_str("o"), templ->NewInstance());
5591  v8::Handle<Value> value = CompileRun(
5592    "o.x = function f(x) { return x + 1; };"
5593    "var result = 0;"
5594    "for (var i = 0; i < 7; i++) {"
5595    "  result = o.x(41);"
5596    "}");
5597  CHECK_EQ(42, value->Int32Value());
5598}
5599
5600
5601static v8::Handle<Value> call_ic_function4;
5602static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
5603                                                  const AccessorInfo& info) {
5604  ApiTestFuzzer::Fuzz();
5605  CHECK(v8_str("x")->Equals(name));
5606  return call_ic_function4;
5607}
5608
5609
5610// This test checks that if interceptor provides a function,
5611// even if we cached shadowed variant, interceptor's function
5612// is invoked
5613THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
5614  v8::HandleScope scope;
5615  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5616  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
5617  LocalContext context;
5618  context->Global()->Set(v8_str("o"), templ->NewInstance());
5619  call_ic_function4 =
5620      v8_compile("function f(x) { return x - 1; }; f")->Run();
5621  v8::Handle<Value> value = CompileRun(
5622    "o.__proto__.x = function(x) { return x + 1; };"
5623    "var result = 0;"
5624    "for (var i = 0; i < 1000; i++) {"
5625    "  result = o.x(42);"
5626    "}");
5627  CHECK_EQ(41, value->Int32Value());
5628}
5629
5630
5631// Test the case when we stored cacheable lookup into
5632// a stub, but it got invalidated later on
5633THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
5634  v8::HandleScope scope;
5635  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5636  templ->SetNamedPropertyHandler(NoBlockGetterX);
5637  LocalContext context;
5638  context->Global()->Set(v8_str("o"), templ->NewInstance());
5639  v8::Handle<Value> value = CompileRun(
5640    "proto1 = new Object();"
5641    "proto2 = new Object();"
5642    "o.__proto__ = proto1;"
5643    "proto1.__proto__ = proto2;"
5644    "proto2.y = function(x) { return x + 1; };"
5645    // Invoke it many times to compile a stub
5646    "for (var i = 0; i < 7; i++) {"
5647    "  o.y(42);"
5648    "}"
5649    "proto1.y = function(x) { return x - 1; };"
5650    "var result = 0;"
5651    "for (var i = 0; i < 7; i++) {"
5652    "  result += o.y(42);"
5653    "}");
5654  CHECK_EQ(41 * 7, value->Int32Value());
5655}
5656
5657
5658static v8::Handle<Value> call_ic_function5;
5659static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
5660                                                  const AccessorInfo& info) {
5661  ApiTestFuzzer::Fuzz();
5662  if (v8_str("x")->Equals(name))
5663    return call_ic_function5;
5664  else
5665    return Local<Value>();
5666}
5667
5668
5669// This test checks that if interceptor doesn't provide a function,
5670// cached constant function is used
5671THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
5672  v8::HandleScope scope;
5673  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5674  templ->SetNamedPropertyHandler(NoBlockGetterX);
5675  LocalContext context;
5676  context->Global()->Set(v8_str("o"), templ->NewInstance());
5677  v8::Handle<Value> value = CompileRun(
5678    "function inc(x) { return x + 1; };"
5679    "inc(1);"
5680    "o.x = inc;"
5681    "var result = 0;"
5682    "for (var i = 0; i < 1000; i++) {"
5683    "  result = o.x(42);"
5684    "}");
5685  CHECK_EQ(43, value->Int32Value());
5686}
5687
5688
5689// This test checks that if interceptor provides a function,
5690// even if we cached constant function, interceptor's function
5691// is invoked
5692THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
5693  v8::HandleScope scope;
5694  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5695  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
5696  LocalContext context;
5697  context->Global()->Set(v8_str("o"), templ->NewInstance());
5698  call_ic_function5 =
5699      v8_compile("function f(x) { return x - 1; }; f")->Run();
5700  v8::Handle<Value> value = CompileRun(
5701    "function inc(x) { return x + 1; };"
5702    "inc(1);"
5703    "o.x = inc;"
5704    "var result = 0;"
5705    "for (var i = 0; i < 1000; i++) {"
5706    "  result = o.x(42);"
5707    "}");
5708  CHECK_EQ(41, value->Int32Value());
5709}
5710
5711
5712// Test the case when we stored constant function into
5713// a stub, but it got invalidated later on
5714THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
5715  v8::HandleScope scope;
5716  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5717  templ->SetNamedPropertyHandler(NoBlockGetterX);
5718  LocalContext context;
5719  context->Global()->Set(v8_str("o"), templ->NewInstance());
5720  v8::Handle<Value> value = CompileRun(
5721    "function inc(x) { return x + 1; };"
5722    "inc(1);"
5723    "proto1 = new Object();"
5724    "proto2 = new Object();"
5725    "o.__proto__ = proto1;"
5726    "proto1.__proto__ = proto2;"
5727    "proto2.y = inc;"
5728    // Invoke it many times to compile a stub
5729    "for (var i = 0; i < 7; i++) {"
5730    "  o.y(42);"
5731    "}"
5732    "proto1.y = function(x) { return x - 1; };"
5733    "var result = 0;"
5734    "for (var i = 0; i < 7; i++) {"
5735    "  result += o.y(42);"
5736    "}");
5737  CHECK_EQ(41 * 7, value->Int32Value());
5738}
5739
5740
5741// Test the case when we stored constant function into
5742// a stub, but it got invalidated later on due to override on
5743// global object which is between interceptor and constant function' holders.
5744THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
5745  v8::HandleScope scope;
5746  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5747  templ->SetNamedPropertyHandler(NoBlockGetterX);
5748  LocalContext context;
5749  context->Global()->Set(v8_str("o"), templ->NewInstance());
5750  v8::Handle<Value> value = CompileRun(
5751    "function inc(x) { return x + 1; };"
5752    "inc(1);"
5753    "o.__proto__ = this;"
5754    "this.__proto__.y = inc;"
5755    // Invoke it many times to compile a stub
5756    "for (var i = 0; i < 7; i++) {"
5757    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
5758    "}"
5759    "this.y = function(x) { return x - 1; };"
5760    "var result = 0;"
5761    "for (var i = 0; i < 7; i++) {"
5762    "  result += o.y(42);"
5763    "}");
5764  CHECK_EQ(41 * 7, value->Int32Value());
5765}
5766
5767
5768// Test the case when actual function to call sits on global object.
5769THREADED_TEST(InterceptorCallICCachedFromGlobal) {
5770  v8::HandleScope scope;
5771  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5772  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
5773
5774  LocalContext context;
5775  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5776
5777  v8::Handle<Value> value = CompileRun(
5778    "try {"
5779    "  o.__proto__ = this;"
5780    "  for (var i = 0; i < 10; i++) {"
5781    "    var v = o.parseFloat('239');"
5782    "    if (v != 239) throw v;"
5783      // Now it should be ICed and keep a reference to parseFloat.
5784    "  }"
5785    "  var result = 0;"
5786    "  for (var i = 0; i < 10; i++) {"
5787    "    result += o.parseFloat('239');"
5788    "  }"
5789    "  result"
5790    "} catch(e) {"
5791    "  e"
5792    "};");
5793  CHECK_EQ(239 * 10, value->Int32Value());
5794}
5795
5796
5797static int interceptor_call_count = 0;
5798
5799static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
5800                                                     const AccessorInfo& info) {
5801  ApiTestFuzzer::Fuzz();
5802  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
5803    return call_ic_function2;
5804  }
5805  return v8::Handle<Value>();
5806}
5807
5808
5809// This test should hit load and call ICs for the interceptor case.
5810// Once in a while, the interceptor will reply that a property was not
5811// found in which case we should get a reference error.
5812THREADED_TEST(InterceptorICReferenceErrors) {
5813  v8::HandleScope scope;
5814  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5815  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
5816  LocalContext context(0, templ, v8::Handle<Value>());
5817  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
5818  v8::Handle<Value> value = CompileRun(
5819    "function f() {"
5820    "  for (var i = 0; i < 1000; i++) {"
5821    "    try { x; } catch(e) { return true; }"
5822    "  }"
5823    "  return false;"
5824    "};"
5825    "f();");
5826  CHECK_EQ(true, value->BooleanValue());
5827  interceptor_call_count = 0;
5828  value = CompileRun(
5829    "function g() {"
5830    "  for (var i = 0; i < 1000; i++) {"
5831    "    try { x(42); } catch(e) { return true; }"
5832    "  }"
5833    "  return false;"
5834    "};"
5835    "g();");
5836  CHECK_EQ(true, value->BooleanValue());
5837}
5838
5839
5840static int interceptor_ic_exception_get_count = 0;
5841
5842static v8::Handle<Value> InterceptorICExceptionGetter(
5843    Local<String> name,
5844    const AccessorInfo& info) {
5845  ApiTestFuzzer::Fuzz();
5846  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
5847    return call_ic_function3;
5848  }
5849  if (interceptor_ic_exception_get_count == 20) {
5850    return v8::ThrowException(v8_num(42));
5851  }
5852  // Do not handle get for properties other than x.
5853  return v8::Handle<Value>();
5854}
5855
5856// Test interceptor load/call IC where the interceptor throws an
5857// exception once in a while.
5858THREADED_TEST(InterceptorICGetterExceptions) {
5859  interceptor_ic_exception_get_count = 0;
5860  v8::HandleScope scope;
5861  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5862  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
5863  LocalContext context(0, templ, v8::Handle<Value>());
5864  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
5865  v8::Handle<Value> value = CompileRun(
5866    "function f() {"
5867    "  for (var i = 0; i < 100; i++) {"
5868    "    try { x; } catch(e) { return true; }"
5869    "  }"
5870    "  return false;"
5871    "};"
5872    "f();");
5873  CHECK_EQ(true, value->BooleanValue());
5874  interceptor_ic_exception_get_count = 0;
5875  value = CompileRun(
5876    "function f() {"
5877    "  for (var i = 0; i < 100; i++) {"
5878    "    try { x(42); } catch(e) { return true; }"
5879    "  }"
5880    "  return false;"
5881    "};"
5882    "f();");
5883  CHECK_EQ(true, value->BooleanValue());
5884}
5885
5886
5887static int interceptor_ic_exception_set_count = 0;
5888
5889static v8::Handle<Value> InterceptorICExceptionSetter(
5890      Local<String> key, Local<Value> value, const AccessorInfo&) {
5891  ApiTestFuzzer::Fuzz();
5892  if (++interceptor_ic_exception_set_count > 20) {
5893    return v8::ThrowException(v8_num(42));
5894  }
5895  // Do not actually handle setting.
5896  return v8::Handle<Value>();
5897}
5898
5899// Test interceptor store IC where the interceptor throws an exception
5900// once in a while.
5901THREADED_TEST(InterceptorICSetterExceptions) {
5902  interceptor_ic_exception_set_count = 0;
5903  v8::HandleScope scope;
5904  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5905  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
5906  LocalContext context(0, templ, v8::Handle<Value>());
5907  v8::Handle<Value> value = CompileRun(
5908    "function f() {"
5909    "  for (var i = 0; i < 100; i++) {"
5910    "    try { x = 42; } catch(e) { return true; }"
5911    "  }"
5912    "  return false;"
5913    "};"
5914    "f();");
5915  CHECK_EQ(true, value->BooleanValue());
5916}
5917
5918
5919// Test that we ignore null interceptors.
5920THREADED_TEST(NullNamedInterceptor) {
5921  v8::HandleScope scope;
5922  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5923  templ->SetNamedPropertyHandler(0);
5924  LocalContext context;
5925  templ->Set("x", v8_num(42));
5926  v8::Handle<v8::Object> obj = templ->NewInstance();
5927  context->Global()->Set(v8_str("obj"), obj);
5928  v8::Handle<Value> value = CompileRun("obj.x");
5929  CHECK(value->IsInt32());
5930  CHECK_EQ(42, value->Int32Value());
5931}
5932
5933
5934// Test that we ignore null interceptors.
5935THREADED_TEST(NullIndexedInterceptor) {
5936  v8::HandleScope scope;
5937  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5938  templ->SetIndexedPropertyHandler(0);
5939  LocalContext context;
5940  templ->Set("42", v8_num(42));
5941  v8::Handle<v8::Object> obj = templ->NewInstance();
5942  context->Global()->Set(v8_str("obj"), obj);
5943  v8::Handle<Value> value = CompileRun("obj[42]");
5944  CHECK(value->IsInt32());
5945  CHECK_EQ(42, value->Int32Value());
5946}
5947
5948
5949static v8::Handle<Value> ParentGetter(Local<String> name,
5950                                      const AccessorInfo& info) {
5951  ApiTestFuzzer::Fuzz();
5952  return v8_num(1);
5953}
5954
5955
5956static v8::Handle<Value> ChildGetter(Local<String> name,
5957                                     const AccessorInfo& info) {
5958  ApiTestFuzzer::Fuzz();
5959  return v8_num(42);
5960}
5961
5962
5963THREADED_TEST(Overriding) {
5964  v8::HandleScope scope;
5965  LocalContext context;
5966
5967  // Parent template.
5968  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
5969  Local<ObjectTemplate> parent_instance_templ =
5970      parent_templ->InstanceTemplate();
5971  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
5972
5973  // Template that inherits from the parent template.
5974  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
5975  Local<ObjectTemplate> child_instance_templ =
5976      child_templ->InstanceTemplate();
5977  child_templ->Inherit(parent_templ);
5978  // Override 'f'.  The child version of 'f' should get called for child
5979  // instances.
5980  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
5981  // Add 'g' twice.  The 'g' added last should get called for instances.
5982  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
5983  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
5984
5985  // Add 'h' as an accessor to the proto template with ReadOnly attributes
5986  // so 'h' can be shadowed on the instance object.
5987  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
5988  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
5989      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
5990
5991  // Add 'i' as an accessor to the instance template with ReadOnly attributes
5992  // but the attribute does not have effect because it is duplicated with
5993  // NULL setter.
5994  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
5995      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
5996
5997
5998
5999  // Instantiate the child template.
6000  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
6001
6002  // Check that the child function overrides the parent one.
6003  context->Global()->Set(v8_str("o"), instance);
6004  Local<Value> value = v8_compile("o.f")->Run();
6005  // Check that the 'g' that was added last is hit.
6006  CHECK_EQ(42, value->Int32Value());
6007  value = v8_compile("o.g")->Run();
6008  CHECK_EQ(42, value->Int32Value());
6009
6010  // Check 'h' can be shadowed.
6011  value = v8_compile("o.h = 3; o.h")->Run();
6012  CHECK_EQ(3, value->Int32Value());
6013
6014  // Check 'i' is cannot be shadowed or changed.
6015  value = v8_compile("o.i = 3; o.i")->Run();
6016  CHECK_EQ(42, value->Int32Value());
6017}
6018
6019
6020static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
6021  ApiTestFuzzer::Fuzz();
6022  if (args.IsConstructCall()) {
6023    return v8::Boolean::New(true);
6024  }
6025  return v8::Boolean::New(false);
6026}
6027
6028
6029THREADED_TEST(IsConstructCall) {
6030  v8::HandleScope scope;
6031
6032  // Function template with call handler.
6033  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6034  templ->SetCallHandler(IsConstructHandler);
6035
6036  LocalContext context;
6037
6038  context->Global()->Set(v8_str("f"), templ->GetFunction());
6039  Local<Value> value = v8_compile("f()")->Run();
6040  CHECK(!value->BooleanValue());
6041  value = v8_compile("new f()")->Run();
6042  CHECK(value->BooleanValue());
6043}
6044
6045
6046THREADED_TEST(ObjectProtoToString) {
6047  v8::HandleScope scope;
6048  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6049  templ->SetClassName(v8_str("MyClass"));
6050
6051  LocalContext context;
6052
6053  Local<String> customized_tostring = v8_str("customized toString");
6054
6055  // Replace Object.prototype.toString
6056  v8_compile("Object.prototype.toString = function() {"
6057                  "  return 'customized toString';"
6058                  "}")->Run();
6059
6060  // Normal ToString call should call replaced Object.prototype.toString
6061  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
6062  Local<String> value = instance->ToString();
6063  CHECK(value->IsString() && value->Equals(customized_tostring));
6064
6065  // ObjectProtoToString should not call replace toString function.
6066  value = instance->ObjectProtoToString();
6067  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
6068
6069  // Check global
6070  value = context->Global()->ObjectProtoToString();
6071  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
6072
6073  // Check ordinary object
6074  Local<Value> object = v8_compile("new Object()")->Run();
6075  value = Local<v8::Object>::Cast(object)->ObjectProtoToString();
6076  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
6077}
6078
6079
6080bool ApiTestFuzzer::fuzzing_ = false;
6081v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
6082  v8::internal::OS::CreateSemaphore(0);
6083int ApiTestFuzzer::active_tests_;
6084int ApiTestFuzzer::tests_being_run_;
6085int ApiTestFuzzer::current_;
6086
6087
6088// We are in a callback and want to switch to another thread (if we
6089// are currently running the thread fuzzing test).
6090void ApiTestFuzzer::Fuzz() {
6091  if (!fuzzing_) return;
6092  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
6093  test->ContextSwitch();
6094}
6095
6096
6097// Let the next thread go.  Since it is also waiting on the V8 lock it may
6098// not start immediately.
6099bool ApiTestFuzzer::NextThread() {
6100  int test_position = GetNextTestNumber();
6101  const char* test_name = RegisterThreadedTest::nth(current_)->name();
6102  if (test_position == current_) {
6103    if (kLogThreading)
6104      printf("Stay with %s\n", test_name);
6105    return false;
6106  }
6107  if (kLogThreading) {
6108    printf("Switch from %s to %s\n",
6109           test_name,
6110           RegisterThreadedTest::nth(test_position)->name());
6111  }
6112  current_ = test_position;
6113  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
6114  return true;
6115}
6116
6117
6118void ApiTestFuzzer::Run() {
6119  // When it is our turn...
6120  gate_->Wait();
6121  {
6122    // ... get the V8 lock and start running the test.
6123    v8::Locker locker;
6124    CallTest();
6125  }
6126  // This test finished.
6127  active_ = false;
6128  active_tests_--;
6129  // If it was the last then signal that fact.
6130  if (active_tests_ == 0) {
6131    all_tests_done_->Signal();
6132  } else {
6133    // Otherwise select a new test and start that.
6134    NextThread();
6135  }
6136}
6137
6138
6139static unsigned linear_congruential_generator;
6140
6141
6142void ApiTestFuzzer::Setup(PartOfTest part) {
6143  linear_congruential_generator = i::FLAG_testing_prng_seed;
6144  fuzzing_ = true;
6145  int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
6146  int end = (part == FIRST_PART)
6147      ? (RegisterThreadedTest::count() >> 1)
6148      : RegisterThreadedTest::count();
6149  active_tests_ = tests_being_run_ = end - start;
6150  for (int i = 0; i < tests_being_run_; i++) {
6151    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
6152  }
6153  for (int i = 0; i < active_tests_; i++) {
6154    RegisterThreadedTest::nth(i)->fuzzer_->Start();
6155  }
6156}
6157
6158
6159static void CallTestNumber(int test_number) {
6160  (RegisterThreadedTest::nth(test_number)->callback())();
6161}
6162
6163
6164void ApiTestFuzzer::RunAllTests() {
6165  // Set off the first test.
6166  current_ = -1;
6167  NextThread();
6168  // Wait till they are all done.
6169  all_tests_done_->Wait();
6170}
6171
6172
6173int ApiTestFuzzer::GetNextTestNumber() {
6174  int next_test;
6175  do {
6176    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
6177    linear_congruential_generator *= 1664525u;
6178    linear_congruential_generator += 1013904223u;
6179  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
6180  return next_test;
6181}
6182
6183
6184void ApiTestFuzzer::ContextSwitch() {
6185  // If the new thread is the same as the current thread there is nothing to do.
6186  if (NextThread()) {
6187    // Now it can start.
6188    v8::Unlocker unlocker;
6189    // Wait till someone starts us again.
6190    gate_->Wait();
6191    // And we're off.
6192  }
6193}
6194
6195
6196void ApiTestFuzzer::TearDown() {
6197  fuzzing_ = false;
6198  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
6199    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
6200    if (fuzzer != NULL) fuzzer->Join();
6201  }
6202}
6203
6204
6205// Lets not be needlessly self-referential.
6206TEST(Threading) {
6207  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
6208  ApiTestFuzzer::RunAllTests();
6209  ApiTestFuzzer::TearDown();
6210}
6211
6212TEST(Threading2) {
6213  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
6214  ApiTestFuzzer::RunAllTests();
6215  ApiTestFuzzer::TearDown();
6216}
6217
6218
6219void ApiTestFuzzer::CallTest() {
6220  if (kLogThreading)
6221    printf("Start test %d\n", test_number_);
6222  CallTestNumber(test_number_);
6223  if (kLogThreading)
6224    printf("End test %d\n", test_number_);
6225}
6226
6227
6228static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
6229  CHECK(v8::Locker::IsLocked());
6230  ApiTestFuzzer::Fuzz();
6231  v8::Unlocker unlocker;
6232  const char* code = "throw 7;";
6233  {
6234    v8::Locker nested_locker;
6235    v8::HandleScope scope;
6236    v8::Handle<Value> exception;
6237    { v8::TryCatch try_catch;
6238      v8::Handle<Value> value = CompileRun(code);
6239      CHECK(value.IsEmpty());
6240      CHECK(try_catch.HasCaught());
6241      // Make sure to wrap the exception in a new handle because
6242      // the handle returned from the TryCatch is destroyed
6243      // when the TryCatch is destroyed.
6244      exception = Local<Value>::New(try_catch.Exception());
6245    }
6246    return v8::ThrowException(exception);
6247  }
6248}
6249
6250
6251static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
6252  CHECK(v8::Locker::IsLocked());
6253  ApiTestFuzzer::Fuzz();
6254  v8::Unlocker unlocker;
6255  const char* code = "throw 7;";
6256  {
6257    v8::Locker nested_locker;
6258    v8::HandleScope scope;
6259    v8::Handle<Value> value = CompileRun(code);
6260    CHECK(value.IsEmpty());
6261    return v8_str("foo");
6262  }
6263}
6264
6265
6266// These are locking tests that don't need to be run again
6267// as part of the locking aggregation tests.
6268TEST(NestedLockers) {
6269  v8::Locker locker;
6270  CHECK(v8::Locker::IsLocked());
6271  v8::HandleScope scope;
6272  LocalContext env;
6273  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
6274  Local<Function> fun = fun_templ->GetFunction();
6275  env->Global()->Set(v8_str("throw_in_js"), fun);
6276  Local<Script> script = v8_compile("(function () {"
6277                                    "  try {"
6278                                    "    throw_in_js();"
6279                                    "    return 42;"
6280                                    "  } catch (e) {"
6281                                    "    return e * 13;"
6282                                    "  }"
6283                                    "})();");
6284  CHECK_EQ(91, script->Run()->Int32Value());
6285}
6286
6287
6288// These are locking tests that don't need to be run again
6289// as part of the locking aggregation tests.
6290TEST(NestedLockersNoTryCatch) {
6291  v8::Locker locker;
6292  v8::HandleScope scope;
6293  LocalContext env;
6294  Local<v8::FunctionTemplate> fun_templ =
6295      v8::FunctionTemplate::New(ThrowInJSNoCatch);
6296  Local<Function> fun = fun_templ->GetFunction();
6297  env->Global()->Set(v8_str("throw_in_js"), fun);
6298  Local<Script> script = v8_compile("(function () {"
6299                                    "  try {"
6300                                    "    throw_in_js();"
6301                                    "    return 42;"
6302                                    "  } catch (e) {"
6303                                    "    return e * 13;"
6304                                    "  }"
6305                                    "})();");
6306  CHECK_EQ(91, script->Run()->Int32Value());
6307}
6308
6309
6310THREADED_TEST(RecursiveLocking) {
6311  v8::Locker locker;
6312  {
6313    v8::Locker locker2;
6314    CHECK(v8::Locker::IsLocked());
6315  }
6316}
6317
6318
6319static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
6320  ApiTestFuzzer::Fuzz();
6321  v8::Unlocker unlocker;
6322  return v8::Undefined();
6323}
6324
6325
6326THREADED_TEST(LockUnlockLock) {
6327  {
6328    v8::Locker locker;
6329    v8::HandleScope scope;
6330    LocalContext env;
6331    Local<v8::FunctionTemplate> fun_templ =
6332        v8::FunctionTemplate::New(UnlockForAMoment);
6333    Local<Function> fun = fun_templ->GetFunction();
6334    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
6335    Local<Script> script = v8_compile("(function () {"
6336                                      "  unlock_for_a_moment();"
6337                                      "  return 42;"
6338                                      "})();");
6339    CHECK_EQ(42, script->Run()->Int32Value());
6340  }
6341  {
6342    v8::Locker locker;
6343    v8::HandleScope scope;
6344    LocalContext env;
6345    Local<v8::FunctionTemplate> fun_templ =
6346        v8::FunctionTemplate::New(UnlockForAMoment);
6347    Local<Function> fun = fun_templ->GetFunction();
6348    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
6349    Local<Script> script = v8_compile("(function () {"
6350                                      "  unlock_for_a_moment();"
6351                                      "  return 42;"
6352                                      "})();");
6353    CHECK_EQ(42, script->Run()->Int32Value());
6354  }
6355}
6356
6357
6358static int GetGlobalObjectsCount() {
6359  int count = 0;
6360  v8::internal::HeapIterator it;
6361  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
6362    if (object->IsJSGlobalObject()) count++;
6363  return count;
6364}
6365
6366
6367static int GetSurvivingGlobalObjectsCount() {
6368  // We need to collect all garbage twice to be sure that everything
6369  // has been collected.  This is because inline caches are cleared in
6370  // the first garbage collection but some of the maps have already
6371  // been marked at that point.  Therefore some of the maps are not
6372  // collected until the second garbage collection.
6373  v8::internal::Heap::CollectAllGarbage(false);
6374  v8::internal::Heap::CollectAllGarbage(false);
6375  int count = GetGlobalObjectsCount();
6376#ifdef DEBUG
6377  if (count > 0) v8::internal::Heap::TracePathToGlobal();
6378#endif
6379  return count;
6380}
6381
6382
6383TEST(DontLeakGlobalObjects) {
6384  // Regression test for issues 1139850 and 1174891.
6385
6386  v8::V8::Initialize();
6387
6388  int count = GetSurvivingGlobalObjectsCount();
6389
6390  for (int i = 0; i < 5; i++) {
6391    { v8::HandleScope scope;
6392      LocalContext context;
6393    }
6394    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6395
6396    { v8::HandleScope scope;
6397      LocalContext context;
6398      v8_compile("Date")->Run();
6399    }
6400    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6401
6402    { v8::HandleScope scope;
6403      LocalContext context;
6404      v8_compile("/aaa/")->Run();
6405    }
6406    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6407
6408    { v8::HandleScope scope;
6409      const char* extension_list[] = { "v8/gc" };
6410      v8::ExtensionConfiguration extensions(1, extension_list);
6411      LocalContext context(&extensions);
6412      v8_compile("gc();")->Run();
6413    }
6414    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6415  }
6416}
6417
6418
6419v8::Persistent<v8::Object> some_object;
6420v8::Persistent<v8::Object> bad_handle;
6421
6422void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
6423  v8::HandleScope scope;
6424  bad_handle = v8::Persistent<v8::Object>::New(some_object);
6425}
6426
6427
6428THREADED_TEST(NewPersistentHandleFromWeakCallback) {
6429  LocalContext context;
6430
6431  v8::Persistent<v8::Object> handle1, handle2;
6432  {
6433    v8::HandleScope scope;
6434    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
6435    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
6436    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
6437  }
6438  // Note: order is implementation dependent alas: currently
6439  // global handle nodes are processed by PostGarbageCollectionProcessing
6440  // in reverse allocation order, so if second allocated handle is deleted,
6441  // weak callback of the first handle would be able to 'reallocate' it.
6442  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
6443  handle2.Dispose();
6444  i::Heap::CollectAllGarbage(false);
6445}
6446
6447
6448v8::Persistent<v8::Object> to_be_disposed;
6449
6450void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
6451  to_be_disposed.Dispose();
6452  i::Heap::CollectAllGarbage(false);
6453}
6454
6455
6456THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
6457  LocalContext context;
6458
6459  v8::Persistent<v8::Object> handle1, handle2;
6460  {
6461    v8::HandleScope scope;
6462    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
6463    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
6464  }
6465  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
6466  to_be_disposed = handle2;
6467  i::Heap::CollectAllGarbage(false);
6468}
6469
6470void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
6471  handle.Dispose();
6472}
6473
6474void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
6475  v8::HandleScope scope;
6476  v8::Persistent<v8::Object>::New(v8::Object::New());
6477}
6478
6479
6480THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
6481  LocalContext context;
6482
6483  v8::Persistent<v8::Object> handle1, handle2, handle3;
6484  {
6485    v8::HandleScope scope;
6486    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
6487    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
6488    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
6489  }
6490  handle2.MakeWeak(NULL, DisposingCallback);
6491  handle3.MakeWeak(NULL, HandleCreatingCallback);
6492  i::Heap::CollectAllGarbage(false);
6493}
6494
6495
6496THREADED_TEST(CheckForCrossContextObjectLiterals) {
6497  v8::V8::Initialize();
6498
6499  const int nof = 2;
6500  const char* sources[nof] = {
6501    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
6502    "Object()"
6503  };
6504
6505  for (int i = 0; i < nof; i++) {
6506    const char* source = sources[i];
6507    { v8::HandleScope scope;
6508      LocalContext context;
6509      CompileRun(source);
6510    }
6511    { v8::HandleScope scope;
6512      LocalContext context;
6513      CompileRun(source);
6514    }
6515  }
6516}
6517
6518
6519static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
6520  v8::HandleScope inner;
6521  env->Enter();
6522  v8::Handle<Value> three = v8_num(3);
6523  v8::Handle<Value> value = inner.Close(three);
6524  env->Exit();
6525  return value;
6526}
6527
6528
6529THREADED_TEST(NestedHandleScopeAndContexts) {
6530  v8::HandleScope outer;
6531  v8::Persistent<Context> env = Context::New();
6532  env->Enter();
6533  v8::Handle<Value> value = NestedScope(env);
6534  v8::Handle<String> str = value->ToString();
6535  env->Exit();
6536  env.Dispose();
6537}
6538
6539
6540THREADED_TEST(ExternalAllocatedMemory) {
6541  v8::HandleScope outer;
6542  v8::Persistent<Context> env = Context::New();
6543  const int kSize = 1024*1024;
6544  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
6545  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
6546}
6547
6548
6549THREADED_TEST(DisposeEnteredContext) {
6550  v8::HandleScope scope;
6551  LocalContext outer;
6552  { v8::Persistent<v8::Context> inner = v8::Context::New();
6553    inner->Enter();
6554    inner.Dispose();
6555    inner.Clear();
6556    inner->Exit();
6557  }
6558}
6559
6560
6561// Regression test for issue 54, object templates with internal fields
6562// but no accessors or interceptors did not get their internal field
6563// count set on instances.
6564THREADED_TEST(Regress54) {
6565  v8::HandleScope outer;
6566  LocalContext context;
6567  static v8::Persistent<v8::ObjectTemplate> templ;
6568  if (templ.IsEmpty()) {
6569    v8::HandleScope inner;
6570    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
6571    local->SetInternalFieldCount(1);
6572    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
6573  }
6574  v8::Handle<v8::Object> result = templ->NewInstance();
6575  CHECK_EQ(1, result->InternalFieldCount());
6576}
6577
6578
6579// If part of the threaded tests, this test makes ThreadingTest fail
6580// on mac.
6581TEST(CatchStackOverflow) {
6582  v8::HandleScope scope;
6583  LocalContext context;
6584  v8::TryCatch try_catch;
6585  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
6586    "function f() {"
6587    "  return f();"
6588    "}"
6589    ""
6590    "f();"));
6591  v8::Handle<v8::Value> result = script->Run();
6592  CHECK(result.IsEmpty());
6593}
6594
6595
6596static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
6597                                    const char* resource_name,
6598                                    int line_offset) {
6599  v8::HandleScope scope;
6600  v8::TryCatch try_catch;
6601  v8::Handle<v8::Value> result = script->Run();
6602  CHECK(result.IsEmpty());
6603  CHECK(try_catch.HasCaught());
6604  v8::Handle<v8::Message> message = try_catch.Message();
6605  CHECK(!message.IsEmpty());
6606  CHECK_EQ(10 + line_offset, message->GetLineNumber());
6607  CHECK_EQ(91, message->GetStartPosition());
6608  CHECK_EQ(92, message->GetEndPosition());
6609  CHECK_EQ(2, message->GetStartColumn());
6610  CHECK_EQ(3, message->GetEndColumn());
6611  v8::String::AsciiValue line(message->GetSourceLine());
6612  CHECK_EQ("  throw 'nirk';", *line);
6613  v8::String::AsciiValue name(message->GetScriptResourceName());
6614  CHECK_EQ(resource_name, *name);
6615}
6616
6617
6618THREADED_TEST(TryCatchSourceInfo) {
6619  v8::HandleScope scope;
6620  LocalContext context;
6621  v8::Handle<v8::String> source = v8::String::New(
6622      "function Foo() {\n"
6623      "  return Bar();\n"
6624      "}\n"
6625      "\n"
6626      "function Bar() {\n"
6627      "  return Baz();\n"
6628      "}\n"
6629      "\n"
6630      "function Baz() {\n"
6631      "  throw 'nirk';\n"
6632      "}\n"
6633      "\n"
6634      "Foo();\n");
6635
6636  const char* resource_name;
6637  v8::Handle<v8::Script> script;
6638  resource_name = "test.js";
6639  script = v8::Script::Compile(source, v8::String::New(resource_name));
6640  CheckTryCatchSourceInfo(script, resource_name, 0);
6641
6642  resource_name = "test1.js";
6643  v8::ScriptOrigin origin1(v8::String::New(resource_name));
6644  script = v8::Script::Compile(source, &origin1);
6645  CheckTryCatchSourceInfo(script, resource_name, 0);
6646
6647  resource_name = "test2.js";
6648  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
6649  script = v8::Script::Compile(source, &origin2);
6650  CheckTryCatchSourceInfo(script, resource_name, 7);
6651}
6652
6653
6654THREADED_TEST(CompilationCache) {
6655  v8::HandleScope scope;
6656  LocalContext context;
6657  v8::Handle<v8::String> source0 = v8::String::New("1234");
6658  v8::Handle<v8::String> source1 = v8::String::New("1234");
6659  v8::Handle<v8::Script> script0 =
6660      v8::Script::Compile(source0, v8::String::New("test.js"));
6661  v8::Handle<v8::Script> script1 =
6662      v8::Script::Compile(source1, v8::String::New("test.js"));
6663  v8::Handle<v8::Script> script2 =
6664      v8::Script::Compile(source0);  // different origin
6665  CHECK_EQ(1234, script0->Run()->Int32Value());
6666  CHECK_EQ(1234, script1->Run()->Int32Value());
6667  CHECK_EQ(1234, script2->Run()->Int32Value());
6668}
6669
6670
6671static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
6672  ApiTestFuzzer::Fuzz();
6673  return v8_num(42);
6674}
6675
6676
6677THREADED_TEST(CallbackFunctionName) {
6678  v8::HandleScope scope;
6679  LocalContext context;
6680  Local<ObjectTemplate> t = ObjectTemplate::New();
6681  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
6682  context->Global()->Set(v8_str("obj"), t->NewInstance());
6683  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
6684  CHECK(value->IsString());
6685  v8::String::AsciiValue name(value);
6686  CHECK_EQ("asdf", *name);
6687}
6688
6689
6690THREADED_TEST(DateAccess) {
6691  v8::HandleScope scope;
6692  LocalContext context;
6693  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
6694  CHECK(date->IsDate());
6695  CHECK_EQ(1224744689038.0, v8::Handle<v8::Date>::Cast(date)->NumberValue());
6696}
6697
6698
6699void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
6700  v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
6701  v8::Handle<v8::Array> props = obj->GetPropertyNames();
6702  CHECK_EQ(elmc, props->Length());
6703  for (int i = 0; i < elmc; i++) {
6704    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
6705    CHECK_EQ(elmv[i], *elm);
6706  }
6707}
6708
6709
6710THREADED_TEST(PropertyEnumeration) {
6711  v8::HandleScope scope;
6712  LocalContext context;
6713  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
6714      "var result = [];"
6715      "result[0] = {};"
6716      "result[1] = {a: 1, b: 2};"
6717      "result[2] = [1, 2, 3];"
6718      "var proto = {x: 1, y: 2, z: 3};"
6719      "var x = { __proto__: proto, w: 0, z: 1 };"
6720      "result[3] = x;"
6721      "result;"))->Run();
6722  v8::Handle<v8::Array> elms = v8::Handle<v8::Array>::Cast(obj);
6723  CHECK_EQ(4, elms->Length());
6724  int elmc0 = 0;
6725  const char** elmv0 = NULL;
6726  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
6727  int elmc1 = 2;
6728  const char* elmv1[] = {"a", "b"};
6729  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
6730  int elmc2 = 3;
6731  const char* elmv2[] = {"0", "1", "2"};
6732  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
6733  int elmc3 = 4;
6734  const char* elmv3[] = {"w", "z", "x", "y"};
6735  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
6736}
6737
6738
6739static bool NamedSetAccessBlocker(Local<v8::Object> obj,
6740                                  Local<Value> name,
6741                                  v8::AccessType type,
6742                                  Local<Value> data) {
6743  return type != v8::ACCESS_SET;
6744}
6745
6746
6747static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
6748                                    uint32_t key,
6749                                    v8::AccessType type,
6750                                    Local<Value> data) {
6751  return type != v8::ACCESS_SET;
6752}
6753
6754
6755THREADED_TEST(DisableAccessChecksWhileConfiguring) {
6756  v8::HandleScope scope;
6757  LocalContext context;
6758  Local<ObjectTemplate> templ = ObjectTemplate::New();
6759  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
6760                                 IndexedSetAccessBlocker);
6761  templ->Set(v8_str("x"), v8::True());
6762  Local<v8::Object> instance = templ->NewInstance();
6763  context->Global()->Set(v8_str("obj"), instance);
6764  Local<Value> value = CompileRun("obj.x");
6765  CHECK(value->BooleanValue());
6766}
6767
6768
6769static bool NamedGetAccessBlocker(Local<v8::Object> obj,
6770                                  Local<Value> name,
6771                                  v8::AccessType type,
6772                                  Local<Value> data) {
6773  return false;
6774}
6775
6776
6777static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
6778                                    uint32_t key,
6779                                    v8::AccessType type,
6780                                    Local<Value> data) {
6781  return false;
6782}
6783
6784
6785
6786THREADED_TEST(AccessChecksReenabledCorrectly) {
6787  v8::HandleScope scope;
6788  LocalContext context;
6789  Local<ObjectTemplate> templ = ObjectTemplate::New();
6790  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
6791                                 IndexedGetAccessBlocker);
6792  templ->Set(v8_str("a"), v8_str("a"));
6793  // Add more than 8 (see kMaxFastProperties) properties
6794  // so that the constructor will force copying map.
6795  // Cannot sprintf, gcc complains unsafety.
6796  char buf[4];
6797  for (char i = '0'; i <= '9' ; i++) {
6798    buf[0] = i;
6799    for (char j = '0'; j <= '9'; j++) {
6800      buf[1] = j;
6801      for (char k = '0'; k <= '9'; k++) {
6802        buf[2] = k;
6803        buf[3] = 0;
6804        templ->Set(v8_str(buf), v8::Number::New(k));
6805      }
6806    }
6807  }
6808
6809  Local<v8::Object> instance_1 = templ->NewInstance();
6810  context->Global()->Set(v8_str("obj_1"), instance_1);
6811
6812  Local<Value> value_1 = CompileRun("obj_1.a");
6813  CHECK(value_1->IsUndefined());
6814
6815  Local<v8::Object> instance_2 = templ->NewInstance();
6816  context->Global()->Set(v8_str("obj_2"), instance_2);
6817
6818  Local<Value> value_2 = CompileRun("obj_2.a");
6819  CHECK(value_2->IsUndefined());
6820}
6821
6822
6823// This tests that access check information remains on the global
6824// object template when creating contexts.
6825THREADED_TEST(AccessControlRepeatedContextCreation) {
6826  v8::HandleScope handle_scope;
6827  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6828  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
6829                                           IndexedSetAccessBlocker);
6830  i::Handle<i::ObjectTemplateInfo> internal_template =
6831      v8::Utils::OpenHandle(*global_template);
6832  CHECK(!internal_template->constructor()->IsUndefined());
6833  i::Handle<i::FunctionTemplateInfo> constructor(
6834      i::FunctionTemplateInfo::cast(internal_template->constructor()));
6835  CHECK(!constructor->access_check_info()->IsUndefined());
6836  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6837  CHECK(!constructor->access_check_info()->IsUndefined());
6838}
6839
6840
6841THREADED_TEST(TurnOnAccessCheck) {
6842  v8::HandleScope handle_scope;
6843
6844  // Create an environment with access check to the global object disabled by
6845  // default.
6846  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6847  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
6848                                           IndexedGetAccessBlocker,
6849                                           v8::Handle<v8::Value>(),
6850                                           false);
6851  v8::Persistent<Context> context = Context::New(NULL, global_template);
6852  Context::Scope context_scope(context);
6853
6854  // Set up a property and a number of functions.
6855  context->Global()->Set(v8_str("a"), v8_num(1));
6856  CompileRun("function f1() {return a;}"
6857             "function f2() {return a;}"
6858             "function g1() {return h();}"
6859             "function g2() {return h();}"
6860             "function h() {return 1;}");
6861  Local<Function> f1 =
6862      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
6863  Local<Function> f2 =
6864      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
6865  Local<Function> g1 =
6866      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
6867  Local<Function> g2 =
6868      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
6869  Local<Function> h =
6870      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
6871
6872  // Get the global object.
6873  v8::Handle<v8::Object> global = context->Global();
6874
6875  // Call f1 one time and f2 a number of times. This will ensure that f1 still
6876  // uses the runtime system to retreive property a whereas f2 uses global load
6877  // inline cache.
6878  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
6879  for (int i = 0; i < 4; i++) {
6880    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
6881  }
6882
6883  // Same for g1 and g2.
6884  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
6885  for (int i = 0; i < 4; i++) {
6886    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
6887  }
6888
6889  // Detach the global and turn on access check.
6890  context->DetachGlobal();
6891  context->Global()->TurnOnAccessCheck();
6892
6893  // Failing access check to property get results in undefined.
6894  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
6895  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
6896
6897  // Failing access check to function call results in exception.
6898  CHECK(g1->Call(global, 0, NULL).IsEmpty());
6899  CHECK(g2->Call(global, 0, NULL).IsEmpty());
6900
6901  // No failing access check when just returning a constant.
6902  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
6903}
6904
6905
6906// This test verifies that pre-compilation (aka preparsing) can be called
6907// without initializing the whole VM. Thus we cannot run this test in a
6908// multi-threaded setup.
6909TEST(PreCompile) {
6910  // TODO(155): This test would break without the initialization of V8. This is
6911  // a workaround for now to make this test not fail.
6912  v8::V8::Initialize();
6913  const char *script = "function foo(a) { return a+1; }";
6914  v8::ScriptData *sd =
6915      v8::ScriptData::PreCompile(script, i::StrLength(script));
6916  CHECK_NE(sd->Length(), 0);
6917  CHECK_NE(sd->Data(), NULL);
6918  CHECK(!sd->HasError());
6919  delete sd;
6920}
6921
6922
6923TEST(PreCompileWithError) {
6924  v8::V8::Initialize();
6925  const char *script = "function foo(a) { return 1 * * 2; }";
6926  v8::ScriptData *sd =
6927      v8::ScriptData::PreCompile(script, i::StrLength(script));
6928  CHECK(sd->HasError());
6929  delete sd;
6930}
6931
6932
6933TEST(Regress31661) {
6934  v8::V8::Initialize();
6935  const char *script = " The Definintive Guide";
6936  v8::ScriptData *sd =
6937      v8::ScriptData::PreCompile(script, i::StrLength(script));
6938  CHECK(sd->HasError());
6939  delete sd;
6940}
6941
6942
6943// This tests that we do not allow dictionary load/call inline caches
6944// to use functions that have not yet been compiled.  The potential
6945// problem of loading a function that has not yet been compiled can
6946// arise because we share code between contexts via the compilation
6947// cache.
6948THREADED_TEST(DictionaryICLoadedFunction) {
6949  v8::HandleScope scope;
6950  // Test LoadIC.
6951  for (int i = 0; i < 2; i++) {
6952    LocalContext context;
6953    context->Global()->Set(v8_str("tmp"), v8::True());
6954    context->Global()->Delete(v8_str("tmp"));
6955    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
6956  }
6957  // Test CallIC.
6958  for (int i = 0; i < 2; i++) {
6959    LocalContext context;
6960    context->Global()->Set(v8_str("tmp"), v8::True());
6961    context->Global()->Delete(v8_str("tmp"));
6962    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
6963  }
6964}
6965
6966
6967// Test that cross-context new calls use the context of the callee to
6968// create the new JavaScript object.
6969THREADED_TEST(CrossContextNew) {
6970  v8::HandleScope scope;
6971  v8::Persistent<Context> context0 = Context::New();
6972  v8::Persistent<Context> context1 = Context::New();
6973
6974  // Allow cross-domain access.
6975  Local<String> token = v8_str("<security token>");
6976  context0->SetSecurityToken(token);
6977  context1->SetSecurityToken(token);
6978
6979  // Set an 'x' property on the Object prototype and define a
6980  // constructor function in context0.
6981  context0->Enter();
6982  CompileRun("Object.prototype.x = 42; function C() {};");
6983  context0->Exit();
6984
6985  // Call the constructor function from context0 and check that the
6986  // result has the 'x' property.
6987  context1->Enter();
6988  context1->Global()->Set(v8_str("other"), context0->Global());
6989  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
6990  CHECK(value->IsInt32());
6991  CHECK_EQ(42, value->Int32Value());
6992  context1->Exit();
6993
6994  // Dispose the contexts to allow them to be garbage collected.
6995  context0.Dispose();
6996  context1.Dispose();
6997}
6998
6999
7000class RegExpInterruptTest {
7001 public:
7002  RegExpInterruptTest() : block_(NULL) {}
7003  ~RegExpInterruptTest() { delete block_; }
7004  void RunTest() {
7005    block_ = i::OS::CreateSemaphore(0);
7006    gc_count_ = 0;
7007    gc_during_regexp_ = 0;
7008    regexp_success_ = false;
7009    gc_success_ = false;
7010    GCThread gc_thread(this);
7011    gc_thread.Start();
7012    v8::Locker::StartPreemption(1);
7013
7014    LongRunningRegExp();
7015    {
7016      v8::Unlocker unlock;
7017      gc_thread.Join();
7018    }
7019    v8::Locker::StopPreemption();
7020    CHECK(regexp_success_);
7021    CHECK(gc_success_);
7022  }
7023 private:
7024  // Number of garbage collections required.
7025  static const int kRequiredGCs = 5;
7026
7027  class GCThread : public i::Thread {
7028   public:
7029    explicit GCThread(RegExpInterruptTest* test)
7030        : test_(test) {}
7031    virtual void Run() {
7032      test_->CollectGarbage();
7033    }
7034   private:
7035     RegExpInterruptTest* test_;
7036  };
7037
7038  void CollectGarbage() {
7039    block_->Wait();
7040    while (gc_during_regexp_ < kRequiredGCs) {
7041      {
7042        v8::Locker lock;
7043        // TODO(lrn): Perhaps create some garbage before collecting.
7044        i::Heap::CollectAllGarbage(false);
7045        gc_count_++;
7046      }
7047      i::OS::Sleep(1);
7048    }
7049    gc_success_ = true;
7050  }
7051
7052  void LongRunningRegExp() {
7053    block_->Signal();  // Enable garbage collection thread on next preemption.
7054    int rounds = 0;
7055    while (gc_during_regexp_ < kRequiredGCs) {
7056      int gc_before = gc_count_;
7057      {
7058        // Match 15-30 "a"'s against 14 and a "b".
7059        const char* c_source =
7060            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
7061            ".exec('aaaaaaaaaaaaaaab') === null";
7062        Local<String> source = String::New(c_source);
7063        Local<Script> script = Script::Compile(source);
7064        Local<Value> result = script->Run();
7065        if (!result->BooleanValue()) {
7066          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
7067          return;
7068        }
7069      }
7070      {
7071        // Match 15-30 "a"'s against 15 and a "b".
7072        const char* c_source =
7073            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
7074            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
7075        Local<String> source = String::New(c_source);
7076        Local<Script> script = Script::Compile(source);
7077        Local<Value> result = script->Run();
7078        if (!result->BooleanValue()) {
7079          gc_during_regexp_ = kRequiredGCs;
7080          return;
7081        }
7082      }
7083      int gc_after = gc_count_;
7084      gc_during_regexp_ += gc_after - gc_before;
7085      rounds++;
7086      i::OS::Sleep(1);
7087    }
7088    regexp_success_ = true;
7089  }
7090
7091  i::Semaphore* block_;
7092  int gc_count_;
7093  int gc_during_regexp_;
7094  bool regexp_success_;
7095  bool gc_success_;
7096};
7097
7098
7099// Test that a regular expression execution can be interrupted and
7100// survive a garbage collection.
7101TEST(RegExpInterruption) {
7102  v8::Locker lock;
7103  v8::V8::Initialize();
7104  v8::HandleScope scope;
7105  Local<Context> local_env;
7106  {
7107    LocalContext env;
7108    local_env = env.local();
7109  }
7110
7111  // Local context should still be live.
7112  CHECK(!local_env.IsEmpty());
7113  local_env->Enter();
7114
7115  // Should complete without problems.
7116  RegExpInterruptTest().RunTest();
7117
7118  local_env->Exit();
7119}
7120
7121
7122class ApplyInterruptTest {
7123 public:
7124  ApplyInterruptTest() : block_(NULL) {}
7125  ~ApplyInterruptTest() { delete block_; }
7126  void RunTest() {
7127    block_ = i::OS::CreateSemaphore(0);
7128    gc_count_ = 0;
7129    gc_during_apply_ = 0;
7130    apply_success_ = false;
7131    gc_success_ = false;
7132    GCThread gc_thread(this);
7133    gc_thread.Start();
7134    v8::Locker::StartPreemption(1);
7135
7136    LongRunningApply();
7137    {
7138      v8::Unlocker unlock;
7139      gc_thread.Join();
7140    }
7141    v8::Locker::StopPreemption();
7142    CHECK(apply_success_);
7143    CHECK(gc_success_);
7144  }
7145 private:
7146  // Number of garbage collections required.
7147  static const int kRequiredGCs = 2;
7148
7149  class GCThread : public i::Thread {
7150   public:
7151    explicit GCThread(ApplyInterruptTest* test)
7152        : test_(test) {}
7153    virtual void Run() {
7154      test_->CollectGarbage();
7155    }
7156   private:
7157     ApplyInterruptTest* test_;
7158  };
7159
7160  void CollectGarbage() {
7161    block_->Wait();
7162    while (gc_during_apply_ < kRequiredGCs) {
7163      {
7164        v8::Locker lock;
7165        i::Heap::CollectAllGarbage(false);
7166        gc_count_++;
7167      }
7168      i::OS::Sleep(1);
7169    }
7170    gc_success_ = true;
7171  }
7172
7173  void LongRunningApply() {
7174    block_->Signal();
7175    int rounds = 0;
7176    while (gc_during_apply_ < kRequiredGCs) {
7177      int gc_before = gc_count_;
7178      {
7179        const char* c_source =
7180            "function do_very_little(bar) {"
7181            "  this.foo = bar;"
7182            "}"
7183            "for (var i = 0; i < 100000; i++) {"
7184            "  do_very_little.apply(this, ['bar']);"
7185            "}";
7186        Local<String> source = String::New(c_source);
7187        Local<Script> script = Script::Compile(source);
7188        Local<Value> result = script->Run();
7189        // Check that no exception was thrown.
7190        CHECK(!result.IsEmpty());
7191      }
7192      int gc_after = gc_count_;
7193      gc_during_apply_ += gc_after - gc_before;
7194      rounds++;
7195    }
7196    apply_success_ = true;
7197  }
7198
7199  i::Semaphore* block_;
7200  int gc_count_;
7201  int gc_during_apply_;
7202  bool apply_success_;
7203  bool gc_success_;
7204};
7205
7206
7207// Test that nothing bad happens if we get a preemption just when we were
7208// about to do an apply().
7209TEST(ApplyInterruption) {
7210  v8::Locker lock;
7211  v8::V8::Initialize();
7212  v8::HandleScope scope;
7213  Local<Context> local_env;
7214  {
7215    LocalContext env;
7216    local_env = env.local();
7217  }
7218
7219  // Local context should still be live.
7220  CHECK(!local_env.IsEmpty());
7221  local_env->Enter();
7222
7223  // Should complete without problems.
7224  ApplyInterruptTest().RunTest();
7225
7226  local_env->Exit();
7227}
7228
7229
7230// Verify that we can clone an object
7231TEST(ObjectClone) {
7232  v8::HandleScope scope;
7233  LocalContext env;
7234
7235  const char* sample =
7236    "var rv = {};"      \
7237    "rv.alpha = 'hello';" \
7238    "rv.beta = 123;"     \
7239    "rv;";
7240
7241  // Create an object, verify basics.
7242  Local<Value> val = CompileRun(sample);
7243  CHECK(val->IsObject());
7244  Local<v8::Object> obj = Local<v8::Object>::Cast(val);
7245  obj->Set(v8_str("gamma"), v8_str("cloneme"));
7246
7247  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
7248  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
7249  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
7250
7251  // Clone it.
7252  Local<v8::Object> clone = obj->Clone();
7253  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
7254  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
7255  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
7256
7257  // Set a property on the clone, verify each object.
7258  clone->Set(v8_str("beta"), v8::Integer::New(456));
7259  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
7260  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
7261}
7262
7263
7264class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
7265 public:
7266  explicit AsciiVectorResource(i::Vector<const char> vector)
7267      : data_(vector) {}
7268  virtual ~AsciiVectorResource() {}
7269  virtual size_t length() const { return data_.length(); }
7270  virtual const char* data() const { return data_.start(); }
7271 private:
7272  i::Vector<const char> data_;
7273};
7274
7275
7276class UC16VectorResource : public v8::String::ExternalStringResource {
7277 public:
7278  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
7279      : data_(vector) {}
7280  virtual ~UC16VectorResource() {}
7281  virtual size_t length() const { return data_.length(); }
7282  virtual const i::uc16* data() const { return data_.start(); }
7283 private:
7284  i::Vector<const i::uc16> data_;
7285};
7286
7287
7288static void MorphAString(i::String* string,
7289                         AsciiVectorResource* ascii_resource,
7290                         UC16VectorResource* uc16_resource) {
7291  CHECK(i::StringShape(string).IsExternal());
7292  if (string->IsAsciiRepresentation()) {
7293    // Check old map is not symbol or long.
7294    CHECK(string->map() == i::Heap::external_ascii_string_map());
7295    // Morph external string to be TwoByte string.
7296    string->set_map(i::Heap::external_string_map());
7297    i::ExternalTwoByteString* morphed =
7298         i::ExternalTwoByteString::cast(string);
7299    morphed->set_resource(uc16_resource);
7300  } else {
7301    // Check old map is not symbol or long.
7302    CHECK(string->map() == i::Heap::external_string_map());
7303    // Morph external string to be ASCII string.
7304    string->set_map(i::Heap::external_ascii_string_map());
7305    i::ExternalAsciiString* morphed =
7306         i::ExternalAsciiString::cast(string);
7307    morphed->set_resource(ascii_resource);
7308  }
7309}
7310
7311
7312// Test that we can still flatten a string if the components it is built up
7313// from have been turned into 16 bit strings in the mean time.
7314THREADED_TEST(MorphCompositeStringTest) {
7315  const char* c_string = "Now is the time for all good men"
7316                         " to come to the aid of the party";
7317  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
7318  {
7319    v8::HandleScope scope;
7320    LocalContext env;
7321    AsciiVectorResource ascii_resource(
7322        i::Vector<const char>(c_string, i::StrLength(c_string)));
7323    UC16VectorResource uc16_resource(
7324        i::Vector<const uint16_t>(two_byte_string,
7325                                  i::StrLength(c_string)));
7326
7327    Local<String> lhs(v8::Utils::ToLocal(
7328        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
7329    Local<String> rhs(v8::Utils::ToLocal(
7330        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
7331
7332    env->Global()->Set(v8_str("lhs"), lhs);
7333    env->Global()->Set(v8_str("rhs"), rhs);
7334
7335    CompileRun(
7336        "var cons = lhs + rhs;"
7337        "var slice = lhs.substring(1, lhs.length - 1);"
7338        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
7339
7340    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
7341    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
7342
7343    // Now do some stuff to make sure the strings are flattened, etc.
7344    CompileRun(
7345        "/[^a-z]/.test(cons);"
7346        "/[^a-z]/.test(slice);"
7347        "/[^a-z]/.test(slice_on_cons);");
7348    const char* expected_cons =
7349        "Now is the time for all good men to come to the aid of the party"
7350        "Now is the time for all good men to come to the aid of the party";
7351    const char* expected_slice =
7352        "ow is the time for all good men to come to the aid of the part";
7353    const char* expected_slice_on_cons =
7354        "ow is the time for all good men to come to the aid of the party"
7355        "Now is the time for all good men to come to the aid of the part";
7356    CHECK_EQ(String::New(expected_cons),
7357             env->Global()->Get(v8_str("cons")));
7358    CHECK_EQ(String::New(expected_slice),
7359             env->Global()->Get(v8_str("slice")));
7360    CHECK_EQ(String::New(expected_slice_on_cons),
7361             env->Global()->Get(v8_str("slice_on_cons")));
7362  }
7363}
7364
7365
7366TEST(CompileExternalTwoByteSource) {
7367  v8::HandleScope scope;
7368  LocalContext context;
7369
7370  // This is a very short list of sources, which currently is to check for a
7371  // regression caused by r2703.
7372  const char* ascii_sources[] = {
7373    "0.5",
7374    "-0.5",   // This mainly testes PushBack in the Scanner.
7375    "--0.5",  // This mainly testes PushBack in the Scanner.
7376    NULL
7377  };
7378
7379  // Compile the sources as external two byte strings.
7380  for (int i = 0; ascii_sources[i] != NULL; i++) {
7381    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
7382    UC16VectorResource uc16_resource(
7383        i::Vector<const uint16_t>(two_byte_string,
7384                                  i::StrLength(ascii_sources[i])));
7385    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
7386    v8::Script::Compile(source);
7387  }
7388}
7389
7390
7391class RegExpStringModificationTest {
7392 public:
7393  RegExpStringModificationTest()
7394      : block_(i::OS::CreateSemaphore(0)),
7395        morphs_(0),
7396        morphs_during_regexp_(0),
7397        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
7398        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
7399  ~RegExpStringModificationTest() { delete block_; }
7400  void RunTest() {
7401    regexp_success_ = false;
7402    morph_success_ = false;
7403
7404    // Initialize the contents of two_byte_content_ to be a uc16 representation
7405    // of "aaaaaaaaaaaaaab".
7406    for (int i = 0; i < 14; i++) {
7407      two_byte_content_[i] = 'a';
7408    }
7409    two_byte_content_[14] = 'b';
7410
7411    // Create the input string for the regexp - the one we are going to change
7412    // properties of.
7413    input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
7414
7415    // Inject the input as a global variable.
7416    i::Handle<i::String> input_name =
7417        i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
7418    i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
7419
7420
7421    MorphThread morph_thread(this);
7422    morph_thread.Start();
7423    v8::Locker::StartPreemption(1);
7424    LongRunningRegExp();
7425    {
7426      v8::Unlocker unlock;
7427      morph_thread.Join();
7428    }
7429    v8::Locker::StopPreemption();
7430    CHECK(regexp_success_);
7431    CHECK(morph_success_);
7432  }
7433 private:
7434
7435  // Number of string modifications required.
7436  static const int kRequiredModifications = 5;
7437  static const int kMaxModifications = 100;
7438
7439  class MorphThread : public i::Thread {
7440   public:
7441    explicit MorphThread(RegExpStringModificationTest* test)
7442        : test_(test) {}
7443    virtual void Run() {
7444      test_->MorphString();
7445    }
7446   private:
7447     RegExpStringModificationTest* test_;
7448  };
7449
7450  void MorphString() {
7451    block_->Wait();
7452    while (morphs_during_regexp_ < kRequiredModifications &&
7453           morphs_ < kMaxModifications) {
7454      {
7455        v8::Locker lock;
7456        // Swap string between ascii and two-byte representation.
7457        i::String* string = *input_;
7458        MorphAString(string, &ascii_resource_, &uc16_resource_);
7459        morphs_++;
7460      }
7461      i::OS::Sleep(1);
7462    }
7463    morph_success_ = true;
7464  }
7465
7466  void LongRunningRegExp() {
7467    block_->Signal();  // Enable morphing thread on next preemption.
7468    while (morphs_during_regexp_ < kRequiredModifications &&
7469           morphs_ < kMaxModifications) {
7470      int morphs_before = morphs_;
7471      {
7472        // Match 15-30 "a"'s against 14 and a "b".
7473        const char* c_source =
7474            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
7475            ".exec(input) === null";
7476        Local<String> source = String::New(c_source);
7477        Local<Script> script = Script::Compile(source);
7478        Local<Value> result = script->Run();
7479        CHECK(result->IsTrue());
7480      }
7481      int morphs_after = morphs_;
7482      morphs_during_regexp_ += morphs_after - morphs_before;
7483    }
7484    regexp_success_ = true;
7485  }
7486
7487  i::uc16 two_byte_content_[15];
7488  i::Semaphore* block_;
7489  int morphs_;
7490  int morphs_during_regexp_;
7491  bool regexp_success_;
7492  bool morph_success_;
7493  i::Handle<i::String> input_;
7494  AsciiVectorResource ascii_resource_;
7495  UC16VectorResource uc16_resource_;
7496};
7497
7498
7499// Test that a regular expression execution can be interrupted and
7500// the string changed without failing.
7501TEST(RegExpStringModification) {
7502  v8::Locker lock;
7503  v8::V8::Initialize();
7504  v8::HandleScope scope;
7505  Local<Context> local_env;
7506  {
7507    LocalContext env;
7508    local_env = env.local();
7509  }
7510
7511  // Local context should still be live.
7512  CHECK(!local_env.IsEmpty());
7513  local_env->Enter();
7514
7515  // Should complete without problems.
7516  RegExpStringModificationTest().RunTest();
7517
7518  local_env->Exit();
7519}
7520
7521
7522// Test that we can set a property on the global object even if there
7523// is a read-only property in the prototype chain.
7524TEST(ReadOnlyPropertyInGlobalProto) {
7525  v8::HandleScope scope;
7526  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7527  LocalContext context(0, templ);
7528  v8::Handle<v8::Object> global = context->Global();
7529  v8::Handle<v8::Object> global_proto =
7530      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
7531  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
7532  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
7533  // Check without 'eval' or 'with'.
7534  v8::Handle<v8::Value> res =
7535      CompileRun("function f() { x = 42; return x; }; f()");
7536  // Check with 'eval'.
7537  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
7538  CHECK_EQ(v8::Integer::New(42), res);
7539  // Check with 'with'.
7540  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
7541  CHECK_EQ(v8::Integer::New(42), res);
7542}
7543
7544static int force_set_set_count = 0;
7545static int force_set_get_count = 0;
7546bool pass_on_get = false;
7547
7548static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
7549                                            const v8::AccessorInfo& info) {
7550  force_set_get_count++;
7551  if (pass_on_get) {
7552    return v8::Handle<v8::Value>();
7553  } else {
7554    return v8::Int32::New(3);
7555  }
7556}
7557
7558static void ForceSetSetter(v8::Local<v8::String> name,
7559                           v8::Local<v8::Value> value,
7560                           const v8::AccessorInfo& info) {
7561  force_set_set_count++;
7562}
7563
7564static v8::Handle<v8::Value> ForceSetInterceptSetter(
7565    v8::Local<v8::String> name,
7566    v8::Local<v8::Value> value,
7567    const v8::AccessorInfo& info) {
7568  force_set_set_count++;
7569  return v8::Undefined();
7570}
7571
7572TEST(ForceSet) {
7573  force_set_get_count = 0;
7574  force_set_set_count = 0;
7575  pass_on_get = false;
7576
7577  v8::HandleScope scope;
7578  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7579  v8::Handle<v8::String> access_property = v8::String::New("a");
7580  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
7581  LocalContext context(NULL, templ);
7582  v8::Handle<v8::Object> global = context->Global();
7583
7584  // Ordinary properties
7585  v8::Handle<v8::String> simple_property = v8::String::New("p");
7586  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
7587  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7588  // This should fail because the property is read-only
7589  global->Set(simple_property, v8::Int32::New(5));
7590  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7591  // This should succeed even though the property is read-only
7592  global->ForceSet(simple_property, v8::Int32::New(6));
7593  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
7594
7595  // Accessors
7596  CHECK_EQ(0, force_set_set_count);
7597  CHECK_EQ(0, force_set_get_count);
7598  CHECK_EQ(3, global->Get(access_property)->Int32Value());
7599  // CHECK_EQ the property shouldn't override it, just call the setter
7600  // which in this case does nothing.
7601  global->Set(access_property, v8::Int32::New(7));
7602  CHECK_EQ(3, global->Get(access_property)->Int32Value());
7603  CHECK_EQ(1, force_set_set_count);
7604  CHECK_EQ(2, force_set_get_count);
7605  // Forcing the property to be set should override the accessor without
7606  // calling it
7607  global->ForceSet(access_property, v8::Int32::New(8));
7608  CHECK_EQ(8, global->Get(access_property)->Int32Value());
7609  CHECK_EQ(1, force_set_set_count);
7610  CHECK_EQ(2, force_set_get_count);
7611}
7612
7613TEST(ForceSetWithInterceptor) {
7614  force_set_get_count = 0;
7615  force_set_set_count = 0;
7616  pass_on_get = false;
7617
7618  v8::HandleScope scope;
7619  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7620  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
7621  LocalContext context(NULL, templ);
7622  v8::Handle<v8::Object> global = context->Global();
7623
7624  v8::Handle<v8::String> some_property = v8::String::New("a");
7625  CHECK_EQ(0, force_set_set_count);
7626  CHECK_EQ(0, force_set_get_count);
7627  CHECK_EQ(3, global->Get(some_property)->Int32Value());
7628  // Setting the property shouldn't override it, just call the setter
7629  // which in this case does nothing.
7630  global->Set(some_property, v8::Int32::New(7));
7631  CHECK_EQ(3, global->Get(some_property)->Int32Value());
7632  CHECK_EQ(1, force_set_set_count);
7633  CHECK_EQ(2, force_set_get_count);
7634  // Getting the property when the interceptor returns an empty handle
7635  // should yield undefined, since the property isn't present on the
7636  // object itself yet.
7637  pass_on_get = true;
7638  CHECK(global->Get(some_property)->IsUndefined());
7639  CHECK_EQ(1, force_set_set_count);
7640  CHECK_EQ(3, force_set_get_count);
7641  // Forcing the property to be set should cause the value to be
7642  // set locally without calling the interceptor.
7643  global->ForceSet(some_property, v8::Int32::New(8));
7644  CHECK_EQ(8, global->Get(some_property)->Int32Value());
7645  CHECK_EQ(1, force_set_set_count);
7646  CHECK_EQ(4, force_set_get_count);
7647  // Reenabling the interceptor should cause it to take precedence over
7648  // the property
7649  pass_on_get = false;
7650  CHECK_EQ(3, global->Get(some_property)->Int32Value());
7651  CHECK_EQ(1, force_set_set_count);
7652  CHECK_EQ(5, force_set_get_count);
7653  // The interceptor should also work for other properties
7654  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
7655  CHECK_EQ(1, force_set_set_count);
7656  CHECK_EQ(6, force_set_get_count);
7657}
7658
7659
7660THREADED_TEST(ForceDelete) {
7661  v8::HandleScope scope;
7662  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7663  LocalContext context(NULL, templ);
7664  v8::Handle<v8::Object> global = context->Global();
7665
7666  // Ordinary properties
7667  v8::Handle<v8::String> simple_property = v8::String::New("p");
7668  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
7669  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7670  // This should fail because the property is dont-delete.
7671  CHECK(!global->Delete(simple_property));
7672  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7673  // This should succeed even though the property is dont-delete.
7674  CHECK(global->ForceDelete(simple_property));
7675  CHECK(global->Get(simple_property)->IsUndefined());
7676}
7677
7678
7679static int force_delete_interceptor_count = 0;
7680static bool pass_on_delete = false;
7681
7682
7683static v8::Handle<v8::Boolean> ForceDeleteDeleter(
7684    v8::Local<v8::String> name,
7685    const v8::AccessorInfo& info) {
7686  force_delete_interceptor_count++;
7687  if (pass_on_delete) {
7688    return v8::Handle<v8::Boolean>();
7689  } else {
7690    return v8::True();
7691  }
7692}
7693
7694
7695THREADED_TEST(ForceDeleteWithInterceptor) {
7696  force_delete_interceptor_count = 0;
7697  pass_on_delete = false;
7698
7699  v8::HandleScope scope;
7700  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7701  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
7702  LocalContext context(NULL, templ);
7703  v8::Handle<v8::Object> global = context->Global();
7704
7705  v8::Handle<v8::String> some_property = v8::String::New("a");
7706  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
7707
7708  // Deleting a property should get intercepted and nothing should
7709  // happen.
7710  CHECK_EQ(0, force_delete_interceptor_count);
7711  CHECK(global->Delete(some_property));
7712  CHECK_EQ(1, force_delete_interceptor_count);
7713  CHECK_EQ(42, global->Get(some_property)->Int32Value());
7714  // Deleting the property when the interceptor returns an empty
7715  // handle should not delete the property since it is DontDelete.
7716  pass_on_delete = true;
7717  CHECK(!global->Delete(some_property));
7718  CHECK_EQ(2, force_delete_interceptor_count);
7719  CHECK_EQ(42, global->Get(some_property)->Int32Value());
7720  // Forcing the property to be deleted should delete the value
7721  // without calling the interceptor.
7722  CHECK(global->ForceDelete(some_property));
7723  CHECK(global->Get(some_property)->IsUndefined());
7724  CHECK_EQ(2, force_delete_interceptor_count);
7725}
7726
7727
7728// Make sure that forcing a delete invalidates any IC stubs, so we
7729// don't read the hole value.
7730THREADED_TEST(ForceDeleteIC) {
7731  v8::HandleScope scope;
7732  LocalContext context;
7733  // Create a DontDelete variable on the global object.
7734  CompileRun("this.__proto__ = { foo: 'horse' };"
7735             "var foo = 'fish';"
7736             "function f() { return foo.length; }");
7737  // Initialize the IC for foo in f.
7738  CompileRun("for (var i = 0; i < 4; i++) f();");
7739  // Make sure the value of foo is correct before the deletion.
7740  CHECK_EQ(4, CompileRun("f()")->Int32Value());
7741  // Force the deletion of foo.
7742  CHECK(context->Global()->ForceDelete(v8_str("foo")));
7743  // Make sure the value for foo is read from the prototype, and that
7744  // we don't get in trouble with reading the deleted cell value
7745  // sentinel.
7746  CHECK_EQ(5, CompileRun("f()")->Int32Value());
7747}
7748
7749
7750v8::Persistent<Context> calling_context0;
7751v8::Persistent<Context> calling_context1;
7752v8::Persistent<Context> calling_context2;
7753
7754
7755// Check that the call to the callback is initiated in
7756// calling_context2, the directly calling context is calling_context1
7757// and the callback itself is in calling_context0.
7758static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
7759  ApiTestFuzzer::Fuzz();
7760  CHECK(Context::GetCurrent() == calling_context0);
7761  CHECK(Context::GetCalling() == calling_context1);
7762  CHECK(Context::GetEntered() == calling_context2);
7763  return v8::Integer::New(42);
7764}
7765
7766
7767THREADED_TEST(GetCallingContext) {
7768  v8::HandleScope scope;
7769
7770  calling_context0 = Context::New();
7771  calling_context1 = Context::New();
7772  calling_context2 = Context::New();
7773
7774  // Allow cross-domain access.
7775  Local<String> token = v8_str("<security token>");
7776  calling_context0->SetSecurityToken(token);
7777  calling_context1->SetSecurityToken(token);
7778  calling_context2->SetSecurityToken(token);
7779
7780  // Create an object with a C++ callback in context0.
7781  calling_context0->Enter();
7782  Local<v8::FunctionTemplate> callback_templ =
7783      v8::FunctionTemplate::New(GetCallingContextCallback);
7784  calling_context0->Global()->Set(v8_str("callback"),
7785                                  callback_templ->GetFunction());
7786  calling_context0->Exit();
7787
7788  // Expose context0 in context1 and setup a function that calls the
7789  // callback function.
7790  calling_context1->Enter();
7791  calling_context1->Global()->Set(v8_str("context0"),
7792                                  calling_context0->Global());
7793  CompileRun("function f() { context0.callback() }");
7794  calling_context1->Exit();
7795
7796  // Expose context1 in context2 and call the callback function in
7797  // context0 indirectly through f in context1.
7798  calling_context2->Enter();
7799  calling_context2->Global()->Set(v8_str("context1"),
7800                                  calling_context1->Global());
7801  CompileRun("context1.f()");
7802  calling_context2->Exit();
7803
7804  // Dispose the contexts to allow them to be garbage collected.
7805  calling_context0.Dispose();
7806  calling_context1.Dispose();
7807  calling_context2.Dispose();
7808  calling_context0.Clear();
7809  calling_context1.Clear();
7810  calling_context2.Clear();
7811}
7812
7813
7814// Check that a variable declaration with no explicit initialization
7815// value does not shadow an existing property in the prototype chain.
7816//
7817// This is consistent with Firefox and Safari.
7818//
7819// See http://crbug.com/12548.
7820THREADED_TEST(InitGlobalVarInProtoChain) {
7821  v8::HandleScope scope;
7822  LocalContext context;
7823  // Introduce a variable in the prototype chain.
7824  CompileRun("__proto__.x = 42");
7825  v8::Handle<v8::Value> result = CompileRun("var x; x");
7826  CHECK(!result->IsUndefined());
7827  CHECK_EQ(42, result->Int32Value());
7828}
7829
7830
7831// Regression test for issue 398.
7832// If a function is added to an object, creating a constant function
7833// field, and the result is cloned, replacing the constant function on the
7834// original should not affect the clone.
7835// See http://code.google.com/p/v8/issues/detail?id=398
7836THREADED_TEST(ReplaceConstantFunction) {
7837  v8::HandleScope scope;
7838  LocalContext context;
7839  v8::Handle<v8::Object> obj = v8::Object::New();
7840  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
7841  v8::Handle<v8::String> foo_string = v8::String::New("foo");
7842  obj->Set(foo_string, func_templ->GetFunction());
7843  v8::Handle<v8::Object> obj_clone = obj->Clone();
7844  obj_clone->Set(foo_string, v8::String::New("Hello"));
7845  CHECK(!obj->Get(foo_string)->IsUndefined());
7846}
7847
7848
7849// Regression test for http://crbug.com/16276.
7850THREADED_TEST(Regress16276) {
7851  v8::HandleScope scope;
7852  LocalContext context;
7853  // Force the IC in f to be a dictionary load IC.
7854  CompileRun("function f(obj) { return obj.x; }\n"
7855             "var obj = { x: { foo: 42 }, y: 87 };\n"
7856             "var x = obj.x;\n"
7857             "delete obj.y;\n"
7858             "for (var i = 0; i < 5; i++) f(obj);");
7859  // Detach the global object to make 'this' refer directly to the
7860  // global object (not the proxy), and make sure that the dictionary
7861  // load IC doesn't mess up loading directly from the global object.
7862  context->DetachGlobal();
7863  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
7864}
7865
7866
7867THREADED_TEST(PixelArray) {
7868  v8::HandleScope scope;
7869  LocalContext context;
7870  const int kElementCount = 260;
7871  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
7872  i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
7873                                                              pixel_data);
7874  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
7875  for (int i = 0; i < kElementCount; i++) {
7876    pixels->set(i, i % 256);
7877  }
7878  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
7879  for (int i = 0; i < kElementCount; i++) {
7880    CHECK_EQ(i % 256, pixels->get(i));
7881    CHECK_EQ(i % 256, pixel_data[i]);
7882  }
7883
7884  v8::Handle<v8::Object> obj = v8::Object::New();
7885  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
7886  // Set the elements to be the pixels.
7887  // jsobj->set_elements(*pixels);
7888  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
7889  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
7890  obj->Set(v8_str("field"), v8::Int32::New(1503));
7891  context->Global()->Set(v8_str("pixels"), obj);
7892  v8::Handle<v8::Value> result = CompileRun("pixels.field");
7893  CHECK_EQ(1503, result->Int32Value());
7894  result = CompileRun("pixels[1]");
7895  CHECK_EQ(1, result->Int32Value());
7896
7897  result = CompileRun("var sum = 0;"
7898                      "for (var i = 0; i < 8; i++) {"
7899                      "  sum += pixels[i] = pixels[i] = -i;"
7900                      "}"
7901                      "sum;");
7902  CHECK_EQ(-28, result->Int32Value());
7903
7904  result = CompileRun("var sum = 0;"
7905                      "for (var i = 0; i < 8; i++) {"
7906                      "  sum += pixels[i] = pixels[i] = 0;"
7907                      "}"
7908                      "sum;");
7909  CHECK_EQ(0, result->Int32Value());
7910
7911  result = CompileRun("var sum = 0;"
7912                      "for (var i = 0; i < 8; i++) {"
7913                      "  sum += pixels[i] = pixels[i] = 255;"
7914                      "}"
7915                      "sum;");
7916  CHECK_EQ(8 * 255, result->Int32Value());
7917
7918  result = CompileRun("var sum = 0;"
7919                      "for (var i = 0; i < 8; i++) {"
7920                      "  sum += pixels[i] = pixels[i] = 256 + i;"
7921                      "}"
7922                      "sum;");
7923  CHECK_EQ(2076, result->Int32Value());
7924
7925  result = CompileRun("var sum = 0;"
7926                      "for (var i = 0; i < 8; i++) {"
7927                      "  sum += pixels[i] = pixels[i] = i;"
7928                      "}"
7929                      "sum;");
7930  CHECK_EQ(28, result->Int32Value());
7931
7932  result = CompileRun("var sum = 0;"
7933                      "for (var i = 0; i < 8; i++) {"
7934                      "  sum += pixels[i];"
7935                      "}"
7936                      "sum;");
7937  CHECK_EQ(28, result->Int32Value());
7938
7939  i::Handle<i::Smi> value(i::Smi::FromInt(2));
7940  i::SetElement(jsobj, 1, value);
7941  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
7942  *value.location() = i::Smi::FromInt(256);
7943  i::SetElement(jsobj, 1, value);
7944  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
7945  *value.location() = i::Smi::FromInt(-1);
7946  i::SetElement(jsobj, 1, value);
7947  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
7948
7949  result = CompileRun("for (var i = 0; i < 8; i++) {"
7950                      "  pixels[i] = (i * 65) - 109;"
7951                      "}"
7952                      "pixels[1] + pixels[6];");
7953  CHECK_EQ(255, result->Int32Value());
7954  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
7955  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
7956  CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
7957  CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
7958  CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
7959  CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
7960  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
7961  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
7962  result = CompileRun("var sum = 0;"
7963                      "for (var i = 0; i < 8; i++) {"
7964                      "  sum += pixels[i];"
7965                      "}"
7966                      "sum;");
7967  CHECK_EQ(984, result->Int32Value());
7968
7969  result = CompileRun("for (var i = 0; i < 8; i++) {"
7970                      "  pixels[i] = (i * 1.1);"
7971                      "}"
7972                      "pixels[1] + pixels[6];");
7973  CHECK_EQ(8, result->Int32Value());
7974  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
7975  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
7976  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
7977  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
7978  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
7979  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
7980  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
7981  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
7982
7983  result = CompileRun("for (var i = 0; i < 8; i++) {"
7984                      "  pixels[7] = undefined;"
7985                      "}"
7986                      "pixels[7];");
7987  CHECK_EQ(0, result->Int32Value());
7988  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
7989
7990  result = CompileRun("for (var i = 0; i < 8; i++) {"
7991                      "  pixels[6] = '2.3';"
7992                      "}"
7993                      "pixels[6];");
7994  CHECK_EQ(2, result->Int32Value());
7995  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
7996
7997  result = CompileRun("for (var i = 0; i < 8; i++) {"
7998                      "  pixels[5] = NaN;"
7999                      "}"
8000                      "pixels[5];");
8001  CHECK_EQ(0, result->Int32Value());
8002  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
8003
8004  result = CompileRun("for (var i = 0; i < 8; i++) {"
8005                      "  pixels[8] = Infinity;"
8006                      "}"
8007                      "pixels[8];");
8008  CHECK_EQ(255, result->Int32Value());
8009  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
8010
8011  result = CompileRun("for (var i = 0; i < 8; i++) {"
8012                      "  pixels[9] = -Infinity;"
8013                      "}"
8014                      "pixels[9];");
8015  CHECK_EQ(0, result->Int32Value());
8016  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
8017
8018  result = CompileRun("pixels[3] = 33;"
8019                      "delete pixels[3];"
8020                      "pixels[3];");
8021  CHECK_EQ(33, result->Int32Value());
8022
8023  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
8024                      "pixels[2] = 12; pixels[3] = 13;"
8025                      "pixels.__defineGetter__('2',"
8026                      "function() { return 120; });"
8027                      "pixels[2];");
8028  CHECK_EQ(12, result->Int32Value());
8029
8030  result = CompileRun("var js_array = new Array(40);"
8031                      "js_array[0] = 77;"
8032                      "js_array;");
8033  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
8034
8035  result = CompileRun("pixels[1] = 23;"
8036                      "pixels.__proto__ = [];"
8037                      "js_array.__proto__ = pixels;"
8038                      "js_array.concat(pixels);");
8039  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
8040  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
8041
8042  result = CompileRun("pixels[1] = 23;");
8043  CHECK_EQ(23, result->Int32Value());
8044
8045  // Test for index greater than 255.  Regression test for:
8046  // http://code.google.com/p/chromium/issues/detail?id=26337.
8047  result = CompileRun("pixels[256] = 255;");
8048  CHECK_EQ(255, result->Int32Value());
8049  result = CompileRun("var i = 0;"
8050                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
8051                      "i");
8052  CHECK_EQ(255, result->Int32Value());
8053
8054  free(pixel_data);
8055}
8056
8057
8058template <class ExternalArrayClass, class ElementType>
8059static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
8060                                    int64_t low,
8061                                    int64_t high) {
8062  v8::HandleScope scope;
8063  LocalContext context;
8064  const int kElementCount = 40;
8065  int element_size = 0;
8066  switch (array_type) {
8067    case v8::kExternalByteArray:
8068    case v8::kExternalUnsignedByteArray:
8069      element_size = 1;
8070      break;
8071    case v8::kExternalShortArray:
8072    case v8::kExternalUnsignedShortArray:
8073      element_size = 2;
8074      break;
8075    case v8::kExternalIntArray:
8076    case v8::kExternalUnsignedIntArray:
8077    case v8::kExternalFloatArray:
8078      element_size = 4;
8079      break;
8080    default:
8081      UNREACHABLE();
8082      break;
8083  }
8084  ElementType* array_data =
8085      static_cast<ElementType*>(malloc(kElementCount * element_size));
8086  i::Handle<ExternalArrayClass> array =
8087      i::Handle<ExternalArrayClass>::cast(
8088          i::Factory::NewExternalArray(kElementCount, array_type, array_data));
8089  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
8090  for (int i = 0; i < kElementCount; i++) {
8091    array->set(i, static_cast<ElementType>(i));
8092  }
8093  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
8094  for (int i = 0; i < kElementCount; i++) {
8095    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
8096    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
8097  }
8098
8099  v8::Handle<v8::Object> obj = v8::Object::New();
8100  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
8101  // Set the elements to be the external array.
8102  obj->SetIndexedPropertiesToExternalArrayData(array_data,
8103                                               array_type,
8104                                               kElementCount);
8105  CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
8106  obj->Set(v8_str("field"), v8::Int32::New(1503));
8107  context->Global()->Set(v8_str("ext_array"), obj);
8108  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
8109  CHECK_EQ(1503, result->Int32Value());
8110  result = CompileRun("ext_array[1]");
8111  CHECK_EQ(1, result->Int32Value());
8112
8113  // Check pass through of assigned smis
8114  result = CompileRun("var sum = 0;"
8115                      "for (var i = 0; i < 8; i++) {"
8116                      "  sum += ext_array[i] = ext_array[i] = -i;"
8117                      "}"
8118                      "sum;");
8119  CHECK_EQ(-28, result->Int32Value());
8120
8121  // Check assigned smis
8122  result = CompileRun("for (var i = 0; i < 8; i++) {"
8123                      "  ext_array[i] = i;"
8124                      "}"
8125                      "var sum = 0;"
8126                      "for (var i = 0; i < 8; i++) {"
8127                      "  sum += ext_array[i];"
8128                      "}"
8129                      "sum;");
8130  CHECK_EQ(28, result->Int32Value());
8131
8132  // Check assigned smis in reverse order
8133  result = CompileRun("for (var i = 8; --i >= 0; ) {"
8134                      "  ext_array[i] = i;"
8135                      "}"
8136                      "var sum = 0;"
8137                      "for (var i = 0; i < 8; i++) {"
8138                      "  sum += ext_array[i];"
8139                      "}"
8140                      "sum;");
8141  CHECK_EQ(28, result->Int32Value());
8142
8143  // Check pass through of assigned HeapNumbers
8144  result = CompileRun("var sum = 0;"
8145                      "for (var i = 0; i < 16; i+=2) {"
8146                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
8147                      "}"
8148                      "sum;");
8149  CHECK_EQ(-28, result->Int32Value());
8150
8151  // Check assigned HeapNumbers
8152  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
8153                      "  ext_array[i] = (i * 0.5);"
8154                      "}"
8155                      "var sum = 0;"
8156                      "for (var i = 0; i < 16; i+=2) {"
8157                      "  sum += ext_array[i];"
8158                      "}"
8159                      "sum;");
8160  CHECK_EQ(28, result->Int32Value());
8161
8162  // Check assigned HeapNumbers in reverse order
8163  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
8164                      "  ext_array[i] = (i * 0.5);"
8165                      "}"
8166                      "var sum = 0;"
8167                      "for (var i = 0; i < 16; i+=2) {"
8168                      "  sum += ext_array[i];"
8169                      "}"
8170                      "sum;");
8171  CHECK_EQ(28, result->Int32Value());
8172
8173  i::ScopedVector<char> test_buf(1024);
8174
8175  // Check legal boundary conditions.
8176  // The repeated loads and stores ensure the ICs are exercised.
8177  const char* boundary_program =
8178      "var res = 0;"
8179      "for (var i = 0; i < 16; i++) {"
8180      "  ext_array[i] = %lld;"
8181      "  if (i > 8) {"
8182      "    res = ext_array[i];"
8183      "  }"
8184      "}"
8185      "res;";
8186  i::OS::SNPrintF(test_buf,
8187                  boundary_program,
8188                  low);
8189  result = CompileRun(test_buf.start());
8190  CHECK_EQ(low, result->IntegerValue());
8191
8192  i::OS::SNPrintF(test_buf,
8193                  boundary_program,
8194                  high);
8195  result = CompileRun(test_buf.start());
8196  CHECK_EQ(high, result->IntegerValue());
8197
8198  // Check misprediction of type in IC.
8199  result = CompileRun("var tmp_array = ext_array;"
8200                      "var sum = 0;"
8201                      "for (var i = 0; i < 8; i++) {"
8202                      "  tmp_array[i] = i;"
8203                      "  sum += tmp_array[i];"
8204                      "  if (i == 4) {"
8205                      "    tmp_array = {};"
8206                      "  }"
8207                      "}"
8208                      "sum;");
8209  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
8210  CHECK_EQ(28, result->Int32Value());
8211
8212  // Make sure out-of-range loads do not throw.
8213  i::OS::SNPrintF(test_buf,
8214                  "var caught_exception = false;"
8215                  "try {"
8216                  "  ext_array[%d];"
8217                  "} catch (e) {"
8218                  "  caught_exception = true;"
8219                  "}"
8220                  "caught_exception;",
8221                  kElementCount);
8222  result = CompileRun(test_buf.start());
8223  CHECK_EQ(false, result->BooleanValue());
8224
8225  // Make sure out-of-range stores do not throw.
8226  i::OS::SNPrintF(test_buf,
8227                  "var caught_exception = false;"
8228                  "try {"
8229                  "  ext_array[%d] = 1;"
8230                  "} catch (e) {"
8231                  "  caught_exception = true;"
8232                  "}"
8233                  "caught_exception;",
8234                  kElementCount);
8235  result = CompileRun(test_buf.start());
8236  CHECK_EQ(false, result->BooleanValue());
8237
8238  // Check other boundary conditions, values and operations.
8239  result = CompileRun("for (var i = 0; i < 8; i++) {"
8240                      "  ext_array[7] = undefined;"
8241                      "}"
8242                      "ext_array[7];");
8243  CHECK_EQ(0, result->Int32Value());
8244  CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
8245
8246  result = CompileRun("for (var i = 0; i < 8; i++) {"
8247                      "  ext_array[6] = '2.3';"
8248                      "}"
8249                      "ext_array[6];");
8250  CHECK_EQ(2, result->Int32Value());
8251  CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
8252
8253  if (array_type != v8::kExternalFloatArray) {
8254    // Though the specification doesn't state it, be explicit about
8255    // converting NaNs and +/-Infinity to zero.
8256    result = CompileRun("for (var i = 0; i < 8; i++) {"
8257                        "  ext_array[i] = 5;"
8258                        "}"
8259                        "for (var i = 0; i < 8; i++) {"
8260                        "  ext_array[i] = NaN;"
8261                        "}"
8262                        "ext_array[5];");
8263    CHECK_EQ(0, result->Int32Value());
8264    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
8265
8266    result = CompileRun("for (var i = 0; i < 8; i++) {"
8267                        "  ext_array[i] = 5;"
8268                        "}"
8269                        "for (var i = 0; i < 8; i++) {"
8270                        "  ext_array[i] = Infinity;"
8271                        "}"
8272                        "ext_array[5];");
8273    CHECK_EQ(0, result->Int32Value());
8274    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
8275
8276    result = CompileRun("for (var i = 0; i < 8; i++) {"
8277                        "  ext_array[i] = 5;"
8278                        "}"
8279                        "for (var i = 0; i < 8; i++) {"
8280                        "  ext_array[i] = -Infinity;"
8281                        "}"
8282                        "ext_array[5];");
8283    CHECK_EQ(0, result->Int32Value());
8284    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
8285  }
8286
8287  result = CompileRun("ext_array[3] = 33;"
8288                      "delete ext_array[3];"
8289                      "ext_array[3];");
8290  CHECK_EQ(33, result->Int32Value());
8291
8292  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
8293                      "ext_array[2] = 12; ext_array[3] = 13;"
8294                      "ext_array.__defineGetter__('2',"
8295                      "function() { return 120; });"
8296                      "ext_array[2];");
8297  CHECK_EQ(12, result->Int32Value());
8298
8299  result = CompileRun("var js_array = new Array(40);"
8300                      "js_array[0] = 77;"
8301                      "js_array;");
8302  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
8303
8304  result = CompileRun("ext_array[1] = 23;"
8305                      "ext_array.__proto__ = [];"
8306                      "js_array.__proto__ = ext_array;"
8307                      "js_array.concat(ext_array);");
8308  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
8309  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
8310
8311  result = CompileRun("ext_array[1] = 23;");
8312  CHECK_EQ(23, result->Int32Value());
8313
8314  // Test more complex manipulations which cause eax to contain values
8315  // that won't be completely overwritten by loads from the arrays.
8316  // This catches bugs in the instructions used for the KeyedLoadIC
8317  // for byte and word types.
8318  {
8319    const int kXSize = 300;
8320    const int kYSize = 300;
8321    const int kLargeElementCount = kXSize * kYSize * 4;
8322    ElementType* large_array_data =
8323        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
8324    i::Handle<ExternalArrayClass> large_array =
8325        i::Handle<ExternalArrayClass>::cast(
8326            i::Factory::NewExternalArray(kLargeElementCount,
8327                                         array_type,
8328                                         array_data));
8329    v8::Handle<v8::Object> large_obj = v8::Object::New();
8330    // Set the elements to be the external array.
8331    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
8332                                                       array_type,
8333                                                       kLargeElementCount);
8334    context->Global()->Set(v8_str("large_array"), large_obj);
8335    // Initialize contents of a few rows.
8336    for (int x = 0; x < 300; x++) {
8337      int row = 0;
8338      int offset = row * 300 * 4;
8339      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
8340      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
8341      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
8342      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
8343      row = 150;
8344      offset = row * 300 * 4;
8345      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
8346      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
8347      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
8348      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
8349      row = 298;
8350      offset = row * 300 * 4;
8351      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
8352      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
8353      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
8354      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
8355    }
8356    // The goal of the code below is to make "offset" large enough
8357    // that the computation of the index (which goes into eax) has
8358    // high bits set which will not be overwritten by a byte or short
8359    // load.
8360    result = CompileRun("var failed = false;"
8361                        "var offset = 0;"
8362                        "for (var i = 0; i < 300; i++) {"
8363                        "  if (large_array[4 * i] != 127 ||"
8364                        "      large_array[4 * i + 1] != 0 ||"
8365                        "      large_array[4 * i + 2] != 0 ||"
8366                        "      large_array[4 * i + 3] != 127) {"
8367                        "    failed = true;"
8368                        "  }"
8369                        "}"
8370                        "offset = 150 * 300 * 4;"
8371                        "for (var i = 0; i < 300; i++) {"
8372                        "  if (large_array[offset + 4 * i] != 127 ||"
8373                        "      large_array[offset + 4 * i + 1] != 0 ||"
8374                        "      large_array[offset + 4 * i + 2] != 0 ||"
8375                        "      large_array[offset + 4 * i + 3] != 127) {"
8376                        "    failed = true;"
8377                        "  }"
8378                        "}"
8379                        "offset = 298 * 300 * 4;"
8380                        "for (var i = 0; i < 300; i++) {"
8381                        "  if (large_array[offset + 4 * i] != 127 ||"
8382                        "      large_array[offset + 4 * i + 1] != 0 ||"
8383                        "      large_array[offset + 4 * i + 2] != 0 ||"
8384                        "      large_array[offset + 4 * i + 3] != 127) {"
8385                        "    failed = true;"
8386                        "  }"
8387                        "}"
8388                        "!failed;");
8389    CHECK_EQ(true, result->BooleanValue());
8390    free(large_array_data);
8391  }
8392
8393  free(array_data);
8394}
8395
8396
8397THREADED_TEST(ExternalByteArray) {
8398  ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>(
8399      v8::kExternalByteArray,
8400      -128,
8401      127);
8402}
8403
8404
8405THREADED_TEST(ExternalUnsignedByteArray) {
8406  ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>(
8407      v8::kExternalUnsignedByteArray,
8408      0,
8409      255);
8410}
8411
8412
8413THREADED_TEST(ExternalShortArray) {
8414  ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>(
8415      v8::kExternalShortArray,
8416      -32768,
8417      32767);
8418}
8419
8420
8421THREADED_TEST(ExternalUnsignedShortArray) {
8422  ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>(
8423      v8::kExternalUnsignedShortArray,
8424      0,
8425      65535);
8426}
8427
8428
8429THREADED_TEST(ExternalIntArray) {
8430  ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>(
8431      v8::kExternalIntArray,
8432      INT_MIN,   // -2147483648
8433      INT_MAX);  //  2147483647
8434}
8435
8436
8437THREADED_TEST(ExternalUnsignedIntArray) {
8438  ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>(
8439      v8::kExternalUnsignedIntArray,
8440      0,
8441      UINT_MAX);  // 4294967295
8442}
8443
8444
8445THREADED_TEST(ExternalFloatArray) {
8446  ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>(
8447      v8::kExternalFloatArray,
8448      -500,
8449      500);
8450}
8451
8452
8453THREADED_TEST(ExternalArrays) {
8454  TestExternalByteArray();
8455  TestExternalUnsignedByteArray();
8456  TestExternalShortArray();
8457  TestExternalUnsignedShortArray();
8458  TestExternalIntArray();
8459  TestExternalUnsignedIntArray();
8460  TestExternalFloatArray();
8461}
8462
8463
8464THREADED_TEST(ScriptContextDependence) {
8465  v8::HandleScope scope;
8466  LocalContext c1;
8467  const char *source = "foo";
8468  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
8469  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
8470  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
8471  CHECK_EQ(dep->Run()->Int32Value(), 100);
8472  CHECK_EQ(indep->Run()->Int32Value(), 100);
8473  LocalContext c2;
8474  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
8475  CHECK_EQ(dep->Run()->Int32Value(), 100);
8476  CHECK_EQ(indep->Run()->Int32Value(), 101);
8477}
8478
8479
8480THREADED_TEST(StackTrace) {
8481  v8::HandleScope scope;
8482  LocalContext context;
8483  v8::TryCatch try_catch;
8484  const char *source = "function foo() { FAIL.FAIL; }; foo();";
8485  v8::Handle<v8::String> src = v8::String::New(source);
8486  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
8487  v8::Script::New(src, origin)->Run();
8488  CHECK(try_catch.HasCaught());
8489  v8::String::Utf8Value stack(try_catch.StackTrace());
8490  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
8491}
8492
8493
8494// Test that idle notification can be handled and eventually returns true.
8495THREADED_TEST(IdleNotification) {
8496  bool rv = false;
8497  for (int i = 0; i < 100; i++) {
8498    rv = v8::V8::IdleNotification();
8499    if (rv)
8500      break;
8501  }
8502  CHECK(rv == true);
8503}
8504
8505
8506static uint32_t* stack_limit;
8507
8508static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
8509  stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
8510  return v8::Undefined();
8511}
8512
8513
8514// Uses the address of a local variable to determine the stack top now.
8515// Given a size, returns an address that is that far from the current
8516// top of stack.
8517static uint32_t* ComputeStackLimit(uint32_t size) {
8518  uint32_t* answer = &size - (size / sizeof(size));
8519  // If the size is very large and the stack is very near the bottom of
8520  // memory then the calculation above may wrap around and give an address
8521  // that is above the (downwards-growing) stack.  In that case we return
8522  // a very low address.
8523  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
8524  return answer;
8525}
8526
8527
8528TEST(SetResourceConstraints) {
8529  static const int K = 1024;
8530  uint32_t* set_limit = ComputeStackLimit(128 * K);
8531
8532  // Set stack limit.
8533  v8::ResourceConstraints constraints;
8534  constraints.set_stack_limit(set_limit);
8535  CHECK(v8::SetResourceConstraints(&constraints));
8536
8537  // Execute a script.
8538  v8::HandleScope scope;
8539  LocalContext env;
8540  Local<v8::FunctionTemplate> fun_templ =
8541      v8::FunctionTemplate::New(GetStackLimitCallback);
8542  Local<Function> fun = fun_templ->GetFunction();
8543  env->Global()->Set(v8_str("get_stack_limit"), fun);
8544  CompileRun("get_stack_limit();");
8545
8546  CHECK(stack_limit == set_limit);
8547}
8548
8549
8550TEST(SetResourceConstraintsInThread) {
8551  uint32_t* set_limit;
8552  {
8553    v8::Locker locker;
8554    static const int K = 1024;
8555    set_limit = ComputeStackLimit(128 * K);
8556
8557    // Set stack limit.
8558    v8::ResourceConstraints constraints;
8559    constraints.set_stack_limit(set_limit);
8560    CHECK(v8::SetResourceConstraints(&constraints));
8561
8562    // Execute a script.
8563    v8::HandleScope scope;
8564    LocalContext env;
8565    Local<v8::FunctionTemplate> fun_templ =
8566        v8::FunctionTemplate::New(GetStackLimitCallback);
8567    Local<Function> fun = fun_templ->GetFunction();
8568    env->Global()->Set(v8_str("get_stack_limit"), fun);
8569    CompileRun("get_stack_limit();");
8570
8571    CHECK(stack_limit == set_limit);
8572  }
8573  {
8574    v8::Locker locker;
8575    CHECK(stack_limit == set_limit);
8576  }
8577}
8578
8579
8580THREADED_TEST(GetHeapStatistics) {
8581  v8::HandleScope scope;
8582  LocalContext c1;
8583  v8::HeapStatistics heap_statistics;
8584  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
8585  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
8586  v8::V8::GetHeapStatistics(&heap_statistics);
8587  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
8588  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
8589}
8590
8591
8592static double DoubleFromBits(uint64_t value) {
8593  double target;
8594#ifdef BIG_ENDIAN_FLOATING_POINT
8595  const int kIntSize = 4;
8596  // Somebody swapped the lower and higher half of doubles.
8597  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
8598  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
8599#else
8600  memcpy(&target, &value, sizeof(target));
8601#endif
8602  return target;
8603}
8604
8605
8606static uint64_t DoubleToBits(double value) {
8607  uint64_t target;
8608#ifdef BIG_ENDIAN_FLOATING_POINT
8609  const int kIntSize = 4;
8610  // Somebody swapped the lower and higher half of doubles.
8611  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
8612  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
8613#else
8614  memcpy(&target, &value, sizeof(target));
8615#endif
8616  return target;
8617}
8618
8619
8620static double DoubleToDateTime(double input) {
8621  double date_limit = 864e13;
8622  if (IsNaN(input) || input < -date_limit || input > date_limit) {
8623    return i::OS::nan_value();
8624  }
8625  return (input < 0) ? -(floor(-input)) : floor(input);
8626}
8627
8628// We don't have a consistent way to write 64-bit constants syntactically, so we
8629// split them into two 32-bit constants and combine them programmatically.
8630static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
8631  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
8632}
8633
8634
8635THREADED_TEST(QuietSignalingNaNs) {
8636  v8::HandleScope scope;
8637  LocalContext context;
8638  v8::TryCatch try_catch;
8639
8640  // Special double values.
8641  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
8642  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
8643  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
8644  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
8645  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
8646  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
8647  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
8648
8649  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
8650  // on either side of the epoch.
8651  double date_limit = 864e13;
8652
8653  double test_values[] = {
8654      snan,
8655      qnan,
8656      infinity,
8657      max_normal,
8658      date_limit + 1,
8659      date_limit,
8660      min_normal,
8661      max_denormal,
8662      min_denormal,
8663      0,
8664      -0,
8665      -min_denormal,
8666      -max_denormal,
8667      -min_normal,
8668      -date_limit,
8669      -date_limit - 1,
8670      -max_normal,
8671      -infinity,
8672      -qnan,
8673      -snan
8674  };
8675  int num_test_values = 20;
8676
8677  for (int i = 0; i < num_test_values; i++) {
8678    double test_value = test_values[i];
8679
8680    // Check that Number::New preserves non-NaNs and quiets SNaNs.
8681    v8::Handle<v8::Value> number = v8::Number::New(test_value);
8682    double stored_number = number->NumberValue();
8683    if (!IsNaN(test_value)) {
8684      CHECK_EQ(test_value, stored_number);
8685    } else {
8686      uint64_t stored_bits = DoubleToBits(stored_number);
8687      // Check if quiet nan (bits 51..62 all set).
8688      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
8689    }
8690
8691    // Check that Date::New preserves non-NaNs in the date range and
8692    // quiets SNaNs.
8693    v8::Handle<v8::Value> date = v8::Date::New(test_value);
8694    double expected_stored_date = DoubleToDateTime(test_value);
8695    double stored_date = date->NumberValue();
8696    if (!IsNaN(expected_stored_date)) {
8697      CHECK_EQ(expected_stored_date, stored_date);
8698    } else {
8699      uint64_t stored_bits = DoubleToBits(stored_date);
8700      // Check if quiet nan (bits 51..62 all set).
8701      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
8702    }
8703  }
8704}
8705
8706
8707static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
8708  v8::HandleScope scope;
8709  v8::TryCatch tc;
8710  v8::Handle<v8::String> str = args[0]->ToString();
8711  if (tc.HasCaught())
8712    return tc.ReThrow();
8713  return v8::Undefined();
8714}
8715
8716
8717// Test that an exception can be propagated down through a spaghetti
8718// stack using ReThrow.
8719THREADED_TEST(SpaghettiStackReThrow) {
8720  v8::HandleScope scope;
8721  LocalContext context;
8722  context->Global()->Set(
8723      v8::String::New("s"),
8724      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
8725  v8::TryCatch try_catch;
8726  CompileRun(
8727      "var i = 0;"
8728      "var o = {"
8729      "  toString: function () {"
8730      "    if (i == 10) {"
8731      "      throw 'Hey!';"
8732      "    } else {"
8733      "      i++;"
8734      "      return s(o);"
8735      "    }"
8736      "  }"
8737      "};"
8738      "s(o);");
8739  CHECK(try_catch.HasCaught());
8740  v8::String::Utf8Value value(try_catch.Exception());
8741  CHECK_EQ(0, strcmp(*value, "Hey!"));
8742}
8743
8744
8745TEST(Regress528) {
8746  v8::V8::Initialize();
8747
8748  v8::HandleScope scope;
8749  v8::Persistent<Context> context;
8750  v8::Persistent<Context> other_context;
8751  int gc_count;
8752
8753  // Create a context used to keep the code from aging in the compilation
8754  // cache.
8755  other_context = Context::New();
8756
8757  // Context-dependent context data creates reference from the compilation
8758  // cache to the global object.
8759  const char* source_simple = "1";
8760  context = Context::New();
8761  {
8762    v8::HandleScope scope;
8763
8764    context->Enter();
8765    Local<v8::String> obj = v8::String::New("");
8766    context->SetData(obj);
8767    CompileRun(source_simple);
8768    context->Exit();
8769  }
8770  context.Dispose();
8771  for (gc_count = 1; gc_count < 10; gc_count++) {
8772    other_context->Enter();
8773    CompileRun(source_simple);
8774    other_context->Exit();
8775    v8::internal::Heap::CollectAllGarbage(false);
8776    if (GetGlobalObjectsCount() == 1) break;
8777  }
8778  CHECK_GE(2, gc_count);
8779  CHECK_EQ(1, GetGlobalObjectsCount());
8780
8781  // Eval in a function creates reference from the compilation cache to the
8782  // global object.
8783  const char* source_eval = "function f(){eval('1')}; f()";
8784  context = Context::New();
8785  {
8786    v8::HandleScope scope;
8787
8788    context->Enter();
8789    CompileRun(source_eval);
8790    context->Exit();
8791  }
8792  context.Dispose();
8793  for (gc_count = 1; gc_count < 10; gc_count++) {
8794    other_context->Enter();
8795    CompileRun(source_eval);
8796    other_context->Exit();
8797    v8::internal::Heap::CollectAllGarbage(false);
8798    if (GetGlobalObjectsCount() == 1) break;
8799  }
8800  CHECK_GE(2, gc_count);
8801  CHECK_EQ(1, GetGlobalObjectsCount());
8802
8803  // Looking up the line number for an exception creates reference from the
8804  // compilation cache to the global object.
8805  const char* source_exception = "function f(){throw 1;} f()";
8806  context = Context::New();
8807  {
8808    v8::HandleScope scope;
8809
8810    context->Enter();
8811    v8::TryCatch try_catch;
8812    CompileRun(source_exception);
8813    CHECK(try_catch.HasCaught());
8814    v8::Handle<v8::Message> message = try_catch.Message();
8815    CHECK(!message.IsEmpty());
8816    CHECK_EQ(1, message->GetLineNumber());
8817    context->Exit();
8818  }
8819  context.Dispose();
8820  for (gc_count = 1; gc_count < 10; gc_count++) {
8821    other_context->Enter();
8822    CompileRun(source_exception);
8823    other_context->Exit();
8824    v8::internal::Heap::CollectAllGarbage(false);
8825    if (GetGlobalObjectsCount() == 1) break;
8826  }
8827  CHECK_GE(2, gc_count);
8828  CHECK_EQ(1, GetGlobalObjectsCount());
8829
8830  other_context.Dispose();
8831}
8832