test-api.cc revision 888f6729be6a6f6fbe246cb5a9f122e2dbe455b7
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 = 300;  // 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
3605
3606TEST(CompilationErrorUsingTryCatchHandler) {
3607  v8::HandleScope scope;
3608  LocalContext env;
3609  v8::TryCatch try_catch;
3610  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
3611  CHECK_NE(NULL, *try_catch.Exception());
3612  CHECK(try_catch.HasCaught());
3613}
3614
3615
3616TEST(TryCatchFinallyUsingTryCatchHandler) {
3617  v8::HandleScope scope;
3618  LocalContext env;
3619  v8::TryCatch try_catch;
3620  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
3621  CHECK(!try_catch.HasCaught());
3622  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
3623  CHECK(try_catch.HasCaught());
3624  try_catch.Reset();
3625  Script::Compile(v8_str("(function() {"
3626                         "try { throw ''; } finally { return; }"
3627                         "})()"))->Run();
3628  CHECK(!try_catch.HasCaught());
3629  Script::Compile(v8_str("(function()"
3630                         "  { try { throw ''; } finally { throw 0; }"
3631                         "})()"))->Run();
3632  CHECK(try_catch.HasCaught());
3633}
3634
3635
3636// SecurityHandler can't be run twice
3637TEST(SecurityHandler) {
3638  v8::HandleScope scope0;
3639  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
3640  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
3641                                           IndexedSecurityTestCallback);
3642  // Create an environment
3643  v8::Persistent<Context> context0 =
3644    Context::New(NULL, global_template);
3645  context0->Enter();
3646
3647  v8::Handle<v8::Object> global0 = context0->Global();
3648  v8::Handle<Script> script0 = v8_compile("foo = 111");
3649  script0->Run();
3650  global0->Set(v8_str("0"), v8_num(999));
3651  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
3652  CHECK_EQ(111, foo0->Int32Value());
3653  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
3654  CHECK_EQ(999, z0->Int32Value());
3655
3656  // Create another environment, should fail security checks.
3657  v8::HandleScope scope1;
3658
3659  v8::Persistent<Context> context1 =
3660    Context::New(NULL, global_template);
3661  context1->Enter();
3662
3663  v8::Handle<v8::Object> global1 = context1->Global();
3664  global1->Set(v8_str("othercontext"), global0);
3665  // This set will fail the security check.
3666  v8::Handle<Script> script1 =
3667    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
3668  script1->Run();
3669  // This read will pass the security check.
3670  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
3671  CHECK_EQ(111, foo1->Int32Value());
3672  // This read will pass the security check.
3673  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
3674  CHECK_EQ(999, z1->Int32Value());
3675
3676  // Create another environment, should pass security checks.
3677  { g_security_callback_result = true;  // allow security handler to pass.
3678    v8::HandleScope scope2;
3679    LocalContext context2;
3680    v8::Handle<v8::Object> global2 = context2->Global();
3681    global2->Set(v8_str("othercontext"), global0);
3682    v8::Handle<Script> script2 =
3683        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
3684    script2->Run();
3685    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
3686    CHECK_EQ(333, foo2->Int32Value());
3687    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
3688    CHECK_EQ(888, z2->Int32Value());
3689  }
3690
3691  context1->Exit();
3692  context1.Dispose();
3693
3694  context0->Exit();
3695  context0.Dispose();
3696}
3697
3698
3699THREADED_TEST(SecurityChecks) {
3700  v8::HandleScope handle_scope;
3701  LocalContext env1;
3702  v8::Persistent<Context> env2 = Context::New();
3703
3704  Local<Value> foo = v8_str("foo");
3705  Local<Value> bar = v8_str("bar");
3706
3707  // Set to the same domain.
3708  env1->SetSecurityToken(foo);
3709
3710  // Create a function in env1.
3711  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
3712  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
3713  CHECK(spy->IsFunction());
3714
3715  // Create another function accessing global objects.
3716  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
3717  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
3718  CHECK(spy2->IsFunction());
3719
3720  // Switch to env2 in the same domain and invoke spy on env2.
3721  {
3722    env2->SetSecurityToken(foo);
3723    // Enter env2
3724    Context::Scope scope_env2(env2);
3725    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
3726    CHECK(result->IsFunction());
3727  }
3728
3729  {
3730    env2->SetSecurityToken(bar);
3731    Context::Scope scope_env2(env2);
3732
3733    // Call cross_domain_call, it should throw an exception
3734    v8::TryCatch try_catch;
3735    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
3736    CHECK(try_catch.HasCaught());
3737  }
3738
3739  env2.Dispose();
3740}
3741
3742
3743// Regression test case for issue 1183439.
3744THREADED_TEST(SecurityChecksForPrototypeChain) {
3745  v8::HandleScope scope;
3746  LocalContext current;
3747  v8::Persistent<Context> other = Context::New();
3748
3749  // Change context to be able to get to the Object function in the
3750  // other context without hitting the security checks.
3751  v8::Local<Value> other_object;
3752  { Context::Scope scope(other);
3753    other_object = other->Global()->Get(v8_str("Object"));
3754    other->Global()->Set(v8_num(42), v8_num(87));
3755  }
3756
3757  current->Global()->Set(v8_str("other"), other->Global());
3758  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
3759
3760  // Make sure the security check fails here and we get an undefined
3761  // result instead of getting the Object function. Repeat in a loop
3762  // to make sure to exercise the IC code.
3763  v8::Local<Script> access_other0 = v8_compile("other.Object");
3764  v8::Local<Script> access_other1 = v8_compile("other[42]");
3765  for (int i = 0; i < 5; i++) {
3766    CHECK(!access_other0->Run()->Equals(other_object));
3767    CHECK(access_other0->Run()->IsUndefined());
3768    CHECK(!access_other1->Run()->Equals(v8_num(87)));
3769    CHECK(access_other1->Run()->IsUndefined());
3770  }
3771
3772  // Create an object that has 'other' in its prototype chain and make
3773  // sure we cannot access the Object function indirectly through
3774  // that. Repeat in a loop to make sure to exercise the IC code.
3775  v8_compile("function F() { };"
3776             "F.prototype = other;"
3777             "var f = new F();")->Run();
3778  v8::Local<Script> access_f0 = v8_compile("f.Object");
3779  v8::Local<Script> access_f1 = v8_compile("f[42]");
3780  for (int j = 0; j < 5; j++) {
3781    CHECK(!access_f0->Run()->Equals(other_object));
3782    CHECK(access_f0->Run()->IsUndefined());
3783    CHECK(!access_f1->Run()->Equals(v8_num(87)));
3784    CHECK(access_f1->Run()->IsUndefined());
3785  }
3786
3787  // Now it gets hairy: Set the prototype for the other global object
3788  // to be the current global object. The prototype chain for 'f' now
3789  // goes through 'other' but ends up in the current global object.
3790  { Context::Scope scope(other);
3791    other->Global()->Set(v8_str("__proto__"), current->Global());
3792  }
3793  // Set a named and an index property on the current global
3794  // object. To force the lookup to go through the other global object,
3795  // the properties must not exist in the other global object.
3796  current->Global()->Set(v8_str("foo"), v8_num(100));
3797  current->Global()->Set(v8_num(99), v8_num(101));
3798  // Try to read the properties from f and make sure that the access
3799  // gets stopped by the security checks on the other global object.
3800  Local<Script> access_f2 = v8_compile("f.foo");
3801  Local<Script> access_f3 = v8_compile("f[99]");
3802  for (int k = 0; k < 5; k++) {
3803    CHECK(!access_f2->Run()->Equals(v8_num(100)));
3804    CHECK(access_f2->Run()->IsUndefined());
3805    CHECK(!access_f3->Run()->Equals(v8_num(101)));
3806    CHECK(access_f3->Run()->IsUndefined());
3807  }
3808  other.Dispose();
3809}
3810
3811
3812THREADED_TEST(CrossDomainDelete) {
3813  v8::HandleScope handle_scope;
3814  LocalContext env1;
3815  v8::Persistent<Context> env2 = Context::New();
3816
3817  Local<Value> foo = v8_str("foo");
3818  Local<Value> bar = v8_str("bar");
3819
3820  // Set to the same domain.
3821  env1->SetSecurityToken(foo);
3822  env2->SetSecurityToken(foo);
3823
3824  env1->Global()->Set(v8_str("prop"), v8_num(3));
3825  env2->Global()->Set(v8_str("env1"), env1->Global());
3826
3827  // Change env2 to a different domain and delete env1.prop.
3828  env2->SetSecurityToken(bar);
3829  {
3830    Context::Scope scope_env2(env2);
3831    Local<Value> result =
3832        Script::Compile(v8_str("delete env1.prop"))->Run();
3833    CHECK(result->IsFalse());
3834  }
3835
3836  // Check that env1.prop still exists.
3837  Local<Value> v = env1->Global()->Get(v8_str("prop"));
3838  CHECK(v->IsNumber());
3839  CHECK_EQ(3, v->Int32Value());
3840
3841  env2.Dispose();
3842}
3843
3844
3845THREADED_TEST(CrossDomainIsPropertyEnumerable) {
3846  v8::HandleScope handle_scope;
3847  LocalContext env1;
3848  v8::Persistent<Context> env2 = Context::New();
3849
3850  Local<Value> foo = v8_str("foo");
3851  Local<Value> bar = v8_str("bar");
3852
3853  // Set to the same domain.
3854  env1->SetSecurityToken(foo);
3855  env2->SetSecurityToken(foo);
3856
3857  env1->Global()->Set(v8_str("prop"), v8_num(3));
3858  env2->Global()->Set(v8_str("env1"), env1->Global());
3859
3860  // env1.prop is enumerable in env2.
3861  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
3862  {
3863    Context::Scope scope_env2(env2);
3864    Local<Value> result = Script::Compile(test)->Run();
3865    CHECK(result->IsTrue());
3866  }
3867
3868  // Change env2 to a different domain and test again.
3869  env2->SetSecurityToken(bar);
3870  {
3871    Context::Scope scope_env2(env2);
3872    Local<Value> result = Script::Compile(test)->Run();
3873    CHECK(result->IsFalse());
3874  }
3875
3876  env2.Dispose();
3877}
3878
3879
3880THREADED_TEST(CrossDomainForIn) {
3881  v8::HandleScope handle_scope;
3882  LocalContext env1;
3883  v8::Persistent<Context> env2 = Context::New();
3884
3885  Local<Value> foo = v8_str("foo");
3886  Local<Value> bar = v8_str("bar");
3887
3888  // Set to the same domain.
3889  env1->SetSecurityToken(foo);
3890  env2->SetSecurityToken(foo);
3891
3892  env1->Global()->Set(v8_str("prop"), v8_num(3));
3893  env2->Global()->Set(v8_str("env1"), env1->Global());
3894
3895  // Change env2 to a different domain and set env1's global object
3896  // as the __proto__ of an object in env2 and enumerate properties
3897  // in for-in. It shouldn't enumerate properties on env1's global
3898  // object.
3899  env2->SetSecurityToken(bar);
3900  {
3901    Context::Scope scope_env2(env2);
3902    Local<Value> result =
3903        CompileRun("(function(){var obj = {'__proto__':env1};"
3904                   "for (var p in obj)"
3905                   "   if (p == 'prop') return false;"
3906                   "return true;})()");
3907    CHECK(result->IsTrue());
3908  }
3909  env2.Dispose();
3910}
3911
3912
3913TEST(ContextDetachGlobal) {
3914  v8::HandleScope handle_scope;
3915  LocalContext env1;
3916  v8::Persistent<Context> env2 = Context::New();
3917
3918  Local<v8::Object> global1 = env1->Global();
3919
3920  Local<Value> foo = v8_str("foo");
3921
3922  // Set to the same domain.
3923  env1->SetSecurityToken(foo);
3924  env2->SetSecurityToken(foo);
3925
3926  // Enter env2
3927  env2->Enter();
3928
3929  // Create a function in env1
3930  Local<v8::Object> global2 = env2->Global();
3931  global2->Set(v8_str("prop"), v8::Integer::New(1));
3932  CompileRun("function getProp() {return prop;}");
3933
3934  env1->Global()->Set(v8_str("getProp"),
3935                      global2->Get(v8_str("getProp")));
3936
3937  // Detach env1's global, and reuse the global object of env1
3938  env2->Exit();
3939  env2->DetachGlobal();
3940  // env2 has a new global object.
3941  CHECK(!env2->Global()->Equals(global2));
3942
3943  v8::Persistent<Context> env3 =
3944      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
3945  env3->SetSecurityToken(v8_str("bar"));
3946  env3->Enter();
3947
3948  Local<v8::Object> global3 = env3->Global();
3949  CHECK_EQ(global2, global3);
3950  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
3951  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
3952  global3->Set(v8_str("prop"), v8::Integer::New(-1));
3953  global3->Set(v8_str("prop2"), v8::Integer::New(2));
3954  env3->Exit();
3955
3956  // Call getProp in env1, and it should return the value 1
3957  {
3958    Local<Value> get_prop = global1->Get(v8_str("getProp"));
3959    CHECK(get_prop->IsFunction());
3960    v8::TryCatch try_catch;
3961    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
3962    CHECK(!try_catch.HasCaught());
3963    CHECK_EQ(1, r->Int32Value());
3964  }
3965
3966  // Check that env3 is not accessible from env1
3967  {
3968    Local<Value> r = global3->Get(v8_str("prop2"));
3969    CHECK(r->IsUndefined());
3970  }
3971
3972  env2.Dispose();
3973  env3.Dispose();
3974}
3975
3976
3977static bool NamedAccessBlocker(Local<v8::Object> global,
3978                               Local<Value> name,
3979                               v8::AccessType type,
3980                               Local<Value> data) {
3981  return Context::GetCurrent()->Global()->Equals(global);
3982}
3983
3984
3985static bool IndexedAccessBlocker(Local<v8::Object> global,
3986                                 uint32_t key,
3987                                 v8::AccessType type,
3988                                 Local<Value> data) {
3989  return Context::GetCurrent()->Global()->Equals(global);
3990}
3991
3992
3993static int g_echo_value = -1;
3994static v8::Handle<Value> EchoGetter(Local<String> name,
3995                                    const AccessorInfo& info) {
3996  return v8_num(g_echo_value);
3997}
3998
3999
4000static void EchoSetter(Local<String> name,
4001                       Local<Value> value,
4002                       const AccessorInfo&) {
4003  if (value->IsNumber())
4004    g_echo_value = value->Int32Value();
4005}
4006
4007
4008static v8::Handle<Value> UnreachableGetter(Local<String> name,
4009                                           const AccessorInfo& info) {
4010  CHECK(false);  // This function should not be called..
4011  return v8::Undefined();
4012}
4013
4014
4015static void UnreachableSetter(Local<String>, Local<Value>,
4016                              const AccessorInfo&) {
4017  CHECK(false);  // This function should nto be called.
4018}
4019
4020
4021THREADED_TEST(AccessControl) {
4022  v8::HandleScope handle_scope;
4023  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4024
4025  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
4026                                           IndexedAccessBlocker);
4027
4028  // Add an accessor accessible by cross-domain JS code.
4029  global_template->SetAccessor(
4030      v8_str("accessible_prop"),
4031      EchoGetter, EchoSetter,
4032      v8::Handle<Value>(),
4033      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
4034
4035  // Add an accessor that is not accessible by cross-domain JS code.
4036  global_template->SetAccessor(v8_str("blocked_prop"),
4037                               UnreachableGetter, UnreachableSetter,
4038                               v8::Handle<Value>(),
4039                               v8::DEFAULT);
4040
4041  // Create an environment
4042  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4043  context0->Enter();
4044
4045  v8::Handle<v8::Object> global0 = context0->Global();
4046
4047  v8::HandleScope scope1;
4048
4049  v8::Persistent<Context> context1 = Context::New();
4050  context1->Enter();
4051
4052  v8::Handle<v8::Object> global1 = context1->Global();
4053  global1->Set(v8_str("other"), global0);
4054
4055  v8::Handle<Value> value;
4056
4057  // Access blocked property
4058  value = v8_compile("other.blocked_prop = 1")->Run();
4059  value = v8_compile("other.blocked_prop")->Run();
4060  CHECK(value->IsUndefined());
4061
4062  value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
4063  CHECK(value->IsFalse());
4064
4065  // Access accessible property
4066  value = v8_compile("other.accessible_prop = 3")->Run();
4067  CHECK(value->IsNumber());
4068  CHECK_EQ(3, value->Int32Value());
4069
4070  value = v8_compile("other.accessible_prop")->Run();
4071  CHECK(value->IsNumber());
4072  CHECK_EQ(3, value->Int32Value());
4073
4074  value =
4075    v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
4076  CHECK(value->IsTrue());
4077
4078  // Enumeration doesn't enumerate accessors from inaccessible objects in
4079  // the prototype chain even if the accessors are in themselves accessible.
4080  Local<Value> result =
4081      CompileRun("(function(){var obj = {'__proto__':other};"
4082                 "for (var p in obj)"
4083                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
4084                 "     return false;"
4085                 "   }"
4086                 "return true;})()");
4087  CHECK(result->IsTrue());
4088
4089  context1->Exit();
4090  context0->Exit();
4091  context1.Dispose();
4092  context0.Dispose();
4093}
4094
4095
4096static v8::Handle<Value> ConstTenGetter(Local<String> name,
4097                                        const AccessorInfo& info) {
4098  return v8_num(10);
4099}
4100
4101
4102THREADED_TEST(CrossDomainAccessors) {
4103  v8::HandleScope handle_scope;
4104
4105  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
4106
4107  v8::Handle<v8::ObjectTemplate> global_template =
4108      func_template->InstanceTemplate();
4109
4110  v8::Handle<v8::ObjectTemplate> proto_template =
4111      func_template->PrototypeTemplate();
4112
4113  // Add an accessor to proto that's accessible by cross-domain JS code.
4114  proto_template->SetAccessor(v8_str("accessible"),
4115                              ConstTenGetter, 0,
4116                              v8::Handle<Value>(),
4117                              v8::ALL_CAN_READ);
4118
4119  // Add an accessor that is not accessible by cross-domain JS code.
4120  global_template->SetAccessor(v8_str("unreachable"),
4121                               UnreachableGetter, 0,
4122                               v8::Handle<Value>(),
4123                               v8::DEFAULT);
4124
4125  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4126  context0->Enter();
4127
4128  Local<v8::Object> global = context0->Global();
4129  // Add a normal property that shadows 'accessible'
4130  global->Set(v8_str("accessible"), v8_num(11));
4131
4132  // Enter a new context.
4133  v8::HandleScope scope1;
4134  v8::Persistent<Context> context1 = Context::New();
4135  context1->Enter();
4136
4137  v8::Handle<v8::Object> global1 = context1->Global();
4138  global1->Set(v8_str("other"), global);
4139
4140  // Should return 10, instead of 11
4141  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
4142  CHECK(value->IsNumber());
4143  CHECK_EQ(10, value->Int32Value());
4144
4145  value = v8_compile("other.unreachable")->Run();
4146  CHECK(value->IsUndefined());
4147
4148  context1->Exit();
4149  context0->Exit();
4150  context1.Dispose();
4151  context0.Dispose();
4152}
4153
4154
4155static int named_access_count = 0;
4156static int indexed_access_count = 0;
4157
4158static bool NamedAccessCounter(Local<v8::Object> global,
4159                               Local<Value> name,
4160                               v8::AccessType type,
4161                               Local<Value> data) {
4162  named_access_count++;
4163  return true;
4164}
4165
4166
4167static bool IndexedAccessCounter(Local<v8::Object> global,
4168                                 uint32_t key,
4169                                 v8::AccessType type,
4170                                 Local<Value> data) {
4171  indexed_access_count++;
4172  return true;
4173}
4174
4175
4176// This one is too easily disturbed by other tests.
4177TEST(AccessControlIC) {
4178  named_access_count = 0;
4179  indexed_access_count = 0;
4180
4181  v8::HandleScope handle_scope;
4182
4183  // Create an environment.
4184  v8::Persistent<Context> context0 = Context::New();
4185  context0->Enter();
4186
4187  // Create an object that requires access-check functions to be
4188  // called for cross-domain access.
4189  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4190  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4191                                           IndexedAccessCounter);
4192  Local<v8::Object> object = object_template->NewInstance();
4193
4194  v8::HandleScope scope1;
4195
4196  // Create another environment.
4197  v8::Persistent<Context> context1 = Context::New();
4198  context1->Enter();
4199
4200  // Make easy access to the object from the other environment.
4201  v8::Handle<v8::Object> global1 = context1->Global();
4202  global1->Set(v8_str("obj"), object);
4203
4204  v8::Handle<Value> value;
4205
4206  // Check that the named access-control function is called every time.
4207  CompileRun("function testProp(obj) {"
4208             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
4209             "  for (var j = 0; j < 10; j++) obj.prop;"
4210             "  return obj.prop"
4211             "}");
4212  value = CompileRun("testProp(obj)");
4213  CHECK(value->IsNumber());
4214  CHECK_EQ(1, value->Int32Value());
4215  CHECK_EQ(21, named_access_count);
4216
4217  // Check that the named access-control function is called every time.
4218  CompileRun("var p = 'prop';"
4219             "function testKeyed(obj) {"
4220             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
4221             "  for (var j = 0; j < 10; j++) obj[p];"
4222             "  return obj[p];"
4223             "}");
4224  // Use obj which requires access checks.  No inline caching is used
4225  // in that case.
4226  value = CompileRun("testKeyed(obj)");
4227  CHECK(value->IsNumber());
4228  CHECK_EQ(1, value->Int32Value());
4229  CHECK_EQ(42, named_access_count);
4230  // Force the inline caches into generic state and try again.
4231  CompileRun("testKeyed({ a: 0 })");
4232  CompileRun("testKeyed({ b: 0 })");
4233  value = CompileRun("testKeyed(obj)");
4234  CHECK(value->IsNumber());
4235  CHECK_EQ(1, value->Int32Value());
4236  CHECK_EQ(63, named_access_count);
4237
4238  // Check that the indexed access-control function is called every time.
4239  CompileRun("function testIndexed(obj) {"
4240             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
4241             "  for (var j = 0; j < 10; j++) obj[0];"
4242             "  return obj[0]"
4243             "}");
4244  value = CompileRun("testIndexed(obj)");
4245  CHECK(value->IsNumber());
4246  CHECK_EQ(1, value->Int32Value());
4247  CHECK_EQ(21, indexed_access_count);
4248  // Force the inline caches into generic state.
4249  CompileRun("testIndexed(new Array(1))");
4250  // Test that the indexed access check is called.
4251  value = CompileRun("testIndexed(obj)");
4252  CHECK(value->IsNumber());
4253  CHECK_EQ(1, value->Int32Value());
4254  CHECK_EQ(42, indexed_access_count);
4255
4256  // Check that the named access check is called when invoking
4257  // functions on an object that requires access checks.
4258  CompileRun("obj.f = function() {}");
4259  CompileRun("function testCallNormal(obj) {"
4260             "  for (var i = 0; i < 10; i++) obj.f();"
4261             "}");
4262  CompileRun("testCallNormal(obj)");
4263  CHECK_EQ(74, named_access_count);
4264
4265  // Force obj into slow case.
4266  value = CompileRun("delete obj.prop");
4267  CHECK(value->BooleanValue());
4268  // Force inline caches into dictionary probing mode.
4269  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
4270  // Test that the named access check is called.
4271  value = CompileRun("testProp(obj);");
4272  CHECK(value->IsNumber());
4273  CHECK_EQ(1, value->Int32Value());
4274  CHECK_EQ(96, named_access_count);
4275
4276  // Force the call inline cache into dictionary probing mode.
4277  CompileRun("o.f = function() {}; testCallNormal(o)");
4278  // Test that the named access check is still called for each
4279  // invocation of the function.
4280  value = CompileRun("testCallNormal(obj)");
4281  CHECK_EQ(106, named_access_count);
4282
4283  context1->Exit();
4284  context0->Exit();
4285  context1.Dispose();
4286  context0.Dispose();
4287}
4288
4289
4290static bool NamedAccessFlatten(Local<v8::Object> global,
4291                               Local<Value> name,
4292                               v8::AccessType type,
4293                               Local<Value> data) {
4294  char buf[100];
4295  int len;
4296
4297  CHECK(name->IsString());
4298
4299  memset(buf, 0x1, sizeof(buf));
4300  len = Local<String>::Cast(name)->WriteAscii(buf);
4301  CHECK_EQ(4, len);
4302
4303  uint16_t buf2[100];
4304
4305  memset(buf, 0x1, sizeof(buf));
4306  len = Local<String>::Cast(name)->Write(buf2);
4307  CHECK_EQ(4, len);
4308
4309  return true;
4310}
4311
4312
4313static bool IndexedAccessFlatten(Local<v8::Object> global,
4314                                 uint32_t key,
4315                                 v8::AccessType type,
4316                                 Local<Value> data) {
4317  return true;
4318}
4319
4320
4321// Regression test.  In access checks, operations that may cause
4322// garbage collection are not allowed.  It used to be the case that
4323// using the Write operation on a string could cause a garbage
4324// collection due to flattening of the string.  This is no longer the
4325// case.
4326THREADED_TEST(AccessControlFlatten) {
4327  named_access_count = 0;
4328  indexed_access_count = 0;
4329
4330  v8::HandleScope handle_scope;
4331
4332  // Create an environment.
4333  v8::Persistent<Context> context0 = Context::New();
4334  context0->Enter();
4335
4336  // Create an object that requires access-check functions to be
4337  // called for cross-domain access.
4338  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4339  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
4340                                           IndexedAccessFlatten);
4341  Local<v8::Object> object = object_template->NewInstance();
4342
4343  v8::HandleScope scope1;
4344
4345  // Create another environment.
4346  v8::Persistent<Context> context1 = Context::New();
4347  context1->Enter();
4348
4349  // Make easy access to the object from the other environment.
4350  v8::Handle<v8::Object> global1 = context1->Global();
4351  global1->Set(v8_str("obj"), object);
4352
4353  v8::Handle<Value> value;
4354
4355  value = v8_compile("var p = 'as' + 'df';")->Run();
4356  value = v8_compile("obj[p];")->Run();
4357
4358  context1->Exit();
4359  context0->Exit();
4360  context1.Dispose();
4361  context0.Dispose();
4362}
4363
4364
4365static v8::Handle<Value> AccessControlNamedGetter(
4366    Local<String>, const AccessorInfo&) {
4367  return v8::Integer::New(42);
4368}
4369
4370
4371static v8::Handle<Value> AccessControlNamedSetter(
4372    Local<String>, Local<Value> value, const AccessorInfo&) {
4373  return value;
4374}
4375
4376
4377static v8::Handle<Value> AccessControlIndexedGetter(
4378      uint32_t index,
4379      const AccessorInfo& info) {
4380  return v8_num(42);
4381}
4382
4383
4384static v8::Handle<Value> AccessControlIndexedSetter(
4385    uint32_t, Local<Value> value, const AccessorInfo&) {
4386  return value;
4387}
4388
4389
4390THREADED_TEST(AccessControlInterceptorIC) {
4391  named_access_count = 0;
4392  indexed_access_count = 0;
4393
4394  v8::HandleScope handle_scope;
4395
4396  // Create an environment.
4397  v8::Persistent<Context> context0 = Context::New();
4398  context0->Enter();
4399
4400  // Create an object that requires access-check functions to be
4401  // called for cross-domain access.  The object also has interceptors
4402  // interceptor.
4403  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4404  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4405                                           IndexedAccessCounter);
4406  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
4407                                           AccessControlNamedSetter);
4408  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
4409                                             AccessControlIndexedSetter);
4410  Local<v8::Object> object = object_template->NewInstance();
4411
4412  v8::HandleScope scope1;
4413
4414  // Create another environment.
4415  v8::Persistent<Context> context1 = Context::New();
4416  context1->Enter();
4417
4418  // Make easy access to the object from the other environment.
4419  v8::Handle<v8::Object> global1 = context1->Global();
4420  global1->Set(v8_str("obj"), object);
4421
4422  v8::Handle<Value> value;
4423
4424  // Check that the named access-control function is called every time
4425  // eventhough there is an interceptor on the object.
4426  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
4427  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
4428                     "obj.x")->Run();
4429  CHECK(value->IsNumber());
4430  CHECK_EQ(42, value->Int32Value());
4431  CHECK_EQ(21, named_access_count);
4432
4433  value = v8_compile("var p = 'x';")->Run();
4434  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
4435  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
4436                     "obj[p]")->Run();
4437  CHECK(value->IsNumber());
4438  CHECK_EQ(42, value->Int32Value());
4439  CHECK_EQ(42, named_access_count);
4440
4441  // Check that the indexed access-control function is called every
4442  // time eventhough there is an interceptor on the object.
4443  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
4444  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
4445                     "obj[0]")->Run();
4446  CHECK(value->IsNumber());
4447  CHECK_EQ(42, value->Int32Value());
4448  CHECK_EQ(21, indexed_access_count);
4449
4450  context1->Exit();
4451  context0->Exit();
4452  context1.Dispose();
4453  context0.Dispose();
4454}
4455
4456
4457THREADED_TEST(Version) {
4458  v8::V8::GetVersion();
4459}
4460
4461
4462static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
4463  ApiTestFuzzer::Fuzz();
4464  return v8_num(12);
4465}
4466
4467
4468THREADED_TEST(InstanceProperties) {
4469  v8::HandleScope handle_scope;
4470  LocalContext context;
4471
4472  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4473  Local<ObjectTemplate> instance = t->InstanceTemplate();
4474
4475  instance->Set(v8_str("x"), v8_num(42));
4476  instance->Set(v8_str("f"),
4477                v8::FunctionTemplate::New(InstanceFunctionCallback));
4478
4479  Local<Value> o = t->GetFunction()->NewInstance();
4480
4481  context->Global()->Set(v8_str("i"), o);
4482  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
4483  CHECK_EQ(42, value->Int32Value());
4484
4485  value = Script::Compile(v8_str("i.f()"))->Run();
4486  CHECK_EQ(12, value->Int32Value());
4487}
4488
4489
4490static v8::Handle<Value>
4491GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
4492  ApiTestFuzzer::Fuzz();
4493  return v8::Handle<Value>();
4494}
4495
4496
4497THREADED_TEST(GlobalObjectInstanceProperties) {
4498  v8::HandleScope handle_scope;
4499
4500  Local<Value> global_object;
4501
4502  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4503  t->InstanceTemplate()->SetNamedPropertyHandler(
4504      GlobalObjectInstancePropertiesGet);
4505  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
4506  instance_template->Set(v8_str("x"), v8_num(42));
4507  instance_template->Set(v8_str("f"),
4508                         v8::FunctionTemplate::New(InstanceFunctionCallback));
4509
4510  {
4511    LocalContext env(NULL, instance_template);
4512    // Hold on to the global object so it can be used again in another
4513    // environment initialization.
4514    global_object = env->Global();
4515
4516    Local<Value> value = Script::Compile(v8_str("x"))->Run();
4517    CHECK_EQ(42, value->Int32Value());
4518    value = Script::Compile(v8_str("f()"))->Run();
4519    CHECK_EQ(12, value->Int32Value());
4520  }
4521
4522  {
4523    // Create new environment reusing the global object.
4524    LocalContext env(NULL, instance_template, global_object);
4525    Local<Value> value = Script::Compile(v8_str("x"))->Run();
4526    CHECK_EQ(42, value->Int32Value());
4527    value = Script::Compile(v8_str("f()"))->Run();
4528    CHECK_EQ(12, value->Int32Value());
4529  }
4530}
4531
4532
4533static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
4534  ApiTestFuzzer::Fuzz();
4535  return v8_num(42);
4536}
4537
4538
4539static int shadow_y;
4540static int shadow_y_setter_call_count;
4541static int shadow_y_getter_call_count;
4542
4543
4544static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
4545  shadow_y_setter_call_count++;
4546  shadow_y = 42;
4547}
4548
4549
4550static v8::Handle<Value> ShadowYGetter(Local<String> name,
4551                                       const AccessorInfo& info) {
4552  ApiTestFuzzer::Fuzz();
4553  shadow_y_getter_call_count++;
4554  return v8_num(shadow_y);
4555}
4556
4557
4558static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
4559                                          const AccessorInfo& info) {
4560  return v8::Handle<Value>();
4561}
4562
4563
4564static v8::Handle<Value> ShadowNamedGet(Local<String> key,
4565                                        const AccessorInfo&) {
4566  return v8::Handle<Value>();
4567}
4568
4569
4570THREADED_TEST(ShadowObject) {
4571  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
4572  v8::HandleScope handle_scope;
4573
4574  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
4575  LocalContext context(NULL, global_template);
4576
4577  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4578  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
4579  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
4580  Local<ObjectTemplate> proto = t->PrototypeTemplate();
4581  Local<ObjectTemplate> instance = t->InstanceTemplate();
4582
4583  // Only allow calls of f on instances of t.
4584  Local<v8::Signature> signature = v8::Signature::New(t);
4585  proto->Set(v8_str("f"),
4586             v8::FunctionTemplate::New(ShadowFunctionCallback,
4587                                       Local<Value>(),
4588                                       signature));
4589  proto->Set(v8_str("x"), v8_num(12));
4590
4591  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
4592
4593  Local<Value> o = t->GetFunction()->NewInstance();
4594  context->Global()->Set(v8_str("__proto__"), o);
4595
4596  Local<Value> value =
4597      Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
4598  CHECK(value->IsBoolean());
4599  CHECK(!value->BooleanValue());
4600
4601  value = Script::Compile(v8_str("x"))->Run();
4602  CHECK_EQ(12, value->Int32Value());
4603
4604  value = Script::Compile(v8_str("f()"))->Run();
4605  CHECK_EQ(42, value->Int32Value());
4606
4607  Script::Compile(v8_str("y = 42"))->Run();
4608  CHECK_EQ(1, shadow_y_setter_call_count);
4609  value = Script::Compile(v8_str("y"))->Run();
4610  CHECK_EQ(1, shadow_y_getter_call_count);
4611  CHECK_EQ(42, value->Int32Value());
4612}
4613
4614
4615THREADED_TEST(HiddenPrototype) {
4616  v8::HandleScope handle_scope;
4617  LocalContext context;
4618
4619  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4620  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
4621  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4622  t1->SetHiddenPrototype(true);
4623  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
4624  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
4625  t2->SetHiddenPrototype(true);
4626  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
4627  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
4628  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
4629
4630  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
4631  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
4632  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
4633  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
4634
4635  // Setting the prototype on an object skips hidden prototypes.
4636  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4637  o0->Set(v8_str("__proto__"), o1);
4638  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4639  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4640  o0->Set(v8_str("__proto__"), o2);
4641  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4642  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4643  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
4644  o0->Set(v8_str("__proto__"), o3);
4645  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4646  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4647  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
4648  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
4649
4650  // Getting the prototype of o0 should get the first visible one
4651  // which is o3.  Therefore, z should not be defined on the prototype
4652  // object.
4653  Local<Value> proto = o0->Get(v8_str("__proto__"));
4654  CHECK(proto->IsObject());
4655  CHECK(Local<v8::Object>::Cast(proto)->Get(v8_str("z"))->IsUndefined());
4656}
4657
4658
4659THREADED_TEST(GetterSetterExceptions) {
4660  v8::HandleScope handle_scope;
4661  LocalContext context;
4662  CompileRun(
4663    "function Foo() { };"
4664    "function Throw() { throw 5; };"
4665    "var x = { };"
4666    "x.__defineSetter__('set', Throw);"
4667    "x.__defineGetter__('get', Throw);");
4668  Local<v8::Object> x =
4669      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
4670  v8::TryCatch try_catch;
4671  x->Set(v8_str("set"), v8::Integer::New(8));
4672  x->Get(v8_str("get"));
4673  x->Set(v8_str("set"), v8::Integer::New(8));
4674  x->Get(v8_str("get"));
4675  x->Set(v8_str("set"), v8::Integer::New(8));
4676  x->Get(v8_str("get"));
4677  x->Set(v8_str("set"), v8::Integer::New(8));
4678  x->Get(v8_str("get"));
4679}
4680
4681
4682THREADED_TEST(Constructor) {
4683  v8::HandleScope handle_scope;
4684  LocalContext context;
4685  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4686  templ->SetClassName(v8_str("Fun"));
4687  Local<Function> cons = templ->GetFunction();
4688  context->Global()->Set(v8_str("Fun"), cons);
4689  Local<v8::Object> inst = cons->NewInstance();
4690  i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
4691  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
4692  CHECK(value->BooleanValue());
4693}
4694
4695THREADED_TEST(FunctionDescriptorException) {
4696  v8::HandleScope handle_scope;
4697  LocalContext context;
4698  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4699  templ->SetClassName(v8_str("Fun"));
4700  Local<Function> cons = templ->GetFunction();
4701  context->Global()->Set(v8_str("Fun"), cons);
4702  Local<Value> value = CompileRun(
4703    "function test() {"
4704    "  try {"
4705    "    (new Fun()).blah()"
4706    "  } catch (e) {"
4707    "    var str = String(e);"
4708    "    if (str.indexOf('TypeError') == -1) return 1;"
4709    "    if (str.indexOf('[object Fun]') != -1) return 2;"
4710    "    if (str.indexOf('#<a Fun>') == -1) return 3;"
4711    "    return 0;"
4712    "  }"
4713    "  return 4;"
4714    "}"
4715    "test();");
4716  CHECK_EQ(0, value->Int32Value());
4717}
4718
4719
4720THREADED_TEST(EvalAliasedDynamic) {
4721  v8::HandleScope scope;
4722  LocalContext current;
4723
4724  // Tests where aliased eval can only be resolved dynamically.
4725  Local<Script> script =
4726      Script::Compile(v8_str("function f(x) { "
4727                             "  var foo = 2;"
4728                             "  with (x) { return eval('foo'); }"
4729                             "}"
4730                             "foo = 0;"
4731                             "result1 = f(new Object());"
4732                             "result2 = f(this);"
4733                             "var x = new Object();"
4734                             "x.eval = function(x) { return 1; };"
4735                             "result3 = f(x);"));
4736  script->Run();
4737  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
4738  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
4739  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
4740
4741  v8::TryCatch try_catch;
4742  script =
4743    Script::Compile(v8_str("function f(x) { "
4744                           "  var bar = 2;"
4745                           "  with (x) { return eval('bar'); }"
4746                           "}"
4747                           "f(this)"));
4748  script->Run();
4749  CHECK(try_catch.HasCaught());
4750  try_catch.Reset();
4751}
4752
4753
4754THREADED_TEST(CrossEval) {
4755  v8::HandleScope scope;
4756  LocalContext other;
4757  LocalContext current;
4758
4759  Local<String> token = v8_str("<security token>");
4760  other->SetSecurityToken(token);
4761  current->SetSecurityToken(token);
4762
4763  // Setup reference from current to other.
4764  current->Global()->Set(v8_str("other"), other->Global());
4765
4766  // Check that new variables are introduced in other context.
4767  Local<Script> script =
4768      Script::Compile(v8_str("other.eval('var foo = 1234')"));
4769  script->Run();
4770  Local<Value> foo = other->Global()->Get(v8_str("foo"));
4771  CHECK_EQ(1234, foo->Int32Value());
4772  CHECK(!current->Global()->Has(v8_str("foo")));
4773
4774  // Check that writing to non-existing properties introduces them in
4775  // the other context.
4776  script =
4777      Script::Compile(v8_str("other.eval('na = 1234')"));
4778  script->Run();
4779  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
4780  CHECK(!current->Global()->Has(v8_str("na")));
4781
4782  // Check that global variables in current context are not visible in other
4783  // context.
4784  v8::TryCatch try_catch;
4785  script =
4786      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
4787  Local<Value> result = script->Run();
4788  CHECK(try_catch.HasCaught());
4789  try_catch.Reset();
4790
4791  // Check that local variables in current context are not visible in other
4792  // context.
4793  script =
4794      Script::Compile(v8_str("(function() { "
4795                             "  var baz = 87;"
4796                             "  return other.eval('baz');"
4797                             "})();"));
4798  result = script->Run();
4799  CHECK(try_catch.HasCaught());
4800  try_catch.Reset();
4801
4802  // Check that global variables in the other environment are visible
4803  // when evaluting code.
4804  other->Global()->Set(v8_str("bis"), v8_num(1234));
4805  script = Script::Compile(v8_str("other.eval('bis')"));
4806  CHECK_EQ(1234, script->Run()->Int32Value());
4807  CHECK(!try_catch.HasCaught());
4808
4809  // Check that the 'this' pointer points to the global object evaluating
4810  // code.
4811  other->Global()->Set(v8_str("t"), other->Global());
4812  script = Script::Compile(v8_str("other.eval('this == t')"));
4813  result = script->Run();
4814  CHECK(result->IsTrue());
4815  CHECK(!try_catch.HasCaught());
4816
4817  // Check that variables introduced in with-statement are not visible in
4818  // other context.
4819  script =
4820      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
4821  result = script->Run();
4822  CHECK(try_catch.HasCaught());
4823  try_catch.Reset();
4824
4825  // Check that you cannot use 'eval.call' with another object than the
4826  // current global object.
4827  script =
4828      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
4829  result = script->Run();
4830  CHECK(try_catch.HasCaught());
4831}
4832
4833
4834// Test that calling eval in a context which has been detached from
4835// its global throws an exception.  This behavior is consistent with
4836// other JavaScript implementations.
4837THREADED_TEST(EvalInDetachedGlobal) {
4838  v8::HandleScope scope;
4839
4840  v8::Persistent<Context> context0 = Context::New();
4841  v8::Persistent<Context> context1 = Context::New();
4842
4843  // Setup function in context0 that uses eval from context0.
4844  context0->Enter();
4845  v8::Handle<v8::Value> fun =
4846      CompileRun("var x = 42;"
4847                 "(function() {"
4848                 "  var e = eval;"
4849                 "  return function(s) { return e(s); }"
4850                 "})()");
4851  context0->Exit();
4852
4853  // Put the function into context1 and call it before and after
4854  // detaching the global.  Before detaching, the call succeeds and
4855  // after detaching and exception is thrown.
4856  context1->Enter();
4857  context1->Global()->Set(v8_str("fun"), fun);
4858  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
4859  CHECK_EQ(42, x_value->Int32Value());
4860  context0->DetachGlobal();
4861  v8::TryCatch catcher;
4862  x_value = CompileRun("fun('x')");
4863  CHECK(x_value.IsEmpty());
4864  CHECK(catcher.HasCaught());
4865  context1->Exit();
4866
4867  context1.Dispose();
4868  context0.Dispose();
4869}
4870
4871
4872THREADED_TEST(CrossLazyLoad) {
4873  v8::HandleScope scope;
4874  LocalContext other;
4875  LocalContext current;
4876
4877  Local<String> token = v8_str("<security token>");
4878  other->SetSecurityToken(token);
4879  current->SetSecurityToken(token);
4880
4881  // Setup reference from current to other.
4882  current->Global()->Set(v8_str("other"), other->Global());
4883
4884  // Trigger lazy loading in other context.
4885  Local<Script> script =
4886      Script::Compile(v8_str("other.eval('new Date(42)')"));
4887  Local<Value> value = script->Run();
4888  CHECK_EQ(42.0, value->NumberValue());
4889}
4890
4891
4892static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
4893  ApiTestFuzzer::Fuzz();
4894  if (args.IsConstructCall()) {
4895    if (args[0]->IsInt32()) {
4896       return v8_num(-args[0]->Int32Value());
4897    }
4898  }
4899
4900  return args[0];
4901}
4902
4903
4904// Test that a call handler can be set for objects which will allow
4905// non-function objects created through the API to be called as
4906// functions.
4907THREADED_TEST(CallAsFunction) {
4908  v8::HandleScope scope;
4909  LocalContext context;
4910
4911  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4912  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
4913  instance_template->SetCallAsFunctionHandler(call_as_function);
4914  Local<v8::Object> instance = t->GetFunction()->NewInstance();
4915  context->Global()->Set(v8_str("obj"), instance);
4916  v8::TryCatch try_catch;
4917  Local<Value> value;
4918  CHECK(!try_catch.HasCaught());
4919
4920  value = CompileRun("obj(42)");
4921  CHECK(!try_catch.HasCaught());
4922  CHECK_EQ(42, value->Int32Value());
4923
4924  value = CompileRun("(function(o){return o(49)})(obj)");
4925  CHECK(!try_catch.HasCaught());
4926  CHECK_EQ(49, value->Int32Value());
4927
4928  // test special case of call as function
4929  value = CompileRun("[obj]['0'](45)");
4930  CHECK(!try_catch.HasCaught());
4931  CHECK_EQ(45, value->Int32Value());
4932
4933  value = CompileRun("obj.call = Function.prototype.call;"
4934                     "obj.call(null, 87)");
4935  CHECK(!try_catch.HasCaught());
4936  CHECK_EQ(87, value->Int32Value());
4937
4938  // Regression tests for bug #1116356: Calling call through call/apply
4939  // must work for non-function receivers.
4940  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
4941  value = CompileRun(apply_99);
4942  CHECK(!try_catch.HasCaught());
4943  CHECK_EQ(99, value->Int32Value());
4944
4945  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
4946  value = CompileRun(call_17);
4947  CHECK(!try_catch.HasCaught());
4948  CHECK_EQ(17, value->Int32Value());
4949
4950  // Check that the call-as-function handler can be called through
4951  // new.
4952  value = CompileRun("new obj(43)");
4953  CHECK(!try_catch.HasCaught());
4954  CHECK_EQ(-43, value->Int32Value());
4955}
4956
4957
4958static int CountHandles() {
4959  return v8::HandleScope::NumberOfHandles();
4960}
4961
4962
4963static int Recurse(int depth, int iterations) {
4964  v8::HandleScope scope;
4965  if (depth == 0) return CountHandles();
4966  for (int i = 0; i < iterations; i++) {
4967    Local<v8::Number> n = v8::Integer::New(42);
4968  }
4969  return Recurse(depth - 1, iterations);
4970}
4971
4972
4973THREADED_TEST(HandleIteration) {
4974  static const int kIterations = 500;
4975  static const int kNesting = 200;
4976  CHECK_EQ(0, CountHandles());
4977  {
4978    v8::HandleScope scope1;
4979    CHECK_EQ(0, CountHandles());
4980    for (int i = 0; i < kIterations; i++) {
4981      Local<v8::Number> n = v8::Integer::New(42);
4982      CHECK_EQ(i + 1, CountHandles());
4983    }
4984
4985    CHECK_EQ(kIterations, CountHandles());
4986    {
4987      v8::HandleScope scope2;
4988      for (int j = 0; j < kIterations; j++) {
4989        Local<v8::Number> n = v8::Integer::New(42);
4990        CHECK_EQ(j + 1 + kIterations, CountHandles());
4991      }
4992    }
4993    CHECK_EQ(kIterations, CountHandles());
4994  }
4995  CHECK_EQ(0, CountHandles());
4996  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
4997}
4998
4999
5000static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
5001    Local<String> name,
5002    const AccessorInfo& info) {
5003  ApiTestFuzzer::Fuzz();
5004  return v8::Handle<Value>();
5005}
5006
5007
5008THREADED_TEST(InterceptorHasOwnProperty) {
5009  v8::HandleScope scope;
5010  LocalContext context;
5011  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5012  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5013  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
5014  Local<Function> function = fun_templ->GetFunction();
5015  context->Global()->Set(v8_str("constructor"), function);
5016  v8::Handle<Value> value = CompileRun(
5017      "var o = new constructor();"
5018      "o.hasOwnProperty('ostehaps');");
5019  CHECK_EQ(false, value->BooleanValue());
5020  value = CompileRun(
5021      "o.ostehaps = 42;"
5022      "o.hasOwnProperty('ostehaps');");
5023  CHECK_EQ(true, value->BooleanValue());
5024  value = CompileRun(
5025      "var p = new constructor();"
5026      "p.hasOwnProperty('ostehaps');");
5027  CHECK_EQ(false, value->BooleanValue());
5028}
5029
5030
5031static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
5032    Local<String> name,
5033    const AccessorInfo& info) {
5034  ApiTestFuzzer::Fuzz();
5035  i::Heap::CollectAllGarbage(false);
5036  return v8::Handle<Value>();
5037}
5038
5039
5040THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
5041  v8::HandleScope scope;
5042  LocalContext context;
5043  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5044  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5045  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
5046  Local<Function> function = fun_templ->GetFunction();
5047  context->Global()->Set(v8_str("constructor"), function);
5048  // Let's first make some stuff so we can be sure to get a good GC.
5049  CompileRun(
5050      "function makestr(size) {"
5051      "  switch (size) {"
5052      "    case 1: return 'f';"
5053      "    case 2: return 'fo';"
5054      "    case 3: return 'foo';"
5055      "  }"
5056      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
5057      "}"
5058      "var x = makestr(12345);"
5059      "x = makestr(31415);"
5060      "x = makestr(23456);");
5061  v8::Handle<Value> value = CompileRun(
5062      "var o = new constructor();"
5063      "o.__proto__ = new String(x);"
5064      "o.hasOwnProperty('ostehaps');");
5065  CHECK_EQ(false, value->BooleanValue());
5066}
5067
5068
5069typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
5070                                                 const AccessorInfo& info);
5071
5072
5073static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
5074                                   const char* source,
5075                                   int expected) {
5076  v8::HandleScope scope;
5077  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5078  templ->SetNamedPropertyHandler(getter);
5079  LocalContext context;
5080  context->Global()->Set(v8_str("o"), templ->NewInstance());
5081  v8::Handle<Value> value = CompileRun(source);
5082  CHECK_EQ(expected, value->Int32Value());
5083}
5084
5085
5086static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
5087                                                 const AccessorInfo& info) {
5088  ApiTestFuzzer::Fuzz();
5089  CHECK(v8_str("x")->Equals(name));
5090  return v8::Integer::New(42);
5091}
5092
5093
5094// This test should hit the load IC for the interceptor case.
5095THREADED_TEST(InterceptorLoadIC) {
5096  CheckInterceptorLoadIC(InterceptorLoadICGetter,
5097    "var result = 0;"
5098    "for (var i = 0; i < 1000; i++) {"
5099    "  result = o.x;"
5100    "}",
5101    42);
5102}
5103
5104
5105// Below go several tests which verify that JITing for various
5106// configurations of interceptor and explicit fields works fine
5107// (those cases are special cased to get better performance).
5108
5109static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
5110                                                 const AccessorInfo& info) {
5111  ApiTestFuzzer::Fuzz();
5112  return v8_str("x")->Equals(name)
5113      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
5114}
5115
5116
5117THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
5118  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5119    "var result = 0;"
5120    "o.y = 239;"
5121    "for (var i = 0; i < 1000; i++) {"
5122    "  result = o.y;"
5123    "}",
5124    239);
5125}
5126
5127
5128THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
5129  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5130    "var result = 0;"
5131    "o.__proto__ = { 'y': 239 };"
5132    "for (var i = 0; i < 1000; i++) {"
5133    "  result = o.y + o.x;"
5134    "}",
5135    239 + 42);
5136}
5137
5138
5139THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
5140  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5141    "var result = 0;"
5142    "o.__proto__.y = 239;"
5143    "for (var i = 0; i < 1000; i++) {"
5144    "  result = o.y + o.x;"
5145    "}",
5146    239 + 42);
5147}
5148
5149
5150THREADED_TEST(InterceptorLoadICUndefined) {
5151  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5152    "var result = 0;"
5153    "for (var i = 0; i < 1000; i++) {"
5154    "  result = (o.y == undefined) ? 239 : 42;"
5155    "}",
5156    239);
5157}
5158
5159
5160THREADED_TEST(InterceptorLoadICWithOverride) {
5161  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5162    "fst = new Object();  fst.__proto__ = o;"
5163    "snd = new Object();  snd.__proto__ = fst;"
5164    "var result1 = 0;"
5165    "for (var i = 0; i < 1000;  i++) {"
5166    "  result1 = snd.x;"
5167    "}"
5168    "fst.x = 239;"
5169    "var result = 0;"
5170    "for (var i = 0; i < 1000; i++) {"
5171    "  result = snd.x;"
5172    "}"
5173    "result + result1",
5174    239 + 42);
5175}
5176
5177
5178// Test the case when we stored field into
5179// a stub, but interceptor produced value on its own.
5180THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
5181  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5182    "proto = new Object();"
5183    "o.__proto__ = proto;"
5184    "proto.x = 239;"
5185    "for (var i = 0; i < 1000; i++) {"
5186    "  o.x;"
5187    // Now it should be ICed and keep a reference to x defined on proto
5188    "}"
5189    "var result = 0;"
5190    "for (var i = 0; i < 1000; i++) {"
5191    "  result += o.x;"
5192    "}"
5193    "result;",
5194    42 * 1000);
5195}
5196
5197
5198// Test the case when we stored field into
5199// a stub, but it got invalidated later on.
5200THREADED_TEST(InterceptorLoadICInvalidatedField) {
5201  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5202    "proto1 = new Object();"
5203    "proto2 = new Object();"
5204    "o.__proto__ = proto1;"
5205    "proto1.__proto__ = proto2;"
5206    "proto2.y = 239;"
5207    "for (var i = 0; i < 1000; i++) {"
5208    "  o.y;"
5209    // Now it should be ICed and keep a reference to y defined on proto2
5210    "}"
5211    "proto1.y = 42;"
5212    "var result = 0;"
5213    "for (var i = 0; i < 1000; i++) {"
5214    "  result += o.y;"
5215    "}"
5216    "result;",
5217    42 * 1000);
5218}
5219
5220
5221// Test the case when we stored field into
5222// a stub, but it got invalidated later on due to override on
5223// global object which is between interceptor and fields' holders.
5224THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
5225  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5226    "o.__proto__ = this;"  // set a global to be a proto of o.
5227    "this.__proto__.y = 239;"
5228    "for (var i = 0; i < 10; i++) {"
5229    "  if (o.y != 239) throw 'oops: ' + o.y;"
5230    // Now it should be ICed and keep a reference to y defined on field_holder.
5231    "}"
5232    "this.y = 42;"  // Assign on a global.
5233    "var result = 0;"
5234    "for (var i = 0; i < 10; i++) {"
5235    "  result += o.y;"
5236    "}"
5237    "result;",
5238    42 * 10);
5239}
5240
5241
5242static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
5243  ApiTestFuzzer::Fuzz();
5244  return v8_num(239);
5245}
5246
5247
5248static void SetOnThis(Local<String> name,
5249                      Local<Value> value,
5250                      const AccessorInfo& info) {
5251  info.This()->ForceSet(name, value);
5252}
5253
5254
5255THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
5256  v8::HandleScope scope;
5257  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5258  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5259  templ->SetAccessor(v8_str("y"), Return239);
5260  LocalContext context;
5261  context->Global()->Set(v8_str("o"), templ->NewInstance());
5262  v8::Handle<Value> value = CompileRun(
5263      "var result = 0;"
5264      "for (var i = 0; i < 7; i++) {"
5265      "  result = o.y;"
5266      "}");
5267  CHECK_EQ(239, value->Int32Value());
5268}
5269
5270
5271THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
5272  v8::HandleScope scope;
5273  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5274  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5275  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5276  templ_p->SetAccessor(v8_str("y"), Return239);
5277
5278  LocalContext context;
5279  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5280  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5281
5282  v8::Handle<Value> value = CompileRun(
5283      "o.__proto__ = p;"
5284      "var result = 0;"
5285      "for (var i = 0; i < 7; i++) {"
5286      "  result = o.x + o.y;"
5287      "}");
5288  CHECK_EQ(239 + 42, value->Int32Value());
5289}
5290
5291
5292THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
5293  v8::HandleScope scope;
5294  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5295  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5296  templ->SetAccessor(v8_str("y"), Return239);
5297
5298  LocalContext context;
5299  context->Global()->Set(v8_str("o"), templ->NewInstance());
5300
5301  v8::Handle<Value> value = CompileRun(
5302    "fst = new Object();  fst.__proto__ = o;"
5303    "snd = new Object();  snd.__proto__ = fst;"
5304    "var result1 = 0;"
5305    "for (var i = 0; i < 7;  i++) {"
5306    "  result1 = snd.x;"
5307    "}"
5308    "fst.x = 239;"
5309    "var result = 0;"
5310    "for (var i = 0; i < 7; i++) {"
5311    "  result = snd.x;"
5312    "}"
5313    "result + result1");
5314  CHECK_EQ(239 + 42, value->Int32Value());
5315}
5316
5317
5318// Test the case when we stored callback into
5319// a stub, but interceptor produced value on its own.
5320THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
5321  v8::HandleScope scope;
5322  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5323  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5324  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5325  templ_p->SetAccessor(v8_str("y"), Return239);
5326
5327  LocalContext context;
5328  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5329  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5330
5331  v8::Handle<Value> value = CompileRun(
5332    "o.__proto__ = p;"
5333    "for (var i = 0; i < 7; i++) {"
5334    "  o.x;"
5335    // Now it should be ICed and keep a reference to x defined on p
5336    "}"
5337    "var result = 0;"
5338    "for (var i = 0; i < 7; i++) {"
5339    "  result += o.x;"
5340    "}"
5341    "result");
5342  CHECK_EQ(42 * 7, value->Int32Value());
5343}
5344
5345
5346// Test the case when we stored callback into
5347// a stub, but it got invalidated later on.
5348THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
5349  v8::HandleScope scope;
5350  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5351  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5352  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5353  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
5354
5355  LocalContext context;
5356  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5357  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5358
5359  v8::Handle<Value> value = CompileRun(
5360    "inbetween = new Object();"
5361    "o.__proto__ = inbetween;"
5362    "inbetween.__proto__ = p;"
5363    "for (var i = 0; i < 10; i++) {"
5364    "  o.y;"
5365    // Now it should be ICed and keep a reference to y defined on p
5366    "}"
5367    "inbetween.y = 42;"
5368    "var result = 0;"
5369    "for (var i = 0; i < 10; i++) {"
5370    "  result += o.y;"
5371    "}"
5372    "result");
5373  CHECK_EQ(42 * 10, value->Int32Value());
5374}
5375
5376
5377// Test the case when we stored callback into
5378// a stub, but it got invalidated later on due to override on
5379// global object which is between interceptor and callbacks' holders.
5380THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
5381  v8::HandleScope scope;
5382  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5383  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5384  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5385  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
5386
5387  LocalContext context;
5388  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5389  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5390
5391  v8::Handle<Value> value = CompileRun(
5392    "o.__proto__ = this;"
5393    "this.__proto__ = p;"
5394    "for (var i = 0; i < 10; i++) {"
5395    "  if (o.y != 239) throw 'oops: ' + o.y;"
5396    // Now it should be ICed and keep a reference to y defined on p
5397    "}"
5398    "this.y = 42;"
5399    "var result = 0;"
5400    "for (var i = 0; i < 10; i++) {"
5401    "  result += o.y;"
5402    "}"
5403    "result");
5404  CHECK_EQ(42 * 10, value->Int32Value());
5405}
5406
5407
5408static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
5409                                                  const AccessorInfo& info) {
5410  ApiTestFuzzer::Fuzz();
5411  CHECK(v8_str("x")->Equals(name));
5412  return v8::Integer::New(0);
5413}
5414
5415
5416THREADED_TEST(InterceptorReturningZero) {
5417  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
5418     "o.x == undefined ? 1 : 0",
5419     0);
5420}
5421
5422
5423static v8::Handle<Value> InterceptorStoreICSetter(
5424    Local<String> key, Local<Value> value, const AccessorInfo&) {
5425  CHECK(v8_str("x")->Equals(key));
5426  CHECK_EQ(42, value->Int32Value());
5427  return value;
5428}
5429
5430
5431// This test should hit the store IC for the interceptor case.
5432THREADED_TEST(InterceptorStoreIC) {
5433  v8::HandleScope scope;
5434  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5435  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
5436                                 InterceptorStoreICSetter);
5437  LocalContext context;
5438  context->Global()->Set(v8_str("o"), templ->NewInstance());
5439  v8::Handle<Value> value = CompileRun(
5440    "for (var i = 0; i < 1000; i++) {"
5441    "  o.x = 42;"
5442    "}");
5443}
5444
5445
5446THREADED_TEST(InterceptorStoreICWithNoSetter) {
5447  v8::HandleScope scope;
5448  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5449  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5450  LocalContext context;
5451  context->Global()->Set(v8_str("o"), templ->NewInstance());
5452  v8::Handle<Value> value = CompileRun(
5453    "for (var i = 0; i < 1000; i++) {"
5454    "  o.y = 239;"
5455    "}"
5456    "42 + o.y");
5457  CHECK_EQ(239 + 42, value->Int32Value());
5458}
5459
5460
5461
5462
5463v8::Handle<Value> call_ic_function;
5464v8::Handle<Value> call_ic_function2;
5465v8::Handle<Value> call_ic_function3;
5466
5467static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
5468                                                 const AccessorInfo& info) {
5469  ApiTestFuzzer::Fuzz();
5470  CHECK(v8_str("x")->Equals(name));
5471  return call_ic_function;
5472}
5473
5474
5475// This test should hit the call IC for the interceptor case.
5476THREADED_TEST(InterceptorCallIC) {
5477  v8::HandleScope scope;
5478  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5479  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
5480  LocalContext context;
5481  context->Global()->Set(v8_str("o"), templ->NewInstance());
5482  call_ic_function =
5483      v8_compile("function f(x) { return x + 1; }; f")->Run();
5484  v8::Handle<Value> value = CompileRun(
5485    "var result = 0;"
5486    "for (var i = 0; i < 1000; i++) {"
5487    "  result = o.x(41);"
5488    "}");
5489  CHECK_EQ(42, value->Int32Value());
5490}
5491
5492
5493// This test checks that if interceptor doesn't provide
5494// a value, we can fetch regular value.
5495THREADED_TEST(InterceptorCallICSeesOthers) {
5496  v8::HandleScope scope;
5497  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5498  templ->SetNamedPropertyHandler(NoBlockGetterX);
5499  LocalContext context;
5500  context->Global()->Set(v8_str("o"), templ->NewInstance());
5501  v8::Handle<Value> value = CompileRun(
5502    "o.x = function f(x) { return x + 1; };"
5503    "var result = 0;"
5504    "for (var i = 0; i < 7; i++) {"
5505    "  result = o.x(41);"
5506    "}");
5507  CHECK_EQ(42, value->Int32Value());
5508}
5509
5510
5511static v8::Handle<Value> call_ic_function4;
5512static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
5513                                                  const AccessorInfo& info) {
5514  ApiTestFuzzer::Fuzz();
5515  CHECK(v8_str("x")->Equals(name));
5516  return call_ic_function4;
5517}
5518
5519
5520// This test checks that if interceptor provides a function,
5521// even if we cached shadowed variant, interceptor's function
5522// is invoked
5523THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
5524  v8::HandleScope scope;
5525  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5526  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
5527  LocalContext context;
5528  context->Global()->Set(v8_str("o"), templ->NewInstance());
5529  call_ic_function4 =
5530      v8_compile("function f(x) { return x - 1; }; f")->Run();
5531  v8::Handle<Value> value = CompileRun(
5532    "o.__proto__.x = function(x) { return x + 1; };"
5533    "var result = 0;"
5534    "for (var i = 0; i < 1000; i++) {"
5535    "  result = o.x(42);"
5536    "}");
5537  CHECK_EQ(41, value->Int32Value());
5538}
5539
5540
5541// Test the case when we stored cacheable lookup into
5542// a stub, but it got invalidated later on
5543THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
5544  v8::HandleScope scope;
5545  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5546  templ->SetNamedPropertyHandler(NoBlockGetterX);
5547  LocalContext context;
5548  context->Global()->Set(v8_str("o"), templ->NewInstance());
5549  v8::Handle<Value> value = CompileRun(
5550    "proto1 = new Object();"
5551    "proto2 = new Object();"
5552    "o.__proto__ = proto1;"
5553    "proto1.__proto__ = proto2;"
5554    "proto2.y = function(x) { return x + 1; };"
5555    // Invoke it many times to compile a stub
5556    "for (var i = 0; i < 7; i++) {"
5557    "  o.y(42);"
5558    "}"
5559    "proto1.y = function(x) { return x - 1; };"
5560    "var result = 0;"
5561    "for (var i = 0; i < 7; i++) {"
5562    "  result += o.y(42);"
5563    "}");
5564  CHECK_EQ(41 * 7, value->Int32Value());
5565}
5566
5567
5568static v8::Handle<Value> call_ic_function5;
5569static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
5570                                                  const AccessorInfo& info) {
5571  ApiTestFuzzer::Fuzz();
5572  if (v8_str("x")->Equals(name))
5573    return call_ic_function5;
5574  else
5575    return Local<Value>();
5576}
5577
5578
5579// This test checks that if interceptor doesn't provide a function,
5580// cached constant function is used
5581THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
5582  v8::HandleScope scope;
5583  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5584  templ->SetNamedPropertyHandler(NoBlockGetterX);
5585  LocalContext context;
5586  context->Global()->Set(v8_str("o"), templ->NewInstance());
5587  v8::Handle<Value> value = CompileRun(
5588    "function inc(x) { return x + 1; };"
5589    "inc(1);"
5590    "o.x = inc;"
5591    "var result = 0;"
5592    "for (var i = 0; i < 1000; i++) {"
5593    "  result = o.x(42);"
5594    "}");
5595  CHECK_EQ(43, value->Int32Value());
5596}
5597
5598
5599// This test checks that if interceptor provides a function,
5600// even if we cached constant function, interceptor's function
5601// is invoked
5602THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
5603  v8::HandleScope scope;
5604  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5605  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
5606  LocalContext context;
5607  context->Global()->Set(v8_str("o"), templ->NewInstance());
5608  call_ic_function5 =
5609      v8_compile("function f(x) { return x - 1; }; f")->Run();
5610  v8::Handle<Value> value = CompileRun(
5611    "function inc(x) { return x + 1; };"
5612    "inc(1);"
5613    "o.x = inc;"
5614    "var result = 0;"
5615    "for (var i = 0; i < 1000; i++) {"
5616    "  result = o.x(42);"
5617    "}");
5618  CHECK_EQ(41, value->Int32Value());
5619}
5620
5621
5622// Test the case when we stored constant function into
5623// a stub, but it got invalidated later on
5624THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
5625  v8::HandleScope scope;
5626  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5627  templ->SetNamedPropertyHandler(NoBlockGetterX);
5628  LocalContext context;
5629  context->Global()->Set(v8_str("o"), templ->NewInstance());
5630  v8::Handle<Value> value = CompileRun(
5631    "function inc(x) { return x + 1; };"
5632    "inc(1);"
5633    "proto1 = new Object();"
5634    "proto2 = new Object();"
5635    "o.__proto__ = proto1;"
5636    "proto1.__proto__ = proto2;"
5637    "proto2.y = inc;"
5638    // Invoke it many times to compile a stub
5639    "for (var i = 0; i < 7; i++) {"
5640    "  o.y(42);"
5641    "}"
5642    "proto1.y = function(x) { return x - 1; };"
5643    "var result = 0;"
5644    "for (var i = 0; i < 7; i++) {"
5645    "  result += o.y(42);"
5646    "}");
5647  CHECK_EQ(41 * 7, value->Int32Value());
5648}
5649
5650
5651// Test the case when we stored constant function into
5652// a stub, but it got invalidated later on due to override on
5653// global object which is between interceptor and constant function' holders.
5654THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
5655  v8::HandleScope scope;
5656  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5657  templ->SetNamedPropertyHandler(NoBlockGetterX);
5658  LocalContext context;
5659  context->Global()->Set(v8_str("o"), templ->NewInstance());
5660  v8::Handle<Value> value = CompileRun(
5661    "function inc(x) { return x + 1; };"
5662    "inc(1);"
5663    "o.__proto__ = this;"
5664    "this.__proto__.y = inc;"
5665    // Invoke it many times to compile a stub
5666    "for (var i = 0; i < 7; i++) {"
5667    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
5668    "}"
5669    "this.y = function(x) { return x - 1; };"
5670    "var result = 0;"
5671    "for (var i = 0; i < 7; i++) {"
5672    "  result += o.y(42);"
5673    "}");
5674  CHECK_EQ(41 * 7, value->Int32Value());
5675}
5676
5677
5678static int interceptor_call_count = 0;
5679
5680static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
5681                                                     const AccessorInfo& info) {
5682  ApiTestFuzzer::Fuzz();
5683  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
5684    return call_ic_function2;
5685  }
5686  return v8::Handle<Value>();
5687}
5688
5689
5690// This test should hit load and call ICs for the interceptor case.
5691// Once in a while, the interceptor will reply that a property was not
5692// found in which case we should get a reference error.
5693THREADED_TEST(InterceptorICReferenceErrors) {
5694  v8::HandleScope scope;
5695  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5696  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
5697  LocalContext context(0, templ, v8::Handle<Value>());
5698  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
5699  v8::Handle<Value> value = CompileRun(
5700    "function f() {"
5701    "  for (var i = 0; i < 1000; i++) {"
5702    "    try { x; } catch(e) { return true; }"
5703    "  }"
5704    "  return false;"
5705    "};"
5706    "f();");
5707  CHECK_EQ(true, value->BooleanValue());
5708  interceptor_call_count = 0;
5709  value = CompileRun(
5710    "function g() {"
5711    "  for (var i = 0; i < 1000; i++) {"
5712    "    try { x(42); } catch(e) { return true; }"
5713    "  }"
5714    "  return false;"
5715    "};"
5716    "g();");
5717  CHECK_EQ(true, value->BooleanValue());
5718}
5719
5720
5721static int interceptor_ic_exception_get_count = 0;
5722
5723static v8::Handle<Value> InterceptorICExceptionGetter(
5724    Local<String> name,
5725    const AccessorInfo& info) {
5726  ApiTestFuzzer::Fuzz();
5727  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
5728    return call_ic_function3;
5729  }
5730  if (interceptor_ic_exception_get_count == 20) {
5731    return v8::ThrowException(v8_num(42));
5732  }
5733  // Do not handle get for properties other than x.
5734  return v8::Handle<Value>();
5735}
5736
5737// Test interceptor load/call IC where the interceptor throws an
5738// exception once in a while.
5739THREADED_TEST(InterceptorICGetterExceptions) {
5740  interceptor_ic_exception_get_count = 0;
5741  v8::HandleScope scope;
5742  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5743  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
5744  LocalContext context(0, templ, v8::Handle<Value>());
5745  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
5746  v8::Handle<Value> value = CompileRun(
5747    "function f() {"
5748    "  for (var i = 0; i < 100; i++) {"
5749    "    try { x; } catch(e) { return true; }"
5750    "  }"
5751    "  return false;"
5752    "};"
5753    "f();");
5754  CHECK_EQ(true, value->BooleanValue());
5755  interceptor_ic_exception_get_count = 0;
5756  value = CompileRun(
5757    "function f() {"
5758    "  for (var i = 0; i < 100; i++) {"
5759    "    try { x(42); } catch(e) { return true; }"
5760    "  }"
5761    "  return false;"
5762    "};"
5763    "f();");
5764  CHECK_EQ(true, value->BooleanValue());
5765}
5766
5767
5768static int interceptor_ic_exception_set_count = 0;
5769
5770static v8::Handle<Value> InterceptorICExceptionSetter(
5771      Local<String> key, Local<Value> value, const AccessorInfo&) {
5772  ApiTestFuzzer::Fuzz();
5773  if (++interceptor_ic_exception_set_count > 20) {
5774    return v8::ThrowException(v8_num(42));
5775  }
5776  // Do not actually handle setting.
5777  return v8::Handle<Value>();
5778}
5779
5780// Test interceptor store IC where the interceptor throws an exception
5781// once in a while.
5782THREADED_TEST(InterceptorICSetterExceptions) {
5783  interceptor_ic_exception_set_count = 0;
5784  v8::HandleScope scope;
5785  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5786  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
5787  LocalContext context(0, templ, v8::Handle<Value>());
5788  v8::Handle<Value> value = CompileRun(
5789    "function f() {"
5790    "  for (var i = 0; i < 100; i++) {"
5791    "    try { x = 42; } catch(e) { return true; }"
5792    "  }"
5793    "  return false;"
5794    "};"
5795    "f();");
5796  CHECK_EQ(true, value->BooleanValue());
5797}
5798
5799
5800// Test that we ignore null interceptors.
5801THREADED_TEST(NullNamedInterceptor) {
5802  v8::HandleScope scope;
5803  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5804  templ->SetNamedPropertyHandler(0);
5805  LocalContext context;
5806  templ->Set("x", v8_num(42));
5807  v8::Handle<v8::Object> obj = templ->NewInstance();
5808  context->Global()->Set(v8_str("obj"), obj);
5809  v8::Handle<Value> value = CompileRun("obj.x");
5810  CHECK(value->IsInt32());
5811  CHECK_EQ(42, value->Int32Value());
5812}
5813
5814
5815// Test that we ignore null interceptors.
5816THREADED_TEST(NullIndexedInterceptor) {
5817  v8::HandleScope scope;
5818  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5819  templ->SetIndexedPropertyHandler(0);
5820  LocalContext context;
5821  templ->Set("42", v8_num(42));
5822  v8::Handle<v8::Object> obj = templ->NewInstance();
5823  context->Global()->Set(v8_str("obj"), obj);
5824  v8::Handle<Value> value = CompileRun("obj[42]");
5825  CHECK(value->IsInt32());
5826  CHECK_EQ(42, value->Int32Value());
5827}
5828
5829
5830static v8::Handle<Value> ParentGetter(Local<String> name,
5831                                      const AccessorInfo& info) {
5832  ApiTestFuzzer::Fuzz();
5833  return v8_num(1);
5834}
5835
5836
5837static v8::Handle<Value> ChildGetter(Local<String> name,
5838                                     const AccessorInfo& info) {
5839  ApiTestFuzzer::Fuzz();
5840  return v8_num(42);
5841}
5842
5843
5844THREADED_TEST(Overriding) {
5845  v8::HandleScope scope;
5846  LocalContext context;
5847
5848  // Parent template.
5849  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
5850  Local<ObjectTemplate> parent_instance_templ =
5851      parent_templ->InstanceTemplate();
5852  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
5853
5854  // Template that inherits from the parent template.
5855  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
5856  Local<ObjectTemplate> child_instance_templ =
5857      child_templ->InstanceTemplate();
5858  child_templ->Inherit(parent_templ);
5859  // Override 'f'.  The child version of 'f' should get called for child
5860  // instances.
5861  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
5862  // Add 'g' twice.  The 'g' added last should get called for instances.
5863  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
5864  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
5865
5866  // Add 'h' as an accessor to the proto template with ReadOnly attributes
5867  // so 'h' can be shadowed on the instance object.
5868  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
5869  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
5870      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
5871
5872  // Add 'i' as an accessor to the instance template with ReadOnly attributes
5873  // but the attribute does not have effect because it is duplicated with
5874  // NULL setter.
5875  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
5876      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
5877
5878
5879
5880  // Instantiate the child template.
5881  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
5882
5883  // Check that the child function overrides the parent one.
5884  context->Global()->Set(v8_str("o"), instance);
5885  Local<Value> value = v8_compile("o.f")->Run();
5886  // Check that the 'g' that was added last is hit.
5887  CHECK_EQ(42, value->Int32Value());
5888  value = v8_compile("o.g")->Run();
5889  CHECK_EQ(42, value->Int32Value());
5890
5891  // Check 'h' can be shadowed.
5892  value = v8_compile("o.h = 3; o.h")->Run();
5893  CHECK_EQ(3, value->Int32Value());
5894
5895  // Check 'i' is cannot be shadowed or changed.
5896  value = v8_compile("o.i = 3; o.i")->Run();
5897  CHECK_EQ(42, value->Int32Value());
5898}
5899
5900
5901static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
5902  ApiTestFuzzer::Fuzz();
5903  if (args.IsConstructCall()) {
5904    return v8::Boolean::New(true);
5905  }
5906  return v8::Boolean::New(false);
5907}
5908
5909
5910THREADED_TEST(IsConstructCall) {
5911  v8::HandleScope scope;
5912
5913  // Function template with call handler.
5914  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5915  templ->SetCallHandler(IsConstructHandler);
5916
5917  LocalContext context;
5918
5919  context->Global()->Set(v8_str("f"), templ->GetFunction());
5920  Local<Value> value = v8_compile("f()")->Run();
5921  CHECK(!value->BooleanValue());
5922  value = v8_compile("new f()")->Run();
5923  CHECK(value->BooleanValue());
5924}
5925
5926
5927THREADED_TEST(ObjectProtoToString) {
5928  v8::HandleScope scope;
5929  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5930  templ->SetClassName(v8_str("MyClass"));
5931
5932  LocalContext context;
5933
5934  Local<String> customized_tostring = v8_str("customized toString");
5935
5936  // Replace Object.prototype.toString
5937  v8_compile("Object.prototype.toString = function() {"
5938                  "  return 'customized toString';"
5939                  "}")->Run();
5940
5941  // Normal ToString call should call replaced Object.prototype.toString
5942  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
5943  Local<String> value = instance->ToString();
5944  CHECK(value->IsString() && value->Equals(customized_tostring));
5945
5946  // ObjectProtoToString should not call replace toString function.
5947  value = instance->ObjectProtoToString();
5948  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
5949
5950  // Check global
5951  value = context->Global()->ObjectProtoToString();
5952  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
5953
5954  // Check ordinary object
5955  Local<Value> object = v8_compile("new Object()")->Run();
5956  value = Local<v8::Object>::Cast(object)->ObjectProtoToString();
5957  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
5958}
5959
5960
5961bool ApiTestFuzzer::fuzzing_ = false;
5962v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
5963  v8::internal::OS::CreateSemaphore(0);
5964int ApiTestFuzzer::active_tests_;
5965int ApiTestFuzzer::tests_being_run_;
5966int ApiTestFuzzer::current_;
5967
5968
5969// We are in a callback and want to switch to another thread (if we
5970// are currently running the thread fuzzing test).
5971void ApiTestFuzzer::Fuzz() {
5972  if (!fuzzing_) return;
5973  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
5974  test->ContextSwitch();
5975}
5976
5977
5978// Let the next thread go.  Since it is also waiting on the V8 lock it may
5979// not start immediately.
5980bool ApiTestFuzzer::NextThread() {
5981  int test_position = GetNextTestNumber();
5982  const char* test_name = RegisterThreadedTest::nth(current_)->name();
5983  if (test_position == current_) {
5984    if (kLogThreading)
5985      printf("Stay with %s\n", test_name);
5986    return false;
5987  }
5988  if (kLogThreading) {
5989    printf("Switch from %s to %s\n",
5990           test_name,
5991           RegisterThreadedTest::nth(test_position)->name());
5992  }
5993  current_ = test_position;
5994  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
5995  return true;
5996}
5997
5998
5999void ApiTestFuzzer::Run() {
6000  // When it is our turn...
6001  gate_->Wait();
6002  {
6003    // ... get the V8 lock and start running the test.
6004    v8::Locker locker;
6005    CallTest();
6006  }
6007  // This test finished.
6008  active_ = false;
6009  active_tests_--;
6010  // If it was the last then signal that fact.
6011  if (active_tests_ == 0) {
6012    all_tests_done_->Signal();
6013  } else {
6014    // Otherwise select a new test and start that.
6015    NextThread();
6016  }
6017}
6018
6019
6020static unsigned linear_congruential_generator;
6021
6022
6023void ApiTestFuzzer::Setup(PartOfTest part) {
6024  linear_congruential_generator = i::FLAG_testing_prng_seed;
6025  fuzzing_ = true;
6026  int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
6027  int end = (part == FIRST_PART)
6028      ? (RegisterThreadedTest::count() >> 1)
6029      : RegisterThreadedTest::count();
6030  active_tests_ = tests_being_run_ = end - start;
6031  for (int i = 0; i < tests_being_run_; i++) {
6032    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
6033  }
6034  for (int i = 0; i < active_tests_; i++) {
6035    RegisterThreadedTest::nth(i)->fuzzer_->Start();
6036  }
6037}
6038
6039
6040static void CallTestNumber(int test_number) {
6041  (RegisterThreadedTest::nth(test_number)->callback())();
6042}
6043
6044
6045void ApiTestFuzzer::RunAllTests() {
6046  // Set off the first test.
6047  current_ = -1;
6048  NextThread();
6049  // Wait till they are all done.
6050  all_tests_done_->Wait();
6051}
6052
6053
6054int ApiTestFuzzer::GetNextTestNumber() {
6055  int next_test;
6056  do {
6057    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
6058    linear_congruential_generator *= 1664525u;
6059    linear_congruential_generator += 1013904223u;
6060  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
6061  return next_test;
6062}
6063
6064
6065void ApiTestFuzzer::ContextSwitch() {
6066  // If the new thread is the same as the current thread there is nothing to do.
6067  if (NextThread()) {
6068    // Now it can start.
6069    v8::Unlocker unlocker;
6070    // Wait till someone starts us again.
6071    gate_->Wait();
6072    // And we're off.
6073  }
6074}
6075
6076
6077void ApiTestFuzzer::TearDown() {
6078  fuzzing_ = false;
6079  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
6080    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
6081    if (fuzzer != NULL) fuzzer->Join();
6082  }
6083}
6084
6085
6086// Lets not be needlessly self-referential.
6087TEST(Threading) {
6088  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
6089  ApiTestFuzzer::RunAllTests();
6090  ApiTestFuzzer::TearDown();
6091}
6092
6093TEST(Threading2) {
6094  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
6095  ApiTestFuzzer::RunAllTests();
6096  ApiTestFuzzer::TearDown();
6097}
6098
6099
6100void ApiTestFuzzer::CallTest() {
6101  if (kLogThreading)
6102    printf("Start test %d\n", test_number_);
6103  CallTestNumber(test_number_);
6104  if (kLogThreading)
6105    printf("End test %d\n", test_number_);
6106}
6107
6108
6109static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
6110  CHECK(v8::Locker::IsLocked());
6111  ApiTestFuzzer::Fuzz();
6112  v8::Unlocker unlocker;
6113  const char* code = "throw 7;";
6114  {
6115    v8::Locker nested_locker;
6116    v8::HandleScope scope;
6117    v8::Handle<Value> exception;
6118    { v8::TryCatch try_catch;
6119      v8::Handle<Value> value = CompileRun(code);
6120      CHECK(value.IsEmpty());
6121      CHECK(try_catch.HasCaught());
6122      // Make sure to wrap the exception in a new handle because
6123      // the handle returned from the TryCatch is destroyed
6124      // when the TryCatch is destroyed.
6125      exception = Local<Value>::New(try_catch.Exception());
6126    }
6127    return v8::ThrowException(exception);
6128  }
6129}
6130
6131
6132static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
6133  CHECK(v8::Locker::IsLocked());
6134  ApiTestFuzzer::Fuzz();
6135  v8::Unlocker unlocker;
6136  const char* code = "throw 7;";
6137  {
6138    v8::Locker nested_locker;
6139    v8::HandleScope scope;
6140    v8::Handle<Value> value = CompileRun(code);
6141    CHECK(value.IsEmpty());
6142    return v8_str("foo");
6143  }
6144}
6145
6146
6147// These are locking tests that don't need to be run again
6148// as part of the locking aggregation tests.
6149TEST(NestedLockers) {
6150  v8::Locker locker;
6151  CHECK(v8::Locker::IsLocked());
6152  v8::HandleScope scope;
6153  LocalContext env;
6154  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
6155  Local<Function> fun = fun_templ->GetFunction();
6156  env->Global()->Set(v8_str("throw_in_js"), fun);
6157  Local<Script> script = v8_compile("(function () {"
6158                                    "  try {"
6159                                    "    throw_in_js();"
6160                                    "    return 42;"
6161                                    "  } catch (e) {"
6162                                    "    return e * 13;"
6163                                    "  }"
6164                                    "})();");
6165  CHECK_EQ(91, script->Run()->Int32Value());
6166}
6167
6168
6169// These are locking tests that don't need to be run again
6170// as part of the locking aggregation tests.
6171TEST(NestedLockersNoTryCatch) {
6172  v8::Locker locker;
6173  v8::HandleScope scope;
6174  LocalContext env;
6175  Local<v8::FunctionTemplate> fun_templ =
6176      v8::FunctionTemplate::New(ThrowInJSNoCatch);
6177  Local<Function> fun = fun_templ->GetFunction();
6178  env->Global()->Set(v8_str("throw_in_js"), fun);
6179  Local<Script> script = v8_compile("(function () {"
6180                                    "  try {"
6181                                    "    throw_in_js();"
6182                                    "    return 42;"
6183                                    "  } catch (e) {"
6184                                    "    return e * 13;"
6185                                    "  }"
6186                                    "})();");
6187  CHECK_EQ(91, script->Run()->Int32Value());
6188}
6189
6190
6191THREADED_TEST(RecursiveLocking) {
6192  v8::Locker locker;
6193  {
6194    v8::Locker locker2;
6195    CHECK(v8::Locker::IsLocked());
6196  }
6197}
6198
6199
6200static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
6201  ApiTestFuzzer::Fuzz();
6202  v8::Unlocker unlocker;
6203  return v8::Undefined();
6204}
6205
6206
6207THREADED_TEST(LockUnlockLock) {
6208  {
6209    v8::Locker locker;
6210    v8::HandleScope scope;
6211    LocalContext env;
6212    Local<v8::FunctionTemplate> fun_templ =
6213        v8::FunctionTemplate::New(UnlockForAMoment);
6214    Local<Function> fun = fun_templ->GetFunction();
6215    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
6216    Local<Script> script = v8_compile("(function () {"
6217                                      "  unlock_for_a_moment();"
6218                                      "  return 42;"
6219                                      "})();");
6220    CHECK_EQ(42, script->Run()->Int32Value());
6221  }
6222  {
6223    v8::Locker locker;
6224    v8::HandleScope scope;
6225    LocalContext env;
6226    Local<v8::FunctionTemplate> fun_templ =
6227        v8::FunctionTemplate::New(UnlockForAMoment);
6228    Local<Function> fun = fun_templ->GetFunction();
6229    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
6230    Local<Script> script = v8_compile("(function () {"
6231                                      "  unlock_for_a_moment();"
6232                                      "  return 42;"
6233                                      "})();");
6234    CHECK_EQ(42, script->Run()->Int32Value());
6235  }
6236}
6237
6238
6239static int GetGlobalObjectsCount() {
6240  int count = 0;
6241  v8::internal::HeapIterator it;
6242  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
6243    if (object->IsJSGlobalObject()) count++;
6244  return count;
6245}
6246
6247
6248static int GetSurvivingGlobalObjectsCount() {
6249  // We need to collect all garbage twice to be sure that everything
6250  // has been collected.  This is because inline caches are cleared in
6251  // the first garbage collection but some of the maps have already
6252  // been marked at that point.  Therefore some of the maps are not
6253  // collected until the second garbage collection.
6254  v8::internal::Heap::CollectAllGarbage(false);
6255  v8::internal::Heap::CollectAllGarbage(false);
6256  int count = GetGlobalObjectsCount();
6257#ifdef DEBUG
6258  if (count > 0) v8::internal::Heap::TracePathToGlobal();
6259#endif
6260  return count;
6261}
6262
6263
6264TEST(DontLeakGlobalObjects) {
6265  // Regression test for issues 1139850 and 1174891.
6266
6267  v8::V8::Initialize();
6268
6269  int count = GetSurvivingGlobalObjectsCount();
6270
6271  for (int i = 0; i < 5; i++) {
6272    { v8::HandleScope scope;
6273      LocalContext context;
6274    }
6275    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6276
6277    { v8::HandleScope scope;
6278      LocalContext context;
6279      v8_compile("Date")->Run();
6280    }
6281    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6282
6283    { v8::HandleScope scope;
6284      LocalContext context;
6285      v8_compile("/aaa/")->Run();
6286    }
6287    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6288
6289    { v8::HandleScope scope;
6290      const char* extension_list[] = { "v8/gc" };
6291      v8::ExtensionConfiguration extensions(1, extension_list);
6292      LocalContext context(&extensions);
6293      v8_compile("gc();")->Run();
6294    }
6295    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6296  }
6297}
6298
6299
6300v8::Persistent<v8::Object> some_object;
6301v8::Persistent<v8::Object> bad_handle;
6302
6303void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
6304  v8::HandleScope scope;
6305  bad_handle = v8::Persistent<v8::Object>::New(some_object);
6306}
6307
6308
6309THREADED_TEST(NewPersistentHandleFromWeakCallback) {
6310  LocalContext context;
6311
6312  v8::Persistent<v8::Object> handle1, handle2;
6313  {
6314    v8::HandleScope scope;
6315    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
6316    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
6317    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
6318  }
6319  // Note: order is implementation dependent alas: currently
6320  // global handle nodes are processed by PostGarbageCollectionProcessing
6321  // in reverse allocation order, so if second allocated handle is deleted,
6322  // weak callback of the first handle would be able to 'reallocate' it.
6323  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
6324  handle2.Dispose();
6325  i::Heap::CollectAllGarbage(false);
6326}
6327
6328
6329v8::Persistent<v8::Object> to_be_disposed;
6330
6331void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
6332  to_be_disposed.Dispose();
6333  i::Heap::CollectAllGarbage(false);
6334}
6335
6336
6337THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
6338  LocalContext context;
6339
6340  v8::Persistent<v8::Object> handle1, handle2;
6341  {
6342    v8::HandleScope scope;
6343    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
6344    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
6345  }
6346  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
6347  to_be_disposed = handle2;
6348  i::Heap::CollectAllGarbage(false);
6349}
6350
6351void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
6352  handle.Dispose();
6353}
6354
6355void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
6356  v8::HandleScope scope;
6357  v8::Persistent<v8::Object>::New(v8::Object::New());
6358}
6359
6360
6361THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
6362  LocalContext context;
6363
6364  v8::Persistent<v8::Object> handle1, handle2, handle3;
6365  {
6366    v8::HandleScope scope;
6367    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
6368    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
6369    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
6370  }
6371  handle2.MakeWeak(NULL, DisposingCallback);
6372  handle3.MakeWeak(NULL, HandleCreatingCallback);
6373  i::Heap::CollectAllGarbage(false);
6374}
6375
6376
6377THREADED_TEST(CheckForCrossContextObjectLiterals) {
6378  v8::V8::Initialize();
6379
6380  const int nof = 2;
6381  const char* sources[nof] = {
6382    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
6383    "Object()"
6384  };
6385
6386  for (int i = 0; i < nof; i++) {
6387    const char* source = sources[i];
6388    { v8::HandleScope scope;
6389      LocalContext context;
6390      CompileRun(source);
6391    }
6392    { v8::HandleScope scope;
6393      LocalContext context;
6394      CompileRun(source);
6395    }
6396  }
6397}
6398
6399
6400static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
6401  v8::HandleScope inner;
6402  env->Enter();
6403  v8::Handle<Value> three = v8_num(3);
6404  v8::Handle<Value> value = inner.Close(three);
6405  env->Exit();
6406  return value;
6407}
6408
6409
6410THREADED_TEST(NestedHandleScopeAndContexts) {
6411  v8::HandleScope outer;
6412  v8::Persistent<Context> env = Context::New();
6413  env->Enter();
6414  v8::Handle<Value> value = NestedScope(env);
6415  v8::Handle<String> str = value->ToString();
6416  env->Exit();
6417  env.Dispose();
6418}
6419
6420
6421THREADED_TEST(ExternalAllocatedMemory) {
6422  v8::HandleScope outer;
6423  v8::Persistent<Context> env = Context::New();
6424  const int kSize = 1024*1024;
6425  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
6426  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
6427}
6428
6429
6430THREADED_TEST(DisposeEnteredContext) {
6431  v8::HandleScope scope;
6432  LocalContext outer;
6433  { v8::Persistent<v8::Context> inner = v8::Context::New();
6434    inner->Enter();
6435    inner.Dispose();
6436    inner.Clear();
6437    inner->Exit();
6438  }
6439}
6440
6441
6442// Regression test for issue 54, object templates with internal fields
6443// but no accessors or interceptors did not get their internal field
6444// count set on instances.
6445THREADED_TEST(Regress54) {
6446  v8::HandleScope outer;
6447  LocalContext context;
6448  static v8::Persistent<v8::ObjectTemplate> templ;
6449  if (templ.IsEmpty()) {
6450    v8::HandleScope inner;
6451    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
6452    local->SetInternalFieldCount(1);
6453    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
6454  }
6455  v8::Handle<v8::Object> result = templ->NewInstance();
6456  CHECK_EQ(1, result->InternalFieldCount());
6457}
6458
6459
6460// If part of the threaded tests, this test makes ThreadingTest fail
6461// on mac.
6462TEST(CatchStackOverflow) {
6463  v8::HandleScope scope;
6464  LocalContext context;
6465  v8::TryCatch try_catch;
6466  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
6467    "function f() {"
6468    "  return f();"
6469    "}"
6470    ""
6471    "f();"));
6472  v8::Handle<v8::Value> result = script->Run();
6473  CHECK(result.IsEmpty());
6474}
6475
6476
6477static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
6478                                    const char* resource_name,
6479                                    int line_offset) {
6480  v8::HandleScope scope;
6481  v8::TryCatch try_catch;
6482  v8::Handle<v8::Value> result = script->Run();
6483  CHECK(result.IsEmpty());
6484  CHECK(try_catch.HasCaught());
6485  v8::Handle<v8::Message> message = try_catch.Message();
6486  CHECK(!message.IsEmpty());
6487  CHECK_EQ(10 + line_offset, message->GetLineNumber());
6488  CHECK_EQ(91, message->GetStartPosition());
6489  CHECK_EQ(92, message->GetEndPosition());
6490  CHECK_EQ(2, message->GetStartColumn());
6491  CHECK_EQ(3, message->GetEndColumn());
6492  v8::String::AsciiValue line(message->GetSourceLine());
6493  CHECK_EQ("  throw 'nirk';", *line);
6494  v8::String::AsciiValue name(message->GetScriptResourceName());
6495  CHECK_EQ(resource_name, *name);
6496}
6497
6498
6499THREADED_TEST(TryCatchSourceInfo) {
6500  v8::HandleScope scope;
6501  LocalContext context;
6502  v8::Handle<v8::String> source = v8::String::New(
6503      "function Foo() {\n"
6504      "  return Bar();\n"
6505      "}\n"
6506      "\n"
6507      "function Bar() {\n"
6508      "  return Baz();\n"
6509      "}\n"
6510      "\n"
6511      "function Baz() {\n"
6512      "  throw 'nirk';\n"
6513      "}\n"
6514      "\n"
6515      "Foo();\n");
6516
6517  const char* resource_name;
6518  v8::Handle<v8::Script> script;
6519  resource_name = "test.js";
6520  script = v8::Script::Compile(source, v8::String::New(resource_name));
6521  CheckTryCatchSourceInfo(script, resource_name, 0);
6522
6523  resource_name = "test1.js";
6524  v8::ScriptOrigin origin1(v8::String::New(resource_name));
6525  script = v8::Script::Compile(source, &origin1);
6526  CheckTryCatchSourceInfo(script, resource_name, 0);
6527
6528  resource_name = "test2.js";
6529  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
6530  script = v8::Script::Compile(source, &origin2);
6531  CheckTryCatchSourceInfo(script, resource_name, 7);
6532}
6533
6534
6535THREADED_TEST(CompilationCache) {
6536  v8::HandleScope scope;
6537  LocalContext context;
6538  v8::Handle<v8::String> source0 = v8::String::New("1234");
6539  v8::Handle<v8::String> source1 = v8::String::New("1234");
6540  v8::Handle<v8::Script> script0 =
6541      v8::Script::Compile(source0, v8::String::New("test.js"));
6542  v8::Handle<v8::Script> script1 =
6543      v8::Script::Compile(source1, v8::String::New("test.js"));
6544  v8::Handle<v8::Script> script2 =
6545      v8::Script::Compile(source0);  // different origin
6546  CHECK_EQ(1234, script0->Run()->Int32Value());
6547  CHECK_EQ(1234, script1->Run()->Int32Value());
6548  CHECK_EQ(1234, script2->Run()->Int32Value());
6549}
6550
6551
6552static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
6553  ApiTestFuzzer::Fuzz();
6554  return v8_num(42);
6555}
6556
6557
6558THREADED_TEST(CallbackFunctionName) {
6559  v8::HandleScope scope;
6560  LocalContext context;
6561  Local<ObjectTemplate> t = ObjectTemplate::New();
6562  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
6563  context->Global()->Set(v8_str("obj"), t->NewInstance());
6564  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
6565  CHECK(value->IsString());
6566  v8::String::AsciiValue name(value);
6567  CHECK_EQ("asdf", *name);
6568}
6569
6570
6571THREADED_TEST(DateAccess) {
6572  v8::HandleScope scope;
6573  LocalContext context;
6574  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
6575  CHECK(date->IsDate());
6576  CHECK_EQ(1224744689038.0, v8::Handle<v8::Date>::Cast(date)->NumberValue());
6577}
6578
6579
6580void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
6581  v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
6582  v8::Handle<v8::Array> props = obj->GetPropertyNames();
6583  CHECK_EQ(elmc, props->Length());
6584  for (int i = 0; i < elmc; i++) {
6585    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
6586    CHECK_EQ(elmv[i], *elm);
6587  }
6588}
6589
6590
6591THREADED_TEST(PropertyEnumeration) {
6592  v8::HandleScope scope;
6593  LocalContext context;
6594  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
6595      "var result = [];"
6596      "result[0] = {};"
6597      "result[1] = {a: 1, b: 2};"
6598      "result[2] = [1, 2, 3];"
6599      "var proto = {x: 1, y: 2, z: 3};"
6600      "var x = { __proto__: proto, w: 0, z: 1 };"
6601      "result[3] = x;"
6602      "result;"))->Run();
6603  v8::Handle<v8::Array> elms = v8::Handle<v8::Array>::Cast(obj);
6604  CHECK_EQ(4, elms->Length());
6605  int elmc0 = 0;
6606  const char** elmv0 = NULL;
6607  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
6608  int elmc1 = 2;
6609  const char* elmv1[] = {"a", "b"};
6610  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
6611  int elmc2 = 3;
6612  const char* elmv2[] = {"0", "1", "2"};
6613  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
6614  int elmc3 = 4;
6615  const char* elmv3[] = {"w", "z", "x", "y"};
6616  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
6617}
6618
6619
6620static bool NamedSetAccessBlocker(Local<v8::Object> obj,
6621                                  Local<Value> name,
6622                                  v8::AccessType type,
6623                                  Local<Value> data) {
6624  return type != v8::ACCESS_SET;
6625}
6626
6627
6628static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
6629                                    uint32_t key,
6630                                    v8::AccessType type,
6631                                    Local<Value> data) {
6632  return type != v8::ACCESS_SET;
6633}
6634
6635
6636THREADED_TEST(DisableAccessChecksWhileConfiguring) {
6637  v8::HandleScope scope;
6638  LocalContext context;
6639  Local<ObjectTemplate> templ = ObjectTemplate::New();
6640  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
6641                                 IndexedSetAccessBlocker);
6642  templ->Set(v8_str("x"), v8::True());
6643  Local<v8::Object> instance = templ->NewInstance();
6644  context->Global()->Set(v8_str("obj"), instance);
6645  Local<Value> value = CompileRun("obj.x");
6646  CHECK(value->BooleanValue());
6647}
6648
6649
6650static bool NamedGetAccessBlocker(Local<v8::Object> obj,
6651                                  Local<Value> name,
6652                                  v8::AccessType type,
6653                                  Local<Value> data) {
6654  return false;
6655}
6656
6657
6658static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
6659                                    uint32_t key,
6660                                    v8::AccessType type,
6661                                    Local<Value> data) {
6662  return false;
6663}
6664
6665
6666
6667THREADED_TEST(AccessChecksReenabledCorrectly) {
6668  v8::HandleScope scope;
6669  LocalContext context;
6670  Local<ObjectTemplate> templ = ObjectTemplate::New();
6671  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
6672                                 IndexedGetAccessBlocker);
6673  templ->Set(v8_str("a"), v8_str("a"));
6674  // Add more than 8 (see kMaxFastProperties) properties
6675  // so that the constructor will force copying map.
6676  // Cannot sprintf, gcc complains unsafety.
6677  char buf[4];
6678  for (char i = '0'; i <= '9' ; i++) {
6679    buf[0] = i;
6680    for (char j = '0'; j <= '9'; j++) {
6681      buf[1] = j;
6682      for (char k = '0'; k <= '9'; k++) {
6683        buf[2] = k;
6684        buf[3] = 0;
6685        templ->Set(v8_str(buf), v8::Number::New(k));
6686      }
6687    }
6688  }
6689
6690  Local<v8::Object> instance_1 = templ->NewInstance();
6691  context->Global()->Set(v8_str("obj_1"), instance_1);
6692
6693  Local<Value> value_1 = CompileRun("obj_1.a");
6694  CHECK(value_1->IsUndefined());
6695
6696  Local<v8::Object> instance_2 = templ->NewInstance();
6697  context->Global()->Set(v8_str("obj_2"), instance_2);
6698
6699  Local<Value> value_2 = CompileRun("obj_2.a");
6700  CHECK(value_2->IsUndefined());
6701}
6702
6703
6704// This tests that access check information remains on the global
6705// object template when creating contexts.
6706THREADED_TEST(AccessControlRepeatedContextCreation) {
6707  v8::HandleScope handle_scope;
6708  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6709  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
6710                                           IndexedSetAccessBlocker);
6711  i::Handle<i::ObjectTemplateInfo> internal_template =
6712      v8::Utils::OpenHandle(*global_template);
6713  CHECK(!internal_template->constructor()->IsUndefined());
6714  i::Handle<i::FunctionTemplateInfo> constructor(
6715      i::FunctionTemplateInfo::cast(internal_template->constructor()));
6716  CHECK(!constructor->access_check_info()->IsUndefined());
6717  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6718  CHECK(!constructor->access_check_info()->IsUndefined());
6719}
6720
6721
6722THREADED_TEST(TurnOnAccessCheck) {
6723  v8::HandleScope handle_scope;
6724
6725  // Create an environment with access check to the global object disabled by
6726  // default.
6727  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6728  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
6729                                           IndexedGetAccessBlocker,
6730                                           v8::Handle<v8::Value>(),
6731                                           false);
6732  v8::Persistent<Context> context = Context::New(NULL, global_template);
6733  Context::Scope context_scope(context);
6734
6735  // Set up a property and a number of functions.
6736  context->Global()->Set(v8_str("a"), v8_num(1));
6737  CompileRun("function f1() {return a;}"
6738             "function f2() {return a;}"
6739             "function g1() {return h();}"
6740             "function g2() {return h();}"
6741             "function h() {return 1;}");
6742  Local<Function> f1 =
6743      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
6744  Local<Function> f2 =
6745      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
6746  Local<Function> g1 =
6747      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
6748  Local<Function> g2 =
6749      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
6750  Local<Function> h =
6751      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
6752
6753  // Get the global object.
6754  v8::Handle<v8::Object> global = context->Global();
6755
6756  // Call f1 one time and f2 a number of times. This will ensure that f1 still
6757  // uses the runtime system to retreive property a whereas f2 uses global load
6758  // inline cache.
6759  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
6760  for (int i = 0; i < 4; i++) {
6761    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
6762  }
6763
6764  // Same for g1 and g2.
6765  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
6766  for (int i = 0; i < 4; i++) {
6767    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
6768  }
6769
6770  // Detach the global and turn on access check.
6771  context->DetachGlobal();
6772  context->Global()->TurnOnAccessCheck();
6773
6774  // Failing access check to property get results in undefined.
6775  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
6776  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
6777
6778  // Failing access check to function call results in exception.
6779  CHECK(g1->Call(global, 0, NULL).IsEmpty());
6780  CHECK(g2->Call(global, 0, NULL).IsEmpty());
6781
6782  // No failing access check when just returning a constant.
6783  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
6784}
6785
6786
6787// This test verifies that pre-compilation (aka preparsing) can be called
6788// without initializing the whole VM. Thus we cannot run this test in a
6789// multi-threaded setup.
6790TEST(PreCompile) {
6791  // TODO(155): This test would break without the initialization of V8. This is
6792  // a workaround for now to make this test not fail.
6793  v8::V8::Initialize();
6794  const char *script = "function foo(a) { return a+1; }";
6795  v8::ScriptData *sd =
6796      v8::ScriptData::PreCompile(script, i::StrLength(script));
6797  CHECK_NE(sd->Length(), 0);
6798  CHECK_NE(sd->Data(), NULL);
6799  CHECK(!sd->HasError());
6800  delete sd;
6801}
6802
6803
6804TEST(PreCompileWithError) {
6805  v8::V8::Initialize();
6806  const char *script = "function foo(a) { return 1 * * 2; }";
6807  v8::ScriptData *sd =
6808      v8::ScriptData::PreCompile(script, i::StrLength(script));
6809  CHECK(sd->HasError());
6810  delete sd;
6811}
6812
6813
6814TEST(Regress31661) {
6815  v8::V8::Initialize();
6816  const char *script = " The Definintive Guide";
6817  v8::ScriptData *sd =
6818      v8::ScriptData::PreCompile(script, i::StrLength(script));
6819  CHECK(sd->HasError());
6820  delete sd;
6821}
6822
6823
6824// This tests that we do not allow dictionary load/call inline caches
6825// to use functions that have not yet been compiled.  The potential
6826// problem of loading a function that has not yet been compiled can
6827// arise because we share code between contexts via the compilation
6828// cache.
6829THREADED_TEST(DictionaryICLoadedFunction) {
6830  v8::HandleScope scope;
6831  // Test LoadIC.
6832  for (int i = 0; i < 2; i++) {
6833    LocalContext context;
6834    context->Global()->Set(v8_str("tmp"), v8::True());
6835    context->Global()->Delete(v8_str("tmp"));
6836    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
6837  }
6838  // Test CallIC.
6839  for (int i = 0; i < 2; i++) {
6840    LocalContext context;
6841    context->Global()->Set(v8_str("tmp"), v8::True());
6842    context->Global()->Delete(v8_str("tmp"));
6843    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
6844  }
6845}
6846
6847
6848// Test that cross-context new calls use the context of the callee to
6849// create the new JavaScript object.
6850THREADED_TEST(CrossContextNew) {
6851  v8::HandleScope scope;
6852  v8::Persistent<Context> context0 = Context::New();
6853  v8::Persistent<Context> context1 = Context::New();
6854
6855  // Allow cross-domain access.
6856  Local<String> token = v8_str("<security token>");
6857  context0->SetSecurityToken(token);
6858  context1->SetSecurityToken(token);
6859
6860  // Set an 'x' property on the Object prototype and define a
6861  // constructor function in context0.
6862  context0->Enter();
6863  CompileRun("Object.prototype.x = 42; function C() {};");
6864  context0->Exit();
6865
6866  // Call the constructor function from context0 and check that the
6867  // result has the 'x' property.
6868  context1->Enter();
6869  context1->Global()->Set(v8_str("other"), context0->Global());
6870  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
6871  CHECK(value->IsInt32());
6872  CHECK_EQ(42, value->Int32Value());
6873  context1->Exit();
6874
6875  // Dispose the contexts to allow them to be garbage collected.
6876  context0.Dispose();
6877  context1.Dispose();
6878}
6879
6880
6881class RegExpInterruptTest {
6882 public:
6883  RegExpInterruptTest() : block_(NULL) {}
6884  ~RegExpInterruptTest() { delete block_; }
6885  void RunTest() {
6886    block_ = i::OS::CreateSemaphore(0);
6887    gc_count_ = 0;
6888    gc_during_regexp_ = 0;
6889    regexp_success_ = false;
6890    gc_success_ = false;
6891    GCThread gc_thread(this);
6892    gc_thread.Start();
6893    v8::Locker::StartPreemption(1);
6894
6895    LongRunningRegExp();
6896    {
6897      v8::Unlocker unlock;
6898      gc_thread.Join();
6899    }
6900    v8::Locker::StopPreemption();
6901    CHECK(regexp_success_);
6902    CHECK(gc_success_);
6903  }
6904 private:
6905  // Number of garbage collections required.
6906  static const int kRequiredGCs = 5;
6907
6908  class GCThread : public i::Thread {
6909   public:
6910    explicit GCThread(RegExpInterruptTest* test)
6911        : test_(test) {}
6912    virtual void Run() {
6913      test_->CollectGarbage();
6914    }
6915   private:
6916     RegExpInterruptTest* test_;
6917  };
6918
6919  void CollectGarbage() {
6920    block_->Wait();
6921    while (gc_during_regexp_ < kRequiredGCs) {
6922      {
6923        v8::Locker lock;
6924        // TODO(lrn): Perhaps create some garbage before collecting.
6925        i::Heap::CollectAllGarbage(false);
6926        gc_count_++;
6927      }
6928      i::OS::Sleep(1);
6929    }
6930    gc_success_ = true;
6931  }
6932
6933  void LongRunningRegExp() {
6934    block_->Signal();  // Enable garbage collection thread on next preemption.
6935    int rounds = 0;
6936    while (gc_during_regexp_ < kRequiredGCs) {
6937      int gc_before = gc_count_;
6938      {
6939        // Match 15-30 "a"'s against 14 and a "b".
6940        const char* c_source =
6941            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
6942            ".exec('aaaaaaaaaaaaaaab') === null";
6943        Local<String> source = String::New(c_source);
6944        Local<Script> script = Script::Compile(source);
6945        Local<Value> result = script->Run();
6946        if (!result->BooleanValue()) {
6947          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
6948          return;
6949        }
6950      }
6951      {
6952        // Match 15-30 "a"'s against 15 and a "b".
6953        const char* c_source =
6954            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
6955            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
6956        Local<String> source = String::New(c_source);
6957        Local<Script> script = Script::Compile(source);
6958        Local<Value> result = script->Run();
6959        if (!result->BooleanValue()) {
6960          gc_during_regexp_ = kRequiredGCs;
6961          return;
6962        }
6963      }
6964      int gc_after = gc_count_;
6965      gc_during_regexp_ += gc_after - gc_before;
6966      rounds++;
6967      i::OS::Sleep(1);
6968    }
6969    regexp_success_ = true;
6970  }
6971
6972  i::Semaphore* block_;
6973  int gc_count_;
6974  int gc_during_regexp_;
6975  bool regexp_success_;
6976  bool gc_success_;
6977};
6978
6979
6980// Test that a regular expression execution can be interrupted and
6981// survive a garbage collection.
6982TEST(RegExpInterruption) {
6983  v8::Locker lock;
6984  v8::V8::Initialize();
6985  v8::HandleScope scope;
6986  Local<Context> local_env;
6987  {
6988    LocalContext env;
6989    local_env = env.local();
6990  }
6991
6992  // Local context should still be live.
6993  CHECK(!local_env.IsEmpty());
6994  local_env->Enter();
6995
6996  // Should complete without problems.
6997  RegExpInterruptTest().RunTest();
6998
6999  local_env->Exit();
7000}
7001
7002
7003class ApplyInterruptTest {
7004 public:
7005  ApplyInterruptTest() : block_(NULL) {}
7006  ~ApplyInterruptTest() { delete block_; }
7007  void RunTest() {
7008    block_ = i::OS::CreateSemaphore(0);
7009    gc_count_ = 0;
7010    gc_during_apply_ = 0;
7011    apply_success_ = false;
7012    gc_success_ = false;
7013    GCThread gc_thread(this);
7014    gc_thread.Start();
7015    v8::Locker::StartPreemption(1);
7016
7017    LongRunningApply();
7018    {
7019      v8::Unlocker unlock;
7020      gc_thread.Join();
7021    }
7022    v8::Locker::StopPreemption();
7023    CHECK(apply_success_);
7024    CHECK(gc_success_);
7025  }
7026 private:
7027  // Number of garbage collections required.
7028  static const int kRequiredGCs = 2;
7029
7030  class GCThread : public i::Thread {
7031   public:
7032    explicit GCThread(ApplyInterruptTest* test)
7033        : test_(test) {}
7034    virtual void Run() {
7035      test_->CollectGarbage();
7036    }
7037   private:
7038     ApplyInterruptTest* test_;
7039  };
7040
7041  void CollectGarbage() {
7042    block_->Wait();
7043    while (gc_during_apply_ < kRequiredGCs) {
7044      {
7045        v8::Locker lock;
7046        i::Heap::CollectAllGarbage(false);
7047        gc_count_++;
7048      }
7049      i::OS::Sleep(1);
7050    }
7051    gc_success_ = true;
7052  }
7053
7054  void LongRunningApply() {
7055    block_->Signal();
7056    int rounds = 0;
7057    while (gc_during_apply_ < kRequiredGCs) {
7058      int gc_before = gc_count_;
7059      {
7060        const char* c_source =
7061            "function do_very_little(bar) {"
7062            "  this.foo = bar;"
7063            "}"
7064            "for (var i = 0; i < 100000; i++) {"
7065            "  do_very_little.apply(this, ['bar']);"
7066            "}";
7067        Local<String> source = String::New(c_source);
7068        Local<Script> script = Script::Compile(source);
7069        Local<Value> result = script->Run();
7070        // Check that no exception was thrown.
7071        CHECK(!result.IsEmpty());
7072      }
7073      int gc_after = gc_count_;
7074      gc_during_apply_ += gc_after - gc_before;
7075      rounds++;
7076    }
7077    apply_success_ = true;
7078  }
7079
7080  i::Semaphore* block_;
7081  int gc_count_;
7082  int gc_during_apply_;
7083  bool apply_success_;
7084  bool gc_success_;
7085};
7086
7087
7088// Test that nothing bad happens if we get a preemption just when we were
7089// about to do an apply().
7090TEST(ApplyInterruption) {
7091  v8::Locker lock;
7092  v8::V8::Initialize();
7093  v8::HandleScope scope;
7094  Local<Context> local_env;
7095  {
7096    LocalContext env;
7097    local_env = env.local();
7098  }
7099
7100  // Local context should still be live.
7101  CHECK(!local_env.IsEmpty());
7102  local_env->Enter();
7103
7104  // Should complete without problems.
7105  ApplyInterruptTest().RunTest();
7106
7107  local_env->Exit();
7108}
7109
7110
7111// Verify that we can clone an object
7112TEST(ObjectClone) {
7113  v8::HandleScope scope;
7114  LocalContext env;
7115
7116  const char* sample =
7117    "var rv = {};"      \
7118    "rv.alpha = 'hello';" \
7119    "rv.beta = 123;"     \
7120    "rv;";
7121
7122  // Create an object, verify basics.
7123  Local<Value> val = CompileRun(sample);
7124  CHECK(val->IsObject());
7125  Local<v8::Object> obj = Local<v8::Object>::Cast(val);
7126  obj->Set(v8_str("gamma"), v8_str("cloneme"));
7127
7128  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
7129  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
7130  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
7131
7132  // Clone it.
7133  Local<v8::Object> clone = obj->Clone();
7134  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
7135  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
7136  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
7137
7138  // Set a property on the clone, verify each object.
7139  clone->Set(v8_str("beta"), v8::Integer::New(456));
7140  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
7141  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
7142}
7143
7144
7145class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
7146 public:
7147  explicit AsciiVectorResource(i::Vector<const char> vector)
7148      : data_(vector) {}
7149  virtual ~AsciiVectorResource() {}
7150  virtual size_t length() const { return data_.length(); }
7151  virtual const char* data() const { return data_.start(); }
7152 private:
7153  i::Vector<const char> data_;
7154};
7155
7156
7157class UC16VectorResource : public v8::String::ExternalStringResource {
7158 public:
7159  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
7160      : data_(vector) {}
7161  virtual ~UC16VectorResource() {}
7162  virtual size_t length() const { return data_.length(); }
7163  virtual const i::uc16* data() const { return data_.start(); }
7164 private:
7165  i::Vector<const i::uc16> data_;
7166};
7167
7168
7169static void MorphAString(i::String* string,
7170                         AsciiVectorResource* ascii_resource,
7171                         UC16VectorResource* uc16_resource) {
7172  CHECK(i::StringShape(string).IsExternal());
7173  if (string->IsAsciiRepresentation()) {
7174    // Check old map is not symbol or long.
7175    CHECK(string->map() == i::Heap::external_ascii_string_map());
7176    // Morph external string to be TwoByte string.
7177    string->set_map(i::Heap::external_string_map());
7178    i::ExternalTwoByteString* morphed =
7179         i::ExternalTwoByteString::cast(string);
7180    morphed->set_resource(uc16_resource);
7181  } else {
7182    // Check old map is not symbol or long.
7183    CHECK(string->map() == i::Heap::external_string_map());
7184    // Morph external string to be ASCII string.
7185    string->set_map(i::Heap::external_ascii_string_map());
7186    i::ExternalAsciiString* morphed =
7187         i::ExternalAsciiString::cast(string);
7188    morphed->set_resource(ascii_resource);
7189  }
7190}
7191
7192
7193// Test that we can still flatten a string if the components it is built up
7194// from have been turned into 16 bit strings in the mean time.
7195THREADED_TEST(MorphCompositeStringTest) {
7196  const char* c_string = "Now is the time for all good men"
7197                         " to come to the aid of the party";
7198  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
7199  {
7200    v8::HandleScope scope;
7201    LocalContext env;
7202    AsciiVectorResource ascii_resource(
7203        i::Vector<const char>(c_string, i::StrLength(c_string)));
7204    UC16VectorResource uc16_resource(
7205        i::Vector<const uint16_t>(two_byte_string,
7206                                  i::StrLength(c_string)));
7207
7208    Local<String> lhs(v8::Utils::ToLocal(
7209        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
7210    Local<String> rhs(v8::Utils::ToLocal(
7211        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
7212
7213    env->Global()->Set(v8_str("lhs"), lhs);
7214    env->Global()->Set(v8_str("rhs"), rhs);
7215
7216    CompileRun(
7217        "var cons = lhs + rhs;"
7218        "var slice = lhs.substring(1, lhs.length - 1);"
7219        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
7220
7221    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
7222    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
7223
7224    // Now do some stuff to make sure the strings are flattened, etc.
7225    CompileRun(
7226        "/[^a-z]/.test(cons);"
7227        "/[^a-z]/.test(slice);"
7228        "/[^a-z]/.test(slice_on_cons);");
7229    const char* expected_cons =
7230        "Now is the time for all good men to come to the aid of the party"
7231        "Now is the time for all good men to come to the aid of the party";
7232    const char* expected_slice =
7233        "ow is the time for all good men to come to the aid of the part";
7234    const char* expected_slice_on_cons =
7235        "ow is the time for all good men to come to the aid of the party"
7236        "Now is the time for all good men to come to the aid of the part";
7237    CHECK_EQ(String::New(expected_cons),
7238             env->Global()->Get(v8_str("cons")));
7239    CHECK_EQ(String::New(expected_slice),
7240             env->Global()->Get(v8_str("slice")));
7241    CHECK_EQ(String::New(expected_slice_on_cons),
7242             env->Global()->Get(v8_str("slice_on_cons")));
7243  }
7244}
7245
7246
7247TEST(CompileExternalTwoByteSource) {
7248  v8::HandleScope scope;
7249  LocalContext context;
7250
7251  // This is a very short list of sources, which currently is to check for a
7252  // regression caused by r2703.
7253  const char* ascii_sources[] = {
7254    "0.5",
7255    "-0.5",   // This mainly testes PushBack in the Scanner.
7256    "--0.5",  // This mainly testes PushBack in the Scanner.
7257    NULL
7258  };
7259
7260  // Compile the sources as external two byte strings.
7261  for (int i = 0; ascii_sources[i] != NULL; i++) {
7262    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
7263    UC16VectorResource uc16_resource(
7264        i::Vector<const uint16_t>(two_byte_string,
7265                                  i::StrLength(ascii_sources[i])));
7266    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
7267    v8::Script::Compile(source);
7268  }
7269}
7270
7271
7272class RegExpStringModificationTest {
7273 public:
7274  RegExpStringModificationTest()
7275      : block_(i::OS::CreateSemaphore(0)),
7276        morphs_(0),
7277        morphs_during_regexp_(0),
7278        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
7279        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
7280  ~RegExpStringModificationTest() { delete block_; }
7281  void RunTest() {
7282    regexp_success_ = false;
7283    morph_success_ = false;
7284
7285    // Initialize the contents of two_byte_content_ to be a uc16 representation
7286    // of "aaaaaaaaaaaaaab".
7287    for (int i = 0; i < 14; i++) {
7288      two_byte_content_[i] = 'a';
7289    }
7290    two_byte_content_[14] = 'b';
7291
7292    // Create the input string for the regexp - the one we are going to change
7293    // properties of.
7294    input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
7295
7296    // Inject the input as a global variable.
7297    i::Handle<i::String> input_name =
7298        i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
7299    i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
7300
7301
7302    MorphThread morph_thread(this);
7303    morph_thread.Start();
7304    v8::Locker::StartPreemption(1);
7305    LongRunningRegExp();
7306    {
7307      v8::Unlocker unlock;
7308      morph_thread.Join();
7309    }
7310    v8::Locker::StopPreemption();
7311    CHECK(regexp_success_);
7312    CHECK(morph_success_);
7313  }
7314 private:
7315
7316  // Number of string modifications required.
7317  static const int kRequiredModifications = 5;
7318  static const int kMaxModifications = 100;
7319
7320  class MorphThread : public i::Thread {
7321   public:
7322    explicit MorphThread(RegExpStringModificationTest* test)
7323        : test_(test) {}
7324    virtual void Run() {
7325      test_->MorphString();
7326    }
7327   private:
7328     RegExpStringModificationTest* test_;
7329  };
7330
7331  void MorphString() {
7332    block_->Wait();
7333    while (morphs_during_regexp_ < kRequiredModifications &&
7334           morphs_ < kMaxModifications) {
7335      {
7336        v8::Locker lock;
7337        // Swap string between ascii and two-byte representation.
7338        i::String* string = *input_;
7339        MorphAString(string, &ascii_resource_, &uc16_resource_);
7340        morphs_++;
7341      }
7342      i::OS::Sleep(1);
7343    }
7344    morph_success_ = true;
7345  }
7346
7347  void LongRunningRegExp() {
7348    block_->Signal();  // Enable morphing thread on next preemption.
7349    while (morphs_during_regexp_ < kRequiredModifications &&
7350           morphs_ < kMaxModifications) {
7351      int morphs_before = morphs_;
7352      {
7353        // Match 15-30 "a"'s against 14 and a "b".
7354        const char* c_source =
7355            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
7356            ".exec(input) === null";
7357        Local<String> source = String::New(c_source);
7358        Local<Script> script = Script::Compile(source);
7359        Local<Value> result = script->Run();
7360        CHECK(result->IsTrue());
7361      }
7362      int morphs_after = morphs_;
7363      morphs_during_regexp_ += morphs_after - morphs_before;
7364    }
7365    regexp_success_ = true;
7366  }
7367
7368  i::uc16 two_byte_content_[15];
7369  i::Semaphore* block_;
7370  int morphs_;
7371  int morphs_during_regexp_;
7372  bool regexp_success_;
7373  bool morph_success_;
7374  i::Handle<i::String> input_;
7375  AsciiVectorResource ascii_resource_;
7376  UC16VectorResource uc16_resource_;
7377};
7378
7379
7380// Test that a regular expression execution can be interrupted and
7381// the string changed without failing.
7382TEST(RegExpStringModification) {
7383  v8::Locker lock;
7384  v8::V8::Initialize();
7385  v8::HandleScope scope;
7386  Local<Context> local_env;
7387  {
7388    LocalContext env;
7389    local_env = env.local();
7390  }
7391
7392  // Local context should still be live.
7393  CHECK(!local_env.IsEmpty());
7394  local_env->Enter();
7395
7396  // Should complete without problems.
7397  RegExpStringModificationTest().RunTest();
7398
7399  local_env->Exit();
7400}
7401
7402
7403// Test that we can set a property on the global object even if there
7404// is a read-only property in the prototype chain.
7405TEST(ReadOnlyPropertyInGlobalProto) {
7406  v8::HandleScope scope;
7407  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7408  LocalContext context(0, templ);
7409  v8::Handle<v8::Object> global = context->Global();
7410  v8::Handle<v8::Object> global_proto =
7411      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
7412  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
7413  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
7414  // Check without 'eval' or 'with'.
7415  v8::Handle<v8::Value> res =
7416      CompileRun("function f() { x = 42; return x; }; f()");
7417  // Check with 'eval'.
7418  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
7419  CHECK_EQ(v8::Integer::New(42), res);
7420  // Check with 'with'.
7421  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
7422  CHECK_EQ(v8::Integer::New(42), res);
7423}
7424
7425static int force_set_set_count = 0;
7426static int force_set_get_count = 0;
7427bool pass_on_get = false;
7428
7429static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
7430                                            const v8::AccessorInfo& info) {
7431  force_set_get_count++;
7432  if (pass_on_get) {
7433    return v8::Handle<v8::Value>();
7434  } else {
7435    return v8::Int32::New(3);
7436  }
7437}
7438
7439static void ForceSetSetter(v8::Local<v8::String> name,
7440                           v8::Local<v8::Value> value,
7441                           const v8::AccessorInfo& info) {
7442  force_set_set_count++;
7443}
7444
7445static v8::Handle<v8::Value> ForceSetInterceptSetter(
7446    v8::Local<v8::String> name,
7447    v8::Local<v8::Value> value,
7448    const v8::AccessorInfo& info) {
7449  force_set_set_count++;
7450  return v8::Undefined();
7451}
7452
7453TEST(ForceSet) {
7454  force_set_get_count = 0;
7455  force_set_set_count = 0;
7456  pass_on_get = false;
7457
7458  v8::HandleScope scope;
7459  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7460  v8::Handle<v8::String> access_property = v8::String::New("a");
7461  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
7462  LocalContext context(NULL, templ);
7463  v8::Handle<v8::Object> global = context->Global();
7464
7465  // Ordinary properties
7466  v8::Handle<v8::String> simple_property = v8::String::New("p");
7467  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
7468  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7469  // This should fail because the property is read-only
7470  global->Set(simple_property, v8::Int32::New(5));
7471  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7472  // This should succeed even though the property is read-only
7473  global->ForceSet(simple_property, v8::Int32::New(6));
7474  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
7475
7476  // Accessors
7477  CHECK_EQ(0, force_set_set_count);
7478  CHECK_EQ(0, force_set_get_count);
7479  CHECK_EQ(3, global->Get(access_property)->Int32Value());
7480  // CHECK_EQ the property shouldn't override it, just call the setter
7481  // which in this case does nothing.
7482  global->Set(access_property, v8::Int32::New(7));
7483  CHECK_EQ(3, global->Get(access_property)->Int32Value());
7484  CHECK_EQ(1, force_set_set_count);
7485  CHECK_EQ(2, force_set_get_count);
7486  // Forcing the property to be set should override the accessor without
7487  // calling it
7488  global->ForceSet(access_property, v8::Int32::New(8));
7489  CHECK_EQ(8, global->Get(access_property)->Int32Value());
7490  CHECK_EQ(1, force_set_set_count);
7491  CHECK_EQ(2, force_set_get_count);
7492}
7493
7494TEST(ForceSetWithInterceptor) {
7495  force_set_get_count = 0;
7496  force_set_set_count = 0;
7497  pass_on_get = false;
7498
7499  v8::HandleScope scope;
7500  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7501  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
7502  LocalContext context(NULL, templ);
7503  v8::Handle<v8::Object> global = context->Global();
7504
7505  v8::Handle<v8::String> some_property = v8::String::New("a");
7506  CHECK_EQ(0, force_set_set_count);
7507  CHECK_EQ(0, force_set_get_count);
7508  CHECK_EQ(3, global->Get(some_property)->Int32Value());
7509  // Setting the property shouldn't override it, just call the setter
7510  // which in this case does nothing.
7511  global->Set(some_property, v8::Int32::New(7));
7512  CHECK_EQ(3, global->Get(some_property)->Int32Value());
7513  CHECK_EQ(1, force_set_set_count);
7514  CHECK_EQ(2, force_set_get_count);
7515  // Getting the property when the interceptor returns an empty handle
7516  // should yield undefined, since the property isn't present on the
7517  // object itself yet.
7518  pass_on_get = true;
7519  CHECK(global->Get(some_property)->IsUndefined());
7520  CHECK_EQ(1, force_set_set_count);
7521  CHECK_EQ(3, force_set_get_count);
7522  // Forcing the property to be set should cause the value to be
7523  // set locally without calling the interceptor.
7524  global->ForceSet(some_property, v8::Int32::New(8));
7525  CHECK_EQ(8, global->Get(some_property)->Int32Value());
7526  CHECK_EQ(1, force_set_set_count);
7527  CHECK_EQ(4, force_set_get_count);
7528  // Reenabling the interceptor should cause it to take precedence over
7529  // the property
7530  pass_on_get = false;
7531  CHECK_EQ(3, global->Get(some_property)->Int32Value());
7532  CHECK_EQ(1, force_set_set_count);
7533  CHECK_EQ(5, force_set_get_count);
7534  // The interceptor should also work for other properties
7535  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
7536  CHECK_EQ(1, force_set_set_count);
7537  CHECK_EQ(6, force_set_get_count);
7538}
7539
7540
7541THREADED_TEST(ForceDelete) {
7542  v8::HandleScope scope;
7543  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7544  LocalContext context(NULL, templ);
7545  v8::Handle<v8::Object> global = context->Global();
7546
7547  // Ordinary properties
7548  v8::Handle<v8::String> simple_property = v8::String::New("p");
7549  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
7550  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7551  // This should fail because the property is dont-delete.
7552  CHECK(!global->Delete(simple_property));
7553  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7554  // This should succeed even though the property is dont-delete.
7555  CHECK(global->ForceDelete(simple_property));
7556  CHECK(global->Get(simple_property)->IsUndefined());
7557}
7558
7559
7560static int force_delete_interceptor_count = 0;
7561static bool pass_on_delete = false;
7562
7563
7564static v8::Handle<v8::Boolean> ForceDeleteDeleter(
7565    v8::Local<v8::String> name,
7566    const v8::AccessorInfo& info) {
7567  force_delete_interceptor_count++;
7568  if (pass_on_delete) {
7569    return v8::Handle<v8::Boolean>();
7570  } else {
7571    return v8::True();
7572  }
7573}
7574
7575
7576THREADED_TEST(ForceDeleteWithInterceptor) {
7577  force_delete_interceptor_count = 0;
7578  pass_on_delete = false;
7579
7580  v8::HandleScope scope;
7581  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7582  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
7583  LocalContext context(NULL, templ);
7584  v8::Handle<v8::Object> global = context->Global();
7585
7586  v8::Handle<v8::String> some_property = v8::String::New("a");
7587  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
7588
7589  // Deleting a property should get intercepted and nothing should
7590  // happen.
7591  CHECK_EQ(0, force_delete_interceptor_count);
7592  CHECK(global->Delete(some_property));
7593  CHECK_EQ(1, force_delete_interceptor_count);
7594  CHECK_EQ(42, global->Get(some_property)->Int32Value());
7595  // Deleting the property when the interceptor returns an empty
7596  // handle should not delete the property since it is DontDelete.
7597  pass_on_delete = true;
7598  CHECK(!global->Delete(some_property));
7599  CHECK_EQ(2, force_delete_interceptor_count);
7600  CHECK_EQ(42, global->Get(some_property)->Int32Value());
7601  // Forcing the property to be deleted should delete the value
7602  // without calling the interceptor.
7603  CHECK(global->ForceDelete(some_property));
7604  CHECK(global->Get(some_property)->IsUndefined());
7605  CHECK_EQ(2, force_delete_interceptor_count);
7606}
7607
7608
7609// Make sure that forcing a delete invalidates any IC stubs, so we
7610// don't read the hole value.
7611THREADED_TEST(ForceDeleteIC) {
7612  v8::HandleScope scope;
7613  LocalContext context;
7614  // Create a DontDelete variable on the global object.
7615  CompileRun("this.__proto__ = { foo: 'horse' };"
7616             "var foo = 'fish';"
7617             "function f() { return foo.length; }");
7618  // Initialize the IC for foo in f.
7619  CompileRun("for (var i = 0; i < 4; i++) f();");
7620  // Make sure the value of foo is correct before the deletion.
7621  CHECK_EQ(4, CompileRun("f()")->Int32Value());
7622  // Force the deletion of foo.
7623  CHECK(context->Global()->ForceDelete(v8_str("foo")));
7624  // Make sure the value for foo is read from the prototype, and that
7625  // we don't get in trouble with reading the deleted cell value
7626  // sentinel.
7627  CHECK_EQ(5, CompileRun("f()")->Int32Value());
7628}
7629
7630
7631v8::Persistent<Context> calling_context0;
7632v8::Persistent<Context> calling_context1;
7633v8::Persistent<Context> calling_context2;
7634
7635
7636// Check that the call to the callback is initiated in
7637// calling_context2, the directly calling context is calling_context1
7638// and the callback itself is in calling_context0.
7639static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
7640  ApiTestFuzzer::Fuzz();
7641  CHECK(Context::GetCurrent() == calling_context0);
7642  CHECK(Context::GetCalling() == calling_context1);
7643  CHECK(Context::GetEntered() == calling_context2);
7644  return v8::Integer::New(42);
7645}
7646
7647
7648THREADED_TEST(GetCallingContext) {
7649  v8::HandleScope scope;
7650
7651  calling_context0 = Context::New();
7652  calling_context1 = Context::New();
7653  calling_context2 = Context::New();
7654
7655  // Allow cross-domain access.
7656  Local<String> token = v8_str("<security token>");
7657  calling_context0->SetSecurityToken(token);
7658  calling_context1->SetSecurityToken(token);
7659  calling_context2->SetSecurityToken(token);
7660
7661  // Create an object with a C++ callback in context0.
7662  calling_context0->Enter();
7663  Local<v8::FunctionTemplate> callback_templ =
7664      v8::FunctionTemplate::New(GetCallingContextCallback);
7665  calling_context0->Global()->Set(v8_str("callback"),
7666                                  callback_templ->GetFunction());
7667  calling_context0->Exit();
7668
7669  // Expose context0 in context1 and setup a function that calls the
7670  // callback function.
7671  calling_context1->Enter();
7672  calling_context1->Global()->Set(v8_str("context0"),
7673                                  calling_context0->Global());
7674  CompileRun("function f() { context0.callback() }");
7675  calling_context1->Exit();
7676
7677  // Expose context1 in context2 and call the callback function in
7678  // context0 indirectly through f in context1.
7679  calling_context2->Enter();
7680  calling_context2->Global()->Set(v8_str("context1"),
7681                                  calling_context1->Global());
7682  CompileRun("context1.f()");
7683  calling_context2->Exit();
7684
7685  // Dispose the contexts to allow them to be garbage collected.
7686  calling_context0.Dispose();
7687  calling_context1.Dispose();
7688  calling_context2.Dispose();
7689  calling_context0.Clear();
7690  calling_context1.Clear();
7691  calling_context2.Clear();
7692}
7693
7694
7695// Check that a variable declaration with no explicit initialization
7696// value does not shadow an existing property in the prototype chain.
7697//
7698// This is consistent with Firefox and Safari.
7699//
7700// See http://crbug.com/12548.
7701THREADED_TEST(InitGlobalVarInProtoChain) {
7702  v8::HandleScope scope;
7703  LocalContext context;
7704  // Introduce a variable in the prototype chain.
7705  CompileRun("__proto__.x = 42");
7706  v8::Handle<v8::Value> result = CompileRun("var x; x");
7707  CHECK(!result->IsUndefined());
7708  CHECK_EQ(42, result->Int32Value());
7709}
7710
7711
7712// Regression test for issue 398.
7713// If a function is added to an object, creating a constant function
7714// field, and the result is cloned, replacing the constant function on the
7715// original should not affect the clone.
7716// See http://code.google.com/p/v8/issues/detail?id=398
7717THREADED_TEST(ReplaceConstantFunction) {
7718  v8::HandleScope scope;
7719  LocalContext context;
7720  v8::Handle<v8::Object> obj = v8::Object::New();
7721  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
7722  v8::Handle<v8::String> foo_string = v8::String::New("foo");
7723  obj->Set(foo_string, func_templ->GetFunction());
7724  v8::Handle<v8::Object> obj_clone = obj->Clone();
7725  obj_clone->Set(foo_string, v8::String::New("Hello"));
7726  CHECK(!obj->Get(foo_string)->IsUndefined());
7727}
7728
7729
7730// Regression test for http://crbug.com/16276.
7731THREADED_TEST(Regress16276) {
7732  v8::HandleScope scope;
7733  LocalContext context;
7734  // Force the IC in f to be a dictionary load IC.
7735  CompileRun("function f(obj) { return obj.x; }\n"
7736             "var obj = { x: { foo: 42 }, y: 87 };\n"
7737             "var x = obj.x;\n"
7738             "delete obj.y;\n"
7739             "for (var i = 0; i < 5; i++) f(obj);");
7740  // Detach the global object to make 'this' refer directly to the
7741  // global object (not the proxy), and make sure that the dictionary
7742  // load IC doesn't mess up loading directly from the global object.
7743  context->DetachGlobal();
7744  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
7745}
7746
7747
7748THREADED_TEST(PixelArray) {
7749  v8::HandleScope scope;
7750  LocalContext context;
7751  const int kElementCount = 260;
7752  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
7753  i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
7754                                                              pixel_data);
7755  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
7756  for (int i = 0; i < kElementCount; i++) {
7757    pixels->set(i, i % 256);
7758  }
7759  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
7760  for (int i = 0; i < kElementCount; i++) {
7761    CHECK_EQ(i % 256, pixels->get(i));
7762    CHECK_EQ(i % 256, pixel_data[i]);
7763  }
7764
7765  v8::Handle<v8::Object> obj = v8::Object::New();
7766  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
7767  // Set the elements to be the pixels.
7768  // jsobj->set_elements(*pixels);
7769  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
7770  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
7771  obj->Set(v8_str("field"), v8::Int32::New(1503));
7772  context->Global()->Set(v8_str("pixels"), obj);
7773  v8::Handle<v8::Value> result = CompileRun("pixels.field");
7774  CHECK_EQ(1503, result->Int32Value());
7775  result = CompileRun("pixels[1]");
7776  CHECK_EQ(1, result->Int32Value());
7777
7778  result = CompileRun("var sum = 0;"
7779                      "for (var i = 0; i < 8; i++) {"
7780                      "  sum += pixels[i] = pixels[i] = -i;"
7781                      "}"
7782                      "sum;");
7783  CHECK_EQ(-28, result->Int32Value());
7784
7785  result = CompileRun("var sum = 0;"
7786                      "for (var i = 0; i < 8; i++) {"
7787                      "  sum += pixels[i] = pixels[i] = 0;"
7788                      "}"
7789                      "sum;");
7790  CHECK_EQ(0, result->Int32Value());
7791
7792  result = CompileRun("var sum = 0;"
7793                      "for (var i = 0; i < 8; i++) {"
7794                      "  sum += pixels[i] = pixels[i] = 255;"
7795                      "}"
7796                      "sum;");
7797  CHECK_EQ(8 * 255, result->Int32Value());
7798
7799  result = CompileRun("var sum = 0;"
7800                      "for (var i = 0; i < 8; i++) {"
7801                      "  sum += pixels[i] = pixels[i] = 256 + i;"
7802                      "}"
7803                      "sum;");
7804  CHECK_EQ(2076, result->Int32Value());
7805
7806  result = CompileRun("var sum = 0;"
7807                      "for (var i = 0; i < 8; i++) {"
7808                      "  sum += pixels[i] = pixels[i] = i;"
7809                      "}"
7810                      "sum;");
7811  CHECK_EQ(28, result->Int32Value());
7812
7813  result = CompileRun("var sum = 0;"
7814                      "for (var i = 0; i < 8; i++) {"
7815                      "  sum += pixels[i];"
7816                      "}"
7817                      "sum;");
7818  CHECK_EQ(28, result->Int32Value());
7819
7820  i::Handle<i::Smi> value(i::Smi::FromInt(2));
7821  i::SetElement(jsobj, 1, value);
7822  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
7823  *value.location() = i::Smi::FromInt(256);
7824  i::SetElement(jsobj, 1, value);
7825  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
7826  *value.location() = i::Smi::FromInt(-1);
7827  i::SetElement(jsobj, 1, value);
7828  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
7829
7830  result = CompileRun("for (var i = 0; i < 8; i++) {"
7831                      "  pixels[i] = (i * 65) - 109;"
7832                      "}"
7833                      "pixels[1] + pixels[6];");
7834  CHECK_EQ(255, result->Int32Value());
7835  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
7836  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
7837  CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
7838  CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
7839  CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
7840  CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
7841  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
7842  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
7843  result = CompileRun("var sum = 0;"
7844                      "for (var i = 0; i < 8; i++) {"
7845                      "  sum += pixels[i];"
7846                      "}"
7847                      "sum;");
7848  CHECK_EQ(984, result->Int32Value());
7849
7850  result = CompileRun("for (var i = 0; i < 8; i++) {"
7851                      "  pixels[i] = (i * 1.1);"
7852                      "}"
7853                      "pixels[1] + pixels[6];");
7854  CHECK_EQ(8, result->Int32Value());
7855  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
7856  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
7857  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
7858  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
7859  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
7860  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
7861  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
7862  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
7863
7864  result = CompileRun("for (var i = 0; i < 8; i++) {"
7865                      "  pixels[7] = undefined;"
7866                      "}"
7867                      "pixels[7];");
7868  CHECK_EQ(0, result->Int32Value());
7869  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
7870
7871  result = CompileRun("for (var i = 0; i < 8; i++) {"
7872                      "  pixels[6] = '2.3';"
7873                      "}"
7874                      "pixels[6];");
7875  CHECK_EQ(2, result->Int32Value());
7876  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
7877
7878  result = CompileRun("for (var i = 0; i < 8; i++) {"
7879                      "  pixels[5] = NaN;"
7880                      "}"
7881                      "pixels[5];");
7882  CHECK_EQ(0, result->Int32Value());
7883  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
7884
7885  result = CompileRun("for (var i = 0; i < 8; i++) {"
7886                      "  pixels[8] = Infinity;"
7887                      "}"
7888                      "pixels[8];");
7889  CHECK_EQ(255, result->Int32Value());
7890  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
7891
7892  result = CompileRun("for (var i = 0; i < 8; i++) {"
7893                      "  pixels[9] = -Infinity;"
7894                      "}"
7895                      "pixels[9];");
7896  CHECK_EQ(0, result->Int32Value());
7897  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
7898
7899  result = CompileRun("pixels[3] = 33;"
7900                      "delete pixels[3];"
7901                      "pixels[3];");
7902  CHECK_EQ(33, result->Int32Value());
7903
7904  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
7905                      "pixels[2] = 12; pixels[3] = 13;"
7906                      "pixels.__defineGetter__('2',"
7907                      "function() { return 120; });"
7908                      "pixels[2];");
7909  CHECK_EQ(12, result->Int32Value());
7910
7911  result = CompileRun("var js_array = new Array(40);"
7912                      "js_array[0] = 77;"
7913                      "js_array;");
7914  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
7915
7916  result = CompileRun("pixels[1] = 23;"
7917                      "pixels.__proto__ = [];"
7918                      "js_array.__proto__ = pixels;"
7919                      "js_array.concat(pixels);");
7920  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
7921  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
7922
7923  result = CompileRun("pixels[1] = 23;");
7924  CHECK_EQ(23, result->Int32Value());
7925
7926  // Test for index greater than 255.  Regression test for:
7927  // http://code.google.com/p/chromium/issues/detail?id=26337.
7928  result = CompileRun("pixels[256] = 255;");
7929  CHECK_EQ(255, result->Int32Value());
7930  result = CompileRun("var i = 0;"
7931                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
7932                      "i");
7933  CHECK_EQ(255, result->Int32Value());
7934
7935  free(pixel_data);
7936}
7937
7938
7939template <class ExternalArrayClass, class ElementType>
7940static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
7941                                    int64_t low,
7942                                    int64_t high) {
7943  v8::HandleScope scope;
7944  LocalContext context;
7945  const int kElementCount = 40;
7946  int element_size = 0;
7947  switch (array_type) {
7948    case v8::kExternalByteArray:
7949    case v8::kExternalUnsignedByteArray:
7950      element_size = 1;
7951      break;
7952    case v8::kExternalShortArray:
7953    case v8::kExternalUnsignedShortArray:
7954      element_size = 2;
7955      break;
7956    case v8::kExternalIntArray:
7957    case v8::kExternalUnsignedIntArray:
7958    case v8::kExternalFloatArray:
7959      element_size = 4;
7960      break;
7961    default:
7962      UNREACHABLE();
7963      break;
7964  }
7965  ElementType* array_data =
7966      static_cast<ElementType*>(malloc(kElementCount * element_size));
7967  i::Handle<ExternalArrayClass> array =
7968      i::Handle<ExternalArrayClass>::cast(
7969          i::Factory::NewExternalArray(kElementCount, array_type, array_data));
7970  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
7971  for (int i = 0; i < kElementCount; i++) {
7972    array->set(i, static_cast<ElementType>(i));
7973  }
7974  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
7975  for (int i = 0; i < kElementCount; i++) {
7976    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
7977    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
7978  }
7979
7980  v8::Handle<v8::Object> obj = v8::Object::New();
7981  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
7982  // Set the elements to be the external array.
7983  obj->SetIndexedPropertiesToExternalArrayData(array_data,
7984                                               array_type,
7985                                               kElementCount);
7986  CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
7987  obj->Set(v8_str("field"), v8::Int32::New(1503));
7988  context->Global()->Set(v8_str("ext_array"), obj);
7989  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
7990  CHECK_EQ(1503, result->Int32Value());
7991  result = CompileRun("ext_array[1]");
7992  CHECK_EQ(1, result->Int32Value());
7993
7994  // Check pass through of assigned smis
7995  result = CompileRun("var sum = 0;"
7996                      "for (var i = 0; i < 8; i++) {"
7997                      "  sum += ext_array[i] = ext_array[i] = -i;"
7998                      "}"
7999                      "sum;");
8000  CHECK_EQ(-28, result->Int32Value());
8001
8002  // Check assigned smis
8003  result = CompileRun("for (var i = 0; i < 8; i++) {"
8004                      "  ext_array[i] = i;"
8005                      "}"
8006                      "var sum = 0;"
8007                      "for (var i = 0; i < 8; i++) {"
8008                      "  sum += ext_array[i];"
8009                      "}"
8010                      "sum;");
8011  CHECK_EQ(28, result->Int32Value());
8012
8013  // Check assigned smis in reverse order
8014  result = CompileRun("for (var i = 8; --i >= 0; ) {"
8015                      "  ext_array[i] = i;"
8016                      "}"
8017                      "var sum = 0;"
8018                      "for (var i = 0; i < 8; i++) {"
8019                      "  sum += ext_array[i];"
8020                      "}"
8021                      "sum;");
8022  CHECK_EQ(28, result->Int32Value());
8023
8024  // Check pass through of assigned HeapNumbers
8025  result = CompileRun("var sum = 0;"
8026                      "for (var i = 0; i < 16; i+=2) {"
8027                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
8028                      "}"
8029                      "sum;");
8030  CHECK_EQ(-28, result->Int32Value());
8031
8032  // Check assigned HeapNumbers
8033  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
8034                      "  ext_array[i] = (i * 0.5);"
8035                      "}"
8036                      "var sum = 0;"
8037                      "for (var i = 0; i < 16; i+=2) {"
8038                      "  sum += ext_array[i];"
8039                      "}"
8040                      "sum;");
8041  CHECK_EQ(28, result->Int32Value());
8042
8043  // Check assigned HeapNumbers in reverse order
8044  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
8045                      "  ext_array[i] = (i * 0.5);"
8046                      "}"
8047                      "var sum = 0;"
8048                      "for (var i = 0; i < 16; i+=2) {"
8049                      "  sum += ext_array[i];"
8050                      "}"
8051                      "sum;");
8052  CHECK_EQ(28, result->Int32Value());
8053
8054  i::ScopedVector<char> test_buf(1024);
8055
8056  // Check legal boundary conditions.
8057  // The repeated loads and stores ensure the ICs are exercised.
8058  const char* boundary_program =
8059      "var res = 0;"
8060      "for (var i = 0; i < 16; i++) {"
8061      "  ext_array[i] = %lld;"
8062      "  if (i > 8) {"
8063      "    res = ext_array[i];"
8064      "  }"
8065      "}"
8066      "res;";
8067  i::OS::SNPrintF(test_buf,
8068                  boundary_program,
8069                  low);
8070  result = CompileRun(test_buf.start());
8071  CHECK_EQ(low, result->IntegerValue());
8072
8073  i::OS::SNPrintF(test_buf,
8074                  boundary_program,
8075                  high);
8076  result = CompileRun(test_buf.start());
8077  CHECK_EQ(high, result->IntegerValue());
8078
8079  // Check misprediction of type in IC.
8080  result = CompileRun("var tmp_array = ext_array;"
8081                      "var sum = 0;"
8082                      "for (var i = 0; i < 8; i++) {"
8083                      "  tmp_array[i] = i;"
8084                      "  sum += tmp_array[i];"
8085                      "  if (i == 4) {"
8086                      "    tmp_array = {};"
8087                      "  }"
8088                      "}"
8089                      "sum;");
8090  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
8091  CHECK_EQ(28, result->Int32Value());
8092
8093  // Make sure out-of-range loads do not throw.
8094  i::OS::SNPrintF(test_buf,
8095                  "var caught_exception = false;"
8096                  "try {"
8097                  "  ext_array[%d];"
8098                  "} catch (e) {"
8099                  "  caught_exception = true;"
8100                  "}"
8101                  "caught_exception;",
8102                  kElementCount);
8103  result = CompileRun(test_buf.start());
8104  CHECK_EQ(false, result->BooleanValue());
8105
8106  // Make sure out-of-range stores do not throw.
8107  i::OS::SNPrintF(test_buf,
8108                  "var caught_exception = false;"
8109                  "try {"
8110                  "  ext_array[%d] = 1;"
8111                  "} catch (e) {"
8112                  "  caught_exception = true;"
8113                  "}"
8114                  "caught_exception;",
8115                  kElementCount);
8116  result = CompileRun(test_buf.start());
8117  CHECK_EQ(false, result->BooleanValue());
8118
8119  // Check other boundary conditions, values and operations.
8120  result = CompileRun("for (var i = 0; i < 8; i++) {"
8121                      "  ext_array[7] = undefined;"
8122                      "}"
8123                      "ext_array[7];");
8124  CHECK_EQ(0, result->Int32Value());
8125  CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
8126
8127  result = CompileRun("for (var i = 0; i < 8; i++) {"
8128                      "  ext_array[6] = '2.3';"
8129                      "}"
8130                      "ext_array[6];");
8131  CHECK_EQ(2, result->Int32Value());
8132  CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
8133
8134  if (array_type != v8::kExternalFloatArray) {
8135    // Though the specification doesn't state it, be explicit about
8136    // converting NaNs and +/-Infinity to zero.
8137    result = CompileRun("for (var i = 0; i < 8; i++) {"
8138                        "  ext_array[i] = 5;"
8139                        "}"
8140                        "for (var i = 0; i < 8; i++) {"
8141                        "  ext_array[i] = NaN;"
8142                        "}"
8143                        "ext_array[5];");
8144    CHECK_EQ(0, result->Int32Value());
8145    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
8146
8147    result = CompileRun("for (var i = 0; i < 8; i++) {"
8148                        "  ext_array[i] = 5;"
8149                        "}"
8150                        "for (var i = 0; i < 8; i++) {"
8151                        "  ext_array[i] = Infinity;"
8152                        "}"
8153                        "ext_array[5];");
8154    CHECK_EQ(0, result->Int32Value());
8155    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
8156
8157    result = CompileRun("for (var i = 0; i < 8; i++) {"
8158                        "  ext_array[i] = 5;"
8159                        "}"
8160                        "for (var i = 0; i < 8; i++) {"
8161                        "  ext_array[i] = -Infinity;"
8162                        "}"
8163                        "ext_array[5];");
8164    CHECK_EQ(0, result->Int32Value());
8165    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
8166  }
8167
8168  result = CompileRun("ext_array[3] = 33;"
8169                      "delete ext_array[3];"
8170                      "ext_array[3];");
8171  CHECK_EQ(33, result->Int32Value());
8172
8173  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
8174                      "ext_array[2] = 12; ext_array[3] = 13;"
8175                      "ext_array.__defineGetter__('2',"
8176                      "function() { return 120; });"
8177                      "ext_array[2];");
8178  CHECK_EQ(12, result->Int32Value());
8179
8180  result = CompileRun("var js_array = new Array(40);"
8181                      "js_array[0] = 77;"
8182                      "js_array;");
8183  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
8184
8185  result = CompileRun("ext_array[1] = 23;"
8186                      "ext_array.__proto__ = [];"
8187                      "js_array.__proto__ = ext_array;"
8188                      "js_array.concat(ext_array);");
8189  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
8190  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
8191
8192  result = CompileRun("ext_array[1] = 23;");
8193  CHECK_EQ(23, result->Int32Value());
8194
8195  // Test more complex manipulations which cause eax to contain values
8196  // that won't be completely overwritten by loads from the arrays.
8197  // This catches bugs in the instructions used for the KeyedLoadIC
8198  // for byte and word types.
8199  {
8200    const int kXSize = 300;
8201    const int kYSize = 300;
8202    const int kLargeElementCount = kXSize * kYSize * 4;
8203    ElementType* large_array_data =
8204        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
8205    i::Handle<ExternalArrayClass> large_array =
8206        i::Handle<ExternalArrayClass>::cast(
8207            i::Factory::NewExternalArray(kLargeElementCount,
8208                                         array_type,
8209                                         array_data));
8210    v8::Handle<v8::Object> large_obj = v8::Object::New();
8211    // Set the elements to be the external array.
8212    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
8213                                                       array_type,
8214                                                       kLargeElementCount);
8215    context->Global()->Set(v8_str("large_array"), large_obj);
8216    // Initialize contents of a few rows.
8217    for (int x = 0; x < 300; x++) {
8218      int row = 0;
8219      int offset = row * 300 * 4;
8220      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
8221      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
8222      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
8223      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
8224      row = 150;
8225      offset = row * 300 * 4;
8226      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
8227      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
8228      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
8229      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
8230      row = 298;
8231      offset = row * 300 * 4;
8232      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
8233      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
8234      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
8235      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
8236    }
8237    // The goal of the code below is to make "offset" large enough
8238    // that the computation of the index (which goes into eax) has
8239    // high bits set which will not be overwritten by a byte or short
8240    // load.
8241    result = CompileRun("var failed = false;"
8242                        "var offset = 0;"
8243                        "for (var i = 0; i < 300; i++) {"
8244                        "  if (large_array[4 * i] != 127 ||"
8245                        "      large_array[4 * i + 1] != 0 ||"
8246                        "      large_array[4 * i + 2] != 0 ||"
8247                        "      large_array[4 * i + 3] != 127) {"
8248                        "    failed = true;"
8249                        "  }"
8250                        "}"
8251                        "offset = 150 * 300 * 4;"
8252                        "for (var i = 0; i < 300; i++) {"
8253                        "  if (large_array[offset + 4 * i] != 127 ||"
8254                        "      large_array[offset + 4 * i + 1] != 0 ||"
8255                        "      large_array[offset + 4 * i + 2] != 0 ||"
8256                        "      large_array[offset + 4 * i + 3] != 127) {"
8257                        "    failed = true;"
8258                        "  }"
8259                        "}"
8260                        "offset = 298 * 300 * 4;"
8261                        "for (var i = 0; i < 300; i++) {"
8262                        "  if (large_array[offset + 4 * i] != 127 ||"
8263                        "      large_array[offset + 4 * i + 1] != 0 ||"
8264                        "      large_array[offset + 4 * i + 2] != 0 ||"
8265                        "      large_array[offset + 4 * i + 3] != 127) {"
8266                        "    failed = true;"
8267                        "  }"
8268                        "}"
8269                        "!failed;");
8270    CHECK_EQ(true, result->BooleanValue());
8271    free(large_array_data);
8272  }
8273
8274  free(array_data);
8275}
8276
8277
8278THREADED_TEST(ExternalByteArray) {
8279  ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>(
8280      v8::kExternalByteArray,
8281      -128,
8282      127);
8283}
8284
8285
8286THREADED_TEST(ExternalUnsignedByteArray) {
8287  ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>(
8288      v8::kExternalUnsignedByteArray,
8289      0,
8290      255);
8291}
8292
8293
8294THREADED_TEST(ExternalShortArray) {
8295  ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>(
8296      v8::kExternalShortArray,
8297      -32768,
8298      32767);
8299}
8300
8301
8302THREADED_TEST(ExternalUnsignedShortArray) {
8303  ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>(
8304      v8::kExternalUnsignedShortArray,
8305      0,
8306      65535);
8307}
8308
8309
8310THREADED_TEST(ExternalIntArray) {
8311  ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>(
8312      v8::kExternalIntArray,
8313      INT_MIN,   // -2147483648
8314      INT_MAX);  //  2147483647
8315}
8316
8317
8318THREADED_TEST(ExternalUnsignedIntArray) {
8319  ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>(
8320      v8::kExternalUnsignedIntArray,
8321      0,
8322      UINT_MAX);  // 4294967295
8323}
8324
8325
8326THREADED_TEST(ExternalFloatArray) {
8327  ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>(
8328      v8::kExternalFloatArray,
8329      -500,
8330      500);
8331}
8332
8333
8334THREADED_TEST(ExternalArrays) {
8335  TestExternalByteArray();
8336  TestExternalUnsignedByteArray();
8337  TestExternalShortArray();
8338  TestExternalUnsignedShortArray();
8339  TestExternalIntArray();
8340  TestExternalUnsignedIntArray();
8341  TestExternalFloatArray();
8342}
8343
8344
8345THREADED_TEST(ScriptContextDependence) {
8346  v8::HandleScope scope;
8347  LocalContext c1;
8348  const char *source = "foo";
8349  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
8350  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
8351  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
8352  CHECK_EQ(dep->Run()->Int32Value(), 100);
8353  CHECK_EQ(indep->Run()->Int32Value(), 100);
8354  LocalContext c2;
8355  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
8356  CHECK_EQ(dep->Run()->Int32Value(), 100);
8357  CHECK_EQ(indep->Run()->Int32Value(), 101);
8358}
8359
8360
8361THREADED_TEST(StackTrace) {
8362  v8::HandleScope scope;
8363  LocalContext context;
8364  v8::TryCatch try_catch;
8365  const char *source = "function foo() { FAIL.FAIL; }; foo();";
8366  v8::Handle<v8::String> src = v8::String::New(source);
8367  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
8368  v8::Script::New(src, origin)->Run();
8369  CHECK(try_catch.HasCaught());
8370  v8::String::Utf8Value stack(try_catch.StackTrace());
8371  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
8372}
8373
8374
8375// Test that idle notification can be handled and eventually returns true.
8376THREADED_TEST(IdleNotification) {
8377  bool rv = false;
8378  for (int i = 0; i < 100; i++) {
8379    rv = v8::V8::IdleNotification();
8380    if (rv)
8381      break;
8382  }
8383  CHECK(rv == true);
8384}
8385
8386
8387static uint32_t* stack_limit;
8388
8389static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
8390  stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
8391  return v8::Undefined();
8392}
8393
8394
8395// Uses the address of a local variable to determine the stack top now.
8396// Given a size, returns an address that is that far from the current
8397// top of stack.
8398static uint32_t* ComputeStackLimit(uint32_t size) {
8399  uint32_t* answer = &size - (size / sizeof(size));
8400  // If the size is very large and the stack is very near the bottom of
8401  // memory then the calculation above may wrap around and give an address
8402  // that is above the (downwards-growing) stack.  In that case we return
8403  // a very low address.
8404  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
8405  return answer;
8406}
8407
8408
8409TEST(SetResourceConstraints) {
8410  static const int K = 1024;
8411  uint32_t* set_limit = ComputeStackLimit(128 * K);
8412
8413  // Set stack limit.
8414  v8::ResourceConstraints constraints;
8415  constraints.set_stack_limit(set_limit);
8416  CHECK(v8::SetResourceConstraints(&constraints));
8417
8418  // Execute a script.
8419  v8::HandleScope scope;
8420  LocalContext env;
8421  Local<v8::FunctionTemplate> fun_templ =
8422      v8::FunctionTemplate::New(GetStackLimitCallback);
8423  Local<Function> fun = fun_templ->GetFunction();
8424  env->Global()->Set(v8_str("get_stack_limit"), fun);
8425  CompileRun("get_stack_limit();");
8426
8427  CHECK(stack_limit == set_limit);
8428}
8429
8430
8431TEST(SetResourceConstraintsInThread) {
8432  uint32_t* set_limit;
8433  {
8434    v8::Locker locker;
8435    static const int K = 1024;
8436    set_limit = ComputeStackLimit(128 * K);
8437
8438    // Set stack limit.
8439    v8::ResourceConstraints constraints;
8440    constraints.set_stack_limit(set_limit);
8441    CHECK(v8::SetResourceConstraints(&constraints));
8442
8443    // Execute a script.
8444    v8::HandleScope scope;
8445    LocalContext env;
8446    Local<v8::FunctionTemplate> fun_templ =
8447        v8::FunctionTemplate::New(GetStackLimitCallback);
8448    Local<Function> fun = fun_templ->GetFunction();
8449    env->Global()->Set(v8_str("get_stack_limit"), fun);
8450    CompileRun("get_stack_limit();");
8451
8452    CHECK(stack_limit == set_limit);
8453  }
8454  {
8455    v8::Locker locker;
8456    CHECK(stack_limit == set_limit);
8457  }
8458}
8459
8460
8461THREADED_TEST(GetHeapStatistics) {
8462  v8::HandleScope scope;
8463  LocalContext c1;
8464  v8::HeapStatistics heap_statistics;
8465  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
8466  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
8467  v8::V8::GetHeapStatistics(&heap_statistics);
8468  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
8469  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
8470}
8471
8472
8473static double DoubleFromBits(uint64_t value) {
8474  double target;
8475#ifdef BIG_ENDIAN_FLOATING_POINT
8476  const int kIntSize = 4;
8477  // Somebody swapped the lower and higher half of doubles.
8478  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
8479  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
8480#else
8481  memcpy(&target, &value, sizeof(target));
8482#endif
8483  return target;
8484}
8485
8486
8487static uint64_t DoubleToBits(double value) {
8488  uint64_t target;
8489#ifdef BIG_ENDIAN_FLOATING_POINT
8490  const int kIntSize = 4;
8491  // Somebody swapped the lower and higher half of doubles.
8492  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
8493  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
8494#else
8495  memcpy(&target, &value, sizeof(target));
8496#endif
8497  return target;
8498}
8499
8500
8501static double DoubleToDateTime(double input) {
8502  double date_limit = 864e13;
8503  if (IsNaN(input) || input < -date_limit || input > date_limit) {
8504    return i::OS::nan_value();
8505  }
8506  return (input < 0) ? -(floor(-input)) : floor(input);
8507}
8508
8509// We don't have a consistent way to write 64-bit constants syntactically, so we
8510// split them into two 32-bit constants and combine them programmatically.
8511static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
8512  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
8513}
8514
8515
8516THREADED_TEST(QuietSignalingNaNs) {
8517  v8::HandleScope scope;
8518  LocalContext context;
8519  v8::TryCatch try_catch;
8520
8521  // Special double values.
8522  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
8523  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
8524  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
8525  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
8526  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
8527  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
8528  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
8529
8530  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
8531  // on either side of the epoch.
8532  double date_limit = 864e13;
8533
8534  double test_values[] = {
8535      snan,
8536      qnan,
8537      infinity,
8538      max_normal,
8539      date_limit + 1,
8540      date_limit,
8541      min_normal,
8542      max_denormal,
8543      min_denormal,
8544      0,
8545      -0,
8546      -min_denormal,
8547      -max_denormal,
8548      -min_normal,
8549      -date_limit,
8550      -date_limit - 1,
8551      -max_normal,
8552      -infinity,
8553      -qnan,
8554      -snan
8555  };
8556  int num_test_values = 20;
8557
8558  for (int i = 0; i < num_test_values; i++) {
8559    double test_value = test_values[i];
8560
8561    // Check that Number::New preserves non-NaNs and quiets SNaNs.
8562    v8::Handle<v8::Value> number = v8::Number::New(test_value);
8563    double stored_number = number->NumberValue();
8564    if (!IsNaN(test_value)) {
8565      CHECK_EQ(test_value, stored_number);
8566    } else {
8567      uint64_t stored_bits = DoubleToBits(stored_number);
8568      // Check if quiet nan (bits 51..62 all set).
8569      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
8570    }
8571
8572    // Check that Date::New preserves non-NaNs in the date range and
8573    // quiets SNaNs.
8574    v8::Handle<v8::Value> date = v8::Date::New(test_value);
8575    double expected_stored_date = DoubleToDateTime(test_value);
8576    double stored_date = date->NumberValue();
8577    if (!IsNaN(expected_stored_date)) {
8578      CHECK_EQ(expected_stored_date, stored_date);
8579    } else {
8580      uint64_t stored_bits = DoubleToBits(stored_date);
8581      // Check if quiet nan (bits 51..62 all set).
8582      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
8583    }
8584  }
8585}
8586
8587
8588static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
8589  v8::HandleScope scope;
8590  v8::TryCatch tc;
8591  v8::Handle<v8::String> str = args[0]->ToString();
8592  if (tc.HasCaught())
8593    return tc.ReThrow();
8594  return v8::Undefined();
8595}
8596
8597
8598// Test that an exception can be propagated down through a spaghetti
8599// stack using ReThrow.
8600THREADED_TEST(SpaghettiStackReThrow) {
8601  v8::HandleScope scope;
8602  LocalContext context;
8603  context->Global()->Set(
8604      v8::String::New("s"),
8605      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
8606  v8::TryCatch try_catch;
8607  CompileRun(
8608      "var i = 0;"
8609      "var o = {"
8610      "  toString: function () {"
8611      "    if (i == 10) {"
8612      "      throw 'Hey!';"
8613      "    } else {"
8614      "      i++;"
8615      "      return s(o);"
8616      "    }"
8617      "  }"
8618      "};"
8619      "s(o);");
8620  CHECK(try_catch.HasCaught());
8621  v8::String::Utf8Value value(try_catch.Exception());
8622  CHECK_EQ(0, strcmp(*value, "Hey!"));
8623}
8624
8625
8626TEST(Regress528) {
8627  v8::V8::Initialize();
8628
8629  v8::HandleScope scope;
8630  v8::Persistent<Context> context;
8631  v8::Persistent<Context> other_context;
8632  int gc_count;
8633
8634  // Create a context used to keep the code from aging in the compilation
8635  // cache.
8636  other_context = Context::New();
8637
8638  // Context-dependent context data creates reference from the compilation
8639  // cache to the global object.
8640  const char* source_simple = "1";
8641  context = Context::New();
8642  {
8643    v8::HandleScope scope;
8644
8645    context->Enter();
8646    Local<v8::String> obj = v8::String::New("");
8647    context->SetData(obj);
8648    CompileRun(source_simple);
8649    context->Exit();
8650  }
8651  context.Dispose();
8652  for (gc_count = 1; gc_count < 10; gc_count++) {
8653    other_context->Enter();
8654    CompileRun(source_simple);
8655    other_context->Exit();
8656    v8::internal::Heap::CollectAllGarbage(false);
8657    if (GetGlobalObjectsCount() == 1) break;
8658  }
8659  CHECK_GE(2, gc_count);
8660  CHECK_EQ(1, GetGlobalObjectsCount());
8661
8662  // Eval in a function creates reference from the compilation cache to the
8663  // global object.
8664  const char* source_eval = "function f(){eval('1')}; f()";
8665  context = Context::New();
8666  {
8667    v8::HandleScope scope;
8668
8669    context->Enter();
8670    CompileRun(source_eval);
8671    context->Exit();
8672  }
8673  context.Dispose();
8674  for (gc_count = 1; gc_count < 10; gc_count++) {
8675    other_context->Enter();
8676    CompileRun(source_eval);
8677    other_context->Exit();
8678    v8::internal::Heap::CollectAllGarbage(false);
8679    if (GetGlobalObjectsCount() == 1) break;
8680  }
8681  CHECK_GE(2, gc_count);
8682  CHECK_EQ(1, GetGlobalObjectsCount());
8683
8684  // Looking up the line number for an exception creates reference from the
8685  // compilation cache to the global object.
8686  const char* source_exception = "function f(){throw 1;} f()";
8687  context = Context::New();
8688  {
8689    v8::HandleScope scope;
8690
8691    context->Enter();
8692    v8::TryCatch try_catch;
8693    CompileRun(source_exception);
8694    CHECK(try_catch.HasCaught());
8695    v8::Handle<v8::Message> message = try_catch.Message();
8696    CHECK(!message.IsEmpty());
8697    CHECK_EQ(1, message->GetLineNumber());
8698    context->Exit();
8699  }
8700  context.Dispose();
8701  for (gc_count = 1; gc_count < 10; gc_count++) {
8702    other_context->Enter();
8703    CompileRun(source_exception);
8704    other_context->Exit();
8705    v8::internal::Heap::CollectAllGarbage(false);
8706    if (GetGlobalObjectsCount() == 1) break;
8707  }
8708  CHECK_GE(2, gc_count);
8709  CHECK_EQ(1, GetGlobalObjectsCount());
8710
8711  other_context.Dispose();
8712}
8713