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