1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <climits>
29#include <csignal>
30#include <map>
31#include <string>
32
33#include "src/v8.h"
34
35#if V8_OS_POSIX
36#include <unistd.h>  // NOLINT
37#endif
38
39#include "include/v8-util.h"
40#include "src/api.h"
41#include "src/arguments.h"
42#include "src/base/platform/platform.h"
43#include "src/compilation-cache.h"
44#include "src/cpu-profiler.h"
45#include "src/execution.h"
46#include "src/isolate.h"
47#include "src/objects.h"
48#include "src/parser.h"
49#include "src/snapshot.h"
50#include "src/unicode-inl.h"
51#include "src/utils.h"
52#include "src/vm-state.h"
53#include "test/cctest/cctest.h"
54
55static const bool kLogThreading = false;
56
57using ::v8::Boolean;
58using ::v8::BooleanObject;
59using ::v8::Context;
60using ::v8::Extension;
61using ::v8::Function;
62using ::v8::FunctionTemplate;
63using ::v8::Handle;
64using ::v8::HandleScope;
65using ::v8::Local;
66using ::v8::Name;
67using ::v8::Message;
68using ::v8::MessageCallback;
69using ::v8::Object;
70using ::v8::ObjectTemplate;
71using ::v8::Persistent;
72using ::v8::Script;
73using ::v8::StackTrace;
74using ::v8::String;
75using ::v8::Symbol;
76using ::v8::TryCatch;
77using ::v8::Undefined;
78using ::v8::UniqueId;
79using ::v8::V8;
80using ::v8::Value;
81
82
83#define THREADED_PROFILED_TEST(Name)                                 \
84  static void Test##Name();                                          \
85  TEST(Name##WithProfiler) {                                         \
86    RunWithProfiler(&Test##Name);                                    \
87  }                                                                  \
88  THREADED_TEST(Name)
89
90
91void RunWithProfiler(void (*test)()) {
92  LocalContext env;
93  v8::HandleScope scope(env->GetIsolate());
94  v8::Local<v8::String> profile_name =
95      v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
96  v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
97
98  cpu_profiler->StartProfiling(profile_name);
99  (*test)();
100  reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
101}
102
103
104static int signature_callback_count;
105static Local<Value> signature_expected_receiver;
106static void IncrementingSignatureCallback(
107    const v8::FunctionCallbackInfo<v8::Value>& args) {
108  ApiTestFuzzer::Fuzz();
109  signature_callback_count++;
110  CHECK_EQ(signature_expected_receiver, args.Holder());
111  CHECK_EQ(signature_expected_receiver, args.This());
112  v8::Handle<v8::Array> result =
113      v8::Array::New(args.GetIsolate(), args.Length());
114  for (int i = 0; i < args.Length(); i++)
115    result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
116  args.GetReturnValue().Set(result);
117}
118
119
120static void SignatureCallback(
121    const v8::FunctionCallbackInfo<v8::Value>& args) {
122  ApiTestFuzzer::Fuzz();
123  v8::Handle<v8::Array> result =
124      v8::Array::New(args.GetIsolate(), args.Length());
125  for (int i = 0; i < args.Length(); i++) {
126    result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
127  }
128  args.GetReturnValue().Set(result);
129}
130
131
132// Tests that call v8::V8::Dispose() cannot be threaded.
133UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
134  CHECK(v8::V8::Initialize());
135  CHECK(v8::V8::Dispose());
136}
137
138
139// Tests that call v8::V8::Dispose() cannot be threaded.
140UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
141  for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
142  for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
143  for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
144  for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
145  for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
146}
147
148
149THREADED_TEST(Handles) {
150  v8::HandleScope scope(CcTest::isolate());
151  Local<Context> local_env;
152  {
153    LocalContext env;
154    local_env = env.local();
155  }
156
157  // Local context should still be live.
158  CHECK(!local_env.IsEmpty());
159  local_env->Enter();
160
161  v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
162  CHECK(!undef.IsEmpty());
163  CHECK(undef->IsUndefined());
164
165  const char* source = "1 + 2 + 3";
166  Local<Script> script = v8_compile(source);
167  CHECK_EQ(6, script->Run()->Int32Value());
168
169  local_env->Exit();
170}
171
172
173THREADED_TEST(IsolateOfContext) {
174  v8::HandleScope scope(CcTest::isolate());
175  v8::Handle<Context> env = Context::New(CcTest::isolate());
176
177  CHECK(!env->GetIsolate()->InContext());
178  CHECK(env->GetIsolate() == CcTest::isolate());
179  env->Enter();
180  CHECK(env->GetIsolate()->InContext());
181  CHECK(env->GetIsolate() == CcTest::isolate());
182  env->Exit();
183  CHECK(!env->GetIsolate()->InContext());
184  CHECK(env->GetIsolate() == CcTest::isolate());
185}
186
187
188static void TestSignature(const char* loop_js, Local<Value> receiver) {
189  i::ScopedVector<char> source(200);
190  i::SNPrintF(source,
191              "for (var i = 0; i < 10; i++) {"
192              "  %s"
193              "}",
194              loop_js);
195  signature_callback_count = 0;
196  signature_expected_receiver = receiver;
197  bool expected_to_throw = receiver.IsEmpty();
198  v8::TryCatch try_catch;
199  CompileRun(source.start());
200  CHECK_EQ(expected_to_throw, try_catch.HasCaught());
201  if (!expected_to_throw) {
202    CHECK_EQ(10, signature_callback_count);
203  } else {
204    CHECK_EQ(v8_str("TypeError: Illegal invocation"),
205             try_catch.Exception()->ToString());
206  }
207}
208
209
210THREADED_TEST(ReceiverSignature) {
211  LocalContext env;
212  v8::Isolate* isolate = env->GetIsolate();
213  v8::HandleScope scope(isolate);
214  // Setup templates.
215  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
216  v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
217  v8::Handle<v8::FunctionTemplate> callback_sig =
218      v8::FunctionTemplate::New(
219          isolate, IncrementingSignatureCallback, Local<Value>(), sig);
220  v8::Handle<v8::FunctionTemplate> callback =
221      v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
222  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
223  sub_fun->Inherit(fun);
224  v8::Handle<v8::FunctionTemplate> unrel_fun =
225      v8::FunctionTemplate::New(isolate);
226  // Install properties.
227  v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
228  fun_proto->Set(v8_str("prop_sig"), callback_sig);
229  fun_proto->Set(v8_str("prop"), callback);
230  fun_proto->SetAccessorProperty(
231      v8_str("accessor_sig"), callback_sig, callback_sig);
232  fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
233  // Instantiate templates.
234  Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
235  Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
236  // Setup global variables.
237  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
238  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
239  env->Global()->Set(v8_str("fun_instance"), fun_instance);
240  env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
241  CompileRun(
242      "var accessor_sig_key = 'accessor_sig';"
243      "var accessor_key = 'accessor';"
244      "var prop_sig_key = 'prop_sig';"
245      "var prop_key = 'prop';"
246      ""
247      "function copy_props(obj) {"
248      "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
249      "  var source = Fun.prototype;"
250      "  for (var i in keys) {"
251      "    var key = keys[i];"
252      "    var desc = Object.getOwnPropertyDescriptor(source, key);"
253      "    Object.defineProperty(obj, key, desc);"
254      "  }"
255      "}"
256      ""
257      "var obj = {};"
258      "copy_props(obj);"
259      "var unrel = new UnrelFun();"
260      "copy_props(unrel);");
261  // Test with and without ICs
262  const char* test_objects[] = {
263      "fun_instance", "sub_fun_instance", "obj", "unrel" };
264  unsigned bad_signature_start_offset = 2;
265  for (unsigned i = 0; i < arraysize(test_objects); i++) {
266    i::ScopedVector<char> source(200);
267    i::SNPrintF(
268        source, "var test_object = %s; test_object", test_objects[i]);
269    Local<Value> test_object = CompileRun(source.start());
270    TestSignature("test_object.prop();", test_object);
271    TestSignature("test_object.accessor;", test_object);
272    TestSignature("test_object[accessor_key];", test_object);
273    TestSignature("test_object.accessor = 1;", test_object);
274    TestSignature("test_object[accessor_key] = 1;", test_object);
275    if (i >= bad_signature_start_offset) test_object = Local<Value>();
276    TestSignature("test_object.prop_sig();", test_object);
277    TestSignature("test_object.accessor_sig;", test_object);
278    TestSignature("test_object[accessor_sig_key];", test_object);
279    TestSignature("test_object.accessor_sig = 1;", test_object);
280    TestSignature("test_object[accessor_sig_key] = 1;", test_object);
281  }
282}
283
284
285THREADED_TEST(ArgumentSignature) {
286  LocalContext env;
287  v8::Isolate* isolate = env->GetIsolate();
288  v8::HandleScope scope(isolate);
289  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
290  cons->SetClassName(v8_str("Cons"));
291  v8::Handle<v8::Signature> sig = v8::Signature::New(
292      isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
293  v8::Handle<v8::FunctionTemplate> fun =
294      v8::FunctionTemplate::New(isolate,
295                                SignatureCallback,
296                                v8::Handle<Value>(),
297                                sig);
298  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
299  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
300
301  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
302  CHECK(value1->IsTrue());
303
304  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
305  CHECK(value2->IsTrue());
306
307  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
308  CHECK(value3->IsTrue());
309
310  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
311  cons1->SetClassName(v8_str("Cons1"));
312  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
313  cons2->SetClassName(v8_str("Cons2"));
314  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
315  cons3->SetClassName(v8_str("Cons3"));
316
317  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
318  v8::Handle<v8::Signature> wsig = v8::Signature::New(
319      isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
320  v8::Handle<v8::FunctionTemplate> fun2 =
321      v8::FunctionTemplate::New(isolate,
322                                SignatureCallback,
323                                v8::Handle<Value>(),
324                                wsig);
325
326  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
327  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
328  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
329  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
330  v8::Handle<Value> value4 = CompileRun(
331      "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
332      "'[object Cons1],[object Cons2],[object Cons3]'");
333  CHECK(value4->IsTrue());
334
335  v8::Handle<Value> value5 = CompileRun(
336      "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
337  CHECK(value5->IsTrue());
338
339  v8::Handle<Value> value6 = CompileRun(
340      "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
341  CHECK(value6->IsTrue());
342
343  v8::Handle<Value> value7 = CompileRun(
344      "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
345      "'[object Cons1],[object Cons2],[object Cons3],d';");
346  CHECK(value7->IsTrue());
347
348  v8::Handle<Value> value8 = CompileRun(
349      "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
350  CHECK(value8->IsTrue());
351}
352
353
354THREADED_TEST(HulIgennem) {
355  LocalContext env;
356  v8::Isolate* isolate = env->GetIsolate();
357  v8::HandleScope scope(isolate);
358  v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
359  Local<String> undef_str = undef->ToString();
360  char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
361  undef_str->WriteUtf8(value);
362  CHECK_EQ(0, strcmp(value, "undefined"));
363  i::DeleteArray(value);
364}
365
366
367THREADED_TEST(Access) {
368  LocalContext env;
369  v8::Isolate* isolate = env->GetIsolate();
370  v8::HandleScope scope(isolate);
371  Local<v8::Object> obj = v8::Object::New(isolate);
372  Local<Value> foo_before = obj->Get(v8_str("foo"));
373  CHECK(foo_before->IsUndefined());
374  Local<String> bar_str = v8_str("bar");
375  obj->Set(v8_str("foo"), bar_str);
376  Local<Value> foo_after = obj->Get(v8_str("foo"));
377  CHECK(!foo_after->IsUndefined());
378  CHECK(foo_after->IsString());
379  CHECK_EQ(bar_str, foo_after);
380}
381
382
383THREADED_TEST(AccessElement) {
384  LocalContext env;
385  v8::HandleScope scope(env->GetIsolate());
386  Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
387  Local<Value> before = obj->Get(1);
388  CHECK(before->IsUndefined());
389  Local<String> bar_str = v8_str("bar");
390  obj->Set(1, bar_str);
391  Local<Value> after = obj->Get(1);
392  CHECK(!after->IsUndefined());
393  CHECK(after->IsString());
394  CHECK_EQ(bar_str, after);
395
396  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
397  CHECK_EQ(v8_str("a"), value->Get(0));
398  CHECK_EQ(v8_str("b"), value->Get(1));
399}
400
401
402THREADED_TEST(Script) {
403  LocalContext env;
404  v8::HandleScope scope(env->GetIsolate());
405  const char* source = "1 + 2 + 3";
406  Local<Script> script = v8_compile(source);
407  CHECK_EQ(6, script->Run()->Int32Value());
408}
409
410
411class TestResource: public String::ExternalStringResource {
412 public:
413  explicit TestResource(uint16_t* data, int* counter = NULL,
414                        bool owning_data = true)
415      : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
416    while (data[length_]) ++length_;
417  }
418
419  ~TestResource() {
420    if (owning_data_) i::DeleteArray(data_);
421    if (counter_ != NULL) ++*counter_;
422  }
423
424  const uint16_t* data() const {
425    return data_;
426  }
427
428  size_t length() const {
429    return length_;
430  }
431
432 private:
433  uint16_t* data_;
434  size_t length_;
435  int* counter_;
436  bool owning_data_;
437};
438
439
440class TestOneByteResource : public String::ExternalOneByteStringResource {
441 public:
442  explicit TestOneByteResource(const char* data, int* counter = NULL,
443                               size_t offset = 0)
444      : orig_data_(data),
445        data_(data + offset),
446        length_(strlen(data) - offset),
447        counter_(counter) {}
448
449  ~TestOneByteResource() {
450    i::DeleteArray(orig_data_);
451    if (counter_ != NULL) ++*counter_;
452  }
453
454  const char* data() const {
455    return data_;
456  }
457
458  size_t length() const {
459    return length_;
460  }
461
462 private:
463  const char* orig_data_;
464  const char* data_;
465  size_t length_;
466  int* counter_;
467};
468
469
470THREADED_TEST(ScriptUsingStringResource) {
471  int dispose_count = 0;
472  const char* c_source = "1 + 2 * 3";
473  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
474  {
475    LocalContext env;
476    v8::HandleScope scope(env->GetIsolate());
477    TestResource* resource = new TestResource(two_byte_source, &dispose_count);
478    Local<String> source = String::NewExternal(env->GetIsolate(), resource);
479    Local<Script> script = v8_compile(source);
480    Local<Value> value = script->Run();
481    CHECK(value->IsNumber());
482    CHECK_EQ(7, value->Int32Value());
483    CHECK(source->IsExternal());
484    CHECK_EQ(resource,
485             static_cast<TestResource*>(source->GetExternalStringResource()));
486    String::Encoding encoding = String::UNKNOWN_ENCODING;
487    CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
488             source->GetExternalStringResourceBase(&encoding));
489    CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
490    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
491    CHECK_EQ(0, dispose_count);
492  }
493  CcTest::i_isolate()->compilation_cache()->Clear();
494  CcTest::heap()->CollectAllAvailableGarbage();
495  CHECK_EQ(1, dispose_count);
496}
497
498
499THREADED_TEST(ScriptUsingOneByteStringResource) {
500  int dispose_count = 0;
501  const char* c_source = "1 + 2 * 3";
502  {
503    LocalContext env;
504    v8::HandleScope scope(env->GetIsolate());
505    TestOneByteResource* resource =
506        new TestOneByteResource(i::StrDup(c_source), &dispose_count);
507    Local<String> source = String::NewExternal(env->GetIsolate(), resource);
508    CHECK(source->IsExternalOneByte());
509    CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
510             source->GetExternalOneByteStringResource());
511    String::Encoding encoding = String::UNKNOWN_ENCODING;
512    CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
513             source->GetExternalStringResourceBase(&encoding));
514    CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
515    Local<Script> script = v8_compile(source);
516    Local<Value> value = script->Run();
517    CHECK(value->IsNumber());
518    CHECK_EQ(7, value->Int32Value());
519    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
520    CHECK_EQ(0, dispose_count);
521  }
522  CcTest::i_isolate()->compilation_cache()->Clear();
523  CcTest::heap()->CollectAllAvailableGarbage();
524  CHECK_EQ(1, dispose_count);
525}
526
527
528THREADED_TEST(ScriptMakingExternalString) {
529  int dispose_count = 0;
530  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
531  {
532    LocalContext env;
533    v8::HandleScope scope(env->GetIsolate());
534    Local<String> source =
535        String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
536    // Trigger GCs so that the newly allocated string moves to old gen.
537    CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
538    CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
539    CHECK_EQ(source->IsExternal(), false);
540    CHECK_EQ(source->IsExternalOneByte(), false);
541    String::Encoding encoding = String::UNKNOWN_ENCODING;
542    CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
543    CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
544    bool success = source->MakeExternal(new TestResource(two_byte_source,
545                                                         &dispose_count));
546    CHECK(success);
547    Local<Script> script = v8_compile(source);
548    Local<Value> value = script->Run();
549    CHECK(value->IsNumber());
550    CHECK_EQ(7, value->Int32Value());
551    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
552    CHECK_EQ(0, dispose_count);
553  }
554  CcTest::i_isolate()->compilation_cache()->Clear();
555  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
556  CHECK_EQ(1, dispose_count);
557}
558
559
560THREADED_TEST(ScriptMakingExternalOneByteString) {
561  int dispose_count = 0;
562  const char* c_source = "1 + 2 * 3";
563  {
564    LocalContext env;
565    v8::HandleScope scope(env->GetIsolate());
566    Local<String> source = v8_str(c_source);
567    // Trigger GCs so that the newly allocated string moves to old gen.
568    CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
569    CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
570    bool success = source->MakeExternal(
571        new TestOneByteResource(i::StrDup(c_source), &dispose_count));
572    CHECK(success);
573    Local<Script> script = v8_compile(source);
574    Local<Value> value = script->Run();
575    CHECK(value->IsNumber());
576    CHECK_EQ(7, value->Int32Value());
577    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
578    CHECK_EQ(0, dispose_count);
579  }
580  CcTest::i_isolate()->compilation_cache()->Clear();
581  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
582  CHECK_EQ(1, dispose_count);
583}
584
585
586TEST(MakingExternalStringConditions) {
587  LocalContext env;
588  v8::HandleScope scope(env->GetIsolate());
589
590  // Free some space in the new space so that we can check freshness.
591  CcTest::heap()->CollectGarbage(i::NEW_SPACE);
592  CcTest::heap()->CollectGarbage(i::NEW_SPACE);
593
594  uint16_t* two_byte_string = AsciiToTwoByteString("s1");
595  Local<String> small_string =
596      String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
597  i::DeleteArray(two_byte_string);
598
599  // We should refuse to externalize newly created small string.
600  CHECK(!small_string->CanMakeExternal());
601  // Trigger GCs so that the newly allocated string moves to old gen.
602  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
603  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
604  // Old space strings should be accepted.
605  CHECK(small_string->CanMakeExternal());
606
607  two_byte_string = AsciiToTwoByteString("small string 2");
608  small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
609  i::DeleteArray(two_byte_string);
610
611  // We should refuse externalizing newly created small string.
612  CHECK(!small_string->CanMakeExternal());
613  for (int i = 0; i < 100; i++) {
614    String::Value value(small_string);
615  }
616  // Frequently used strings should be accepted.
617  CHECK(small_string->CanMakeExternal());
618
619  const int buf_size = 10 * 1024;
620  char* buf = i::NewArray<char>(buf_size);
621  memset(buf, 'a', buf_size);
622  buf[buf_size - 1] = '\0';
623
624  two_byte_string = AsciiToTwoByteString(buf);
625  Local<String> large_string =
626      String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
627  i::DeleteArray(buf);
628  i::DeleteArray(two_byte_string);
629  // Large strings should be immediately accepted.
630  CHECK(large_string->CanMakeExternal());
631}
632
633
634TEST(MakingExternalOneByteStringConditions) {
635  LocalContext env;
636  v8::HandleScope scope(env->GetIsolate());
637
638  // Free some space in the new space so that we can check freshness.
639  CcTest::heap()->CollectGarbage(i::NEW_SPACE);
640  CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641
642  Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
643  // We should refuse to externalize newly created small string.
644  CHECK(!small_string->CanMakeExternal());
645  // Trigger GCs so that the newly allocated string moves to old gen.
646  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
647  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
648  // Old space strings should be accepted.
649  CHECK(small_string->CanMakeExternal());
650
651  small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
652  // We should refuse externalizing newly created small string.
653  CHECK(!small_string->CanMakeExternal());
654  for (int i = 0; i < 100; i++) {
655    String::Value value(small_string);
656  }
657  // Frequently used strings should be accepted.
658  CHECK(small_string->CanMakeExternal());
659
660  const int buf_size = 10 * 1024;
661  char* buf = i::NewArray<char>(buf_size);
662  memset(buf, 'a', buf_size);
663  buf[buf_size - 1] = '\0';
664  Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
665  i::DeleteArray(buf);
666  // Large strings should be immediately accepted.
667  CHECK(large_string->CanMakeExternal());
668}
669
670
671TEST(MakingExternalUnalignedOneByteString) {
672  LocalContext env;
673  v8::HandleScope scope(env->GetIsolate());
674
675  CompileRun("function cons(a, b) { return a + b; }"
676             "function slice(a) { return a.substring(1); }");
677  // Create a cons string that will land in old pointer space.
678  Local<String> cons = Local<String>::Cast(CompileRun(
679      "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
680  // Create a sliced string that will land in old pointer space.
681  Local<String> slice = Local<String>::Cast(CompileRun(
682      "slice('abcdefghijklmnopqrstuvwxyz');"));
683
684  // Trigger GCs so that the newly allocated string moves to old gen.
685  SimulateFullSpace(CcTest::heap()->old_pointer_space());
686  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
687  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
688
689  // Turn into external string with unaligned resource data.
690  const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
691  bool success =
692      cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
693  CHECK(success);
694  const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
695  success =
696      slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
697  CHECK(success);
698
699  // Trigger GCs and force evacuation.
700  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
701  CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
702}
703
704
705THREADED_TEST(UsingExternalString) {
706  i::Factory* factory = CcTest::i_isolate()->factory();
707  {
708    v8::HandleScope scope(CcTest::isolate());
709    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
710    Local<String> string = String::NewExternal(
711        CcTest::isolate(), new TestResource(two_byte_string));
712    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
713    // Trigger GCs so that the newly allocated string moves to old gen.
714    CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
715    CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
716    i::Handle<i::String> isymbol =
717        factory->InternalizeString(istring);
718    CHECK(isymbol->IsInternalizedString());
719  }
720  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
721  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
722}
723
724
725THREADED_TEST(UsingExternalOneByteString) {
726  i::Factory* factory = CcTest::i_isolate()->factory();
727  {
728    v8::HandleScope scope(CcTest::isolate());
729    const char* one_byte_string = "test string";
730    Local<String> string = String::NewExternal(
731        CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
732    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
733    // Trigger GCs so that the newly allocated string moves to old gen.
734    CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
735    CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
736    i::Handle<i::String> isymbol =
737        factory->InternalizeString(istring);
738    CHECK(isymbol->IsInternalizedString());
739  }
740  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
741  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
742}
743
744
745THREADED_TEST(ScavengeExternalString) {
746  i::FLAG_stress_compaction = false;
747  i::FLAG_gc_global = false;
748  int dispose_count = 0;
749  bool in_new_space = false;
750  {
751    v8::HandleScope scope(CcTest::isolate());
752    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
753    Local<String> string = String::NewExternal(
754        CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
755    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
756    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
757    in_new_space = CcTest::heap()->InNewSpace(*istring);
758    CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
759    CHECK_EQ(0, dispose_count);
760  }
761  CcTest::heap()->CollectGarbage(
762      in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
763  CHECK_EQ(1, dispose_count);
764}
765
766
767THREADED_TEST(ScavengeExternalOneByteString) {
768  i::FLAG_stress_compaction = false;
769  i::FLAG_gc_global = false;
770  int dispose_count = 0;
771  bool in_new_space = false;
772  {
773    v8::HandleScope scope(CcTest::isolate());
774    const char* one_byte_string = "test string";
775    Local<String> string = String::NewExternal(
776        CcTest::isolate(),
777        new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
778    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
779    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
780    in_new_space = CcTest::heap()->InNewSpace(*istring);
781    CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
782    CHECK_EQ(0, dispose_count);
783  }
784  CcTest::heap()->CollectGarbage(
785      in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
786  CHECK_EQ(1, dispose_count);
787}
788
789
790class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
791 public:
792  // Only used by non-threaded tests, so it can use static fields.
793  static int dispose_calls;
794  static int dispose_count;
795
796  TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
797      : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
798
799  void Dispose() {
800    ++dispose_calls;
801    if (dispose_) delete this;
802  }
803 private:
804  bool dispose_;
805};
806
807
808int TestOneByteResourceWithDisposeControl::dispose_count = 0;
809int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
810
811
812TEST(ExternalStringWithDisposeHandling) {
813  const char* c_source = "1 + 2 * 3";
814
815  // Use a stack allocated external string resource allocated object.
816  TestOneByteResourceWithDisposeControl::dispose_count = 0;
817  TestOneByteResourceWithDisposeControl::dispose_calls = 0;
818  TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
819  {
820    LocalContext env;
821    v8::HandleScope scope(env->GetIsolate());
822    Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
823    Local<Script> script = v8_compile(source);
824    Local<Value> value = script->Run();
825    CHECK(value->IsNumber());
826    CHECK_EQ(7, value->Int32Value());
827    CcTest::heap()->CollectAllAvailableGarbage();
828    CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
829  }
830  CcTest::i_isolate()->compilation_cache()->Clear();
831  CcTest::heap()->CollectAllAvailableGarbage();
832  CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
833  CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
834
835  // Use a heap allocated external string resource allocated object.
836  TestOneByteResourceWithDisposeControl::dispose_count = 0;
837  TestOneByteResourceWithDisposeControl::dispose_calls = 0;
838  TestOneByteResource* res_heap =
839      new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
840  {
841    LocalContext env;
842    v8::HandleScope scope(env->GetIsolate());
843    Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
844    Local<Script> script = v8_compile(source);
845    Local<Value> value = script->Run();
846    CHECK(value->IsNumber());
847    CHECK_EQ(7, value->Int32Value());
848    CcTest::heap()->CollectAllAvailableGarbage();
849    CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
850  }
851  CcTest::i_isolate()->compilation_cache()->Clear();
852  CcTest::heap()->CollectAllAvailableGarbage();
853  CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
854  CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
855}
856
857
858THREADED_TEST(StringConcat) {
859  {
860    LocalContext env;
861    v8::HandleScope scope(env->GetIsolate());
862    const char* one_byte_string_1 = "function a_times_t";
863    const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
864    const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
865    const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
866    const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
867    const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
868    const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
869    Local<String> left = v8_str(one_byte_string_1);
870
871    uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
872    Local<String> right =
873        String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
874    i::DeleteArray(two_byte_source);
875
876    Local<String> source = String::Concat(left, right);
877    right = String::NewExternal(
878        env->GetIsolate(),
879        new TestOneByteResource(i::StrDup(one_byte_extern_1)));
880    source = String::Concat(source, right);
881    right = String::NewExternal(
882        env->GetIsolate(),
883        new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
884    source = String::Concat(source, right);
885    right = v8_str(one_byte_string_2);
886    source = String::Concat(source, right);
887
888    two_byte_source = AsciiToTwoByteString(two_byte_string_2);
889    right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
890    i::DeleteArray(two_byte_source);
891
892    source = String::Concat(source, right);
893    right = String::NewExternal(
894        env->GetIsolate(),
895        new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
896    source = String::Concat(source, right);
897    Local<Script> script = v8_compile(source);
898    Local<Value> value = script->Run();
899    CHECK(value->IsNumber());
900    CHECK_EQ(68, value->Int32Value());
901  }
902  CcTest::i_isolate()->compilation_cache()->Clear();
903  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
904  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
905}
906
907
908THREADED_TEST(GlobalProperties) {
909  LocalContext env;
910  v8::HandleScope scope(env->GetIsolate());
911  v8::Handle<v8::Object> global = env->Global();
912  global->Set(v8_str("pi"), v8_num(3.1415926));
913  Local<Value> pi = global->Get(v8_str("pi"));
914  CHECK_EQ(3.1415926, pi->NumberValue());
915}
916
917
918template<typename T>
919static void CheckReturnValue(const T& t, i::Address callback) {
920  v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
921  i::Object** o = *reinterpret_cast<i::Object***>(&rv);
922  CHECK_EQ(CcTest::isolate(), t.GetIsolate());
923  CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
924  CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
925  // Verify reset
926  bool is_runtime = (*o)->IsTheHole();
927  rv.Set(true);
928  CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
929  rv.Set(v8::Handle<v8::Object>());
930  CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
931  CHECK_EQ(is_runtime, (*o)->IsTheHole());
932
933  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
934  // If CPU profiler is active check that when API callback is invoked
935  // VMState is set to EXTERNAL.
936  if (isolate->cpu_profiler()->is_profiling()) {
937    CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
938    CHECK(isolate->external_callback_scope());
939    CHECK_EQ(callback, isolate->external_callback_scope()->callback());
940  }
941}
942
943
944static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
945                                 i::Address callback) {
946  ApiTestFuzzer::Fuzz();
947  CheckReturnValue(info, callback);
948  info.GetReturnValue().Set(v8_str("bad value"));
949  info.GetReturnValue().Set(v8_num(102));
950}
951
952
953static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
954  return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
955}
956
957
958static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
959  return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
960}
961
962static void construct_callback(
963    const v8::FunctionCallbackInfo<Value>& info) {
964  ApiTestFuzzer::Fuzz();
965  CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
966  info.This()->Set(v8_str("x"), v8_num(1));
967  info.This()->Set(v8_str("y"), v8_num(2));
968  info.GetReturnValue().Set(v8_str("bad value"));
969  info.GetReturnValue().Set(info.This());
970}
971
972
973static void Return239Callback(
974    Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
975  ApiTestFuzzer::Fuzz();
976  CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
977  info.GetReturnValue().Set(v8_str("bad value"));
978  info.GetReturnValue().Set(v8_num(239));
979}
980
981
982template<typename Handler>
983static void TestFunctionTemplateInitializer(Handler handler,
984                                            Handler handler_2) {
985  // Test constructor calls.
986  {
987    LocalContext env;
988    v8::Isolate* isolate = env->GetIsolate();
989    v8::HandleScope scope(isolate);
990
991    Local<v8::FunctionTemplate> fun_templ =
992        v8::FunctionTemplate::New(isolate, handler);
993    Local<Function> fun = fun_templ->GetFunction();
994    env->Global()->Set(v8_str("obj"), fun);
995    Local<Script> script = v8_compile("obj()");
996    for (int i = 0; i < 30; i++) {
997      CHECK_EQ(102, script->Run()->Int32Value());
998    }
999  }
1000  // Use SetCallHandler to initialize a function template, should work like
1001  // the previous one.
1002  {
1003    LocalContext env;
1004    v8::Isolate* isolate = env->GetIsolate();
1005    v8::HandleScope scope(isolate);
1006
1007    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1008    fun_templ->SetCallHandler(handler_2);
1009    Local<Function> fun = fun_templ->GetFunction();
1010    env->Global()->Set(v8_str("obj"), fun);
1011    Local<Script> script = v8_compile("obj()");
1012    for (int i = 0; i < 30; i++) {
1013      CHECK_EQ(102, script->Run()->Int32Value());
1014    }
1015  }
1016}
1017
1018
1019template<typename Constructor, typename Accessor>
1020static void TestFunctionTemplateAccessor(Constructor constructor,
1021                                         Accessor accessor) {
1022  LocalContext env;
1023  v8::HandleScope scope(env->GetIsolate());
1024
1025  Local<v8::FunctionTemplate> fun_templ =
1026      v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1027  fun_templ->SetClassName(v8_str("funky"));
1028  fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1029  Local<Function> fun = fun_templ->GetFunction();
1030  env->Global()->Set(v8_str("obj"), fun);
1031  Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1032  CHECK_EQ(v8_str("[object funky]"), result);
1033  CompileRun("var obj_instance = new obj();");
1034  Local<Script> script;
1035  script = v8_compile("obj_instance.x");
1036  for (int i = 0; i < 30; i++) {
1037    CHECK_EQ(1, script->Run()->Int32Value());
1038  }
1039  script = v8_compile("obj_instance.m");
1040  for (int i = 0; i < 30; i++) {
1041    CHECK_EQ(239, script->Run()->Int32Value());
1042  }
1043}
1044
1045
1046THREADED_PROFILED_TEST(FunctionTemplate) {
1047  TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1048  TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1049}
1050
1051
1052static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1053  ApiTestFuzzer::Fuzz();
1054  CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1055  info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1056}
1057
1058
1059template<typename Callback>
1060static void TestSimpleCallback(Callback callback) {
1061  LocalContext env;
1062  v8::Isolate* isolate = env->GetIsolate();
1063  v8::HandleScope scope(isolate);
1064
1065  v8::Handle<v8::ObjectTemplate> object_template =
1066      v8::ObjectTemplate::New(isolate);
1067  object_template->Set(isolate, "callback",
1068                       v8::FunctionTemplate::New(isolate, callback));
1069  v8::Local<v8::Object> object = object_template->NewInstance();
1070  (*env)->Global()->Set(v8_str("callback_object"), object);
1071  v8::Handle<v8::Script> script;
1072  script = v8_compile("callback_object.callback(17)");
1073  for (int i = 0; i < 30; i++) {
1074    CHECK_EQ(51424, script->Run()->Int32Value());
1075  }
1076  script = v8_compile("callback_object.callback(17, 24)");
1077  for (int i = 0; i < 30; i++) {
1078    CHECK_EQ(51425, script->Run()->Int32Value());
1079  }
1080}
1081
1082
1083THREADED_PROFILED_TEST(SimpleCallback) {
1084  TestSimpleCallback(SimpleCallback);
1085}
1086
1087
1088template<typename T>
1089void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1090
1091// constant return values
1092static int32_t fast_return_value_int32 = 471;
1093static uint32_t fast_return_value_uint32 = 571;
1094static const double kFastReturnValueDouble = 2.7;
1095// variable return values
1096static bool fast_return_value_bool = false;
1097enum ReturnValueOddball {
1098  kNullReturnValue,
1099  kUndefinedReturnValue,
1100  kEmptyStringReturnValue
1101};
1102static ReturnValueOddball fast_return_value_void;
1103static bool fast_return_value_object_is_empty = false;
1104
1105// Helper function to avoid compiler error: insufficient contextual information
1106// to determine type when applying FUNCTION_ADDR to a template function.
1107static i::Address address_of(v8::FunctionCallback callback) {
1108  return FUNCTION_ADDR(callback);
1109}
1110
1111template<>
1112void FastReturnValueCallback<int32_t>(
1113    const v8::FunctionCallbackInfo<v8::Value>& info) {
1114  CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1115  info.GetReturnValue().Set(fast_return_value_int32);
1116}
1117
1118template<>
1119void FastReturnValueCallback<uint32_t>(
1120    const v8::FunctionCallbackInfo<v8::Value>& info) {
1121  CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1122  info.GetReturnValue().Set(fast_return_value_uint32);
1123}
1124
1125template<>
1126void FastReturnValueCallback<double>(
1127    const v8::FunctionCallbackInfo<v8::Value>& info) {
1128  CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1129  info.GetReturnValue().Set(kFastReturnValueDouble);
1130}
1131
1132template<>
1133void FastReturnValueCallback<bool>(
1134    const v8::FunctionCallbackInfo<v8::Value>& info) {
1135  CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1136  info.GetReturnValue().Set(fast_return_value_bool);
1137}
1138
1139template<>
1140void FastReturnValueCallback<void>(
1141    const v8::FunctionCallbackInfo<v8::Value>& info) {
1142  CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1143  switch (fast_return_value_void) {
1144    case kNullReturnValue:
1145      info.GetReturnValue().SetNull();
1146      break;
1147    case kUndefinedReturnValue:
1148      info.GetReturnValue().SetUndefined();
1149      break;
1150    case kEmptyStringReturnValue:
1151      info.GetReturnValue().SetEmptyString();
1152      break;
1153  }
1154}
1155
1156template<>
1157void FastReturnValueCallback<Object>(
1158    const v8::FunctionCallbackInfo<v8::Value>& info) {
1159  v8::Handle<v8::Object> object;
1160  if (!fast_return_value_object_is_empty) {
1161    object = Object::New(info.GetIsolate());
1162  }
1163  info.GetReturnValue().Set(object);
1164}
1165
1166template<typename T>
1167Handle<Value> TestFastReturnValues() {
1168  LocalContext env;
1169  v8::Isolate* isolate = env->GetIsolate();
1170  v8::EscapableHandleScope scope(isolate);
1171  v8::Handle<v8::ObjectTemplate> object_template =
1172      v8::ObjectTemplate::New(isolate);
1173  v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1174  object_template->Set(isolate, "callback",
1175                       v8::FunctionTemplate::New(isolate, callback));
1176  v8::Local<v8::Object> object = object_template->NewInstance();
1177  (*env)->Global()->Set(v8_str("callback_object"), object);
1178  return scope.Escape(CompileRun("callback_object.callback()"));
1179}
1180
1181
1182THREADED_PROFILED_TEST(FastReturnValues) {
1183  LocalContext env;
1184  v8::HandleScope scope(CcTest::isolate());
1185  v8::Handle<v8::Value> value;
1186  // check int32_t and uint32_t
1187  int32_t int_values[] = {
1188      0, 234, -723,
1189      i::Smi::kMinValue, i::Smi::kMaxValue
1190  };
1191  for (size_t i = 0; i < arraysize(int_values); i++) {
1192    for (int modifier = -1; modifier <= 1; modifier++) {
1193      int int_value = int_values[i] + modifier;
1194      // check int32_t
1195      fast_return_value_int32 = int_value;
1196      value = TestFastReturnValues<int32_t>();
1197      CHECK(value->IsInt32());
1198      CHECK(fast_return_value_int32 == value->Int32Value());
1199      // check uint32_t
1200      fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1201      value = TestFastReturnValues<uint32_t>();
1202      CHECK(value->IsUint32());
1203      CHECK(fast_return_value_uint32 == value->Uint32Value());
1204    }
1205  }
1206  // check double
1207  value = TestFastReturnValues<double>();
1208  CHECK(value->IsNumber());
1209  CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1210  // check bool values
1211  for (int i = 0; i < 2; i++) {
1212    fast_return_value_bool = i == 0;
1213    value = TestFastReturnValues<bool>();
1214    CHECK(value->IsBoolean());
1215    CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1216  }
1217  // check oddballs
1218  ReturnValueOddball oddballs[] = {
1219      kNullReturnValue,
1220      kUndefinedReturnValue,
1221      kEmptyStringReturnValue
1222  };
1223  for (size_t i = 0; i < arraysize(oddballs); i++) {
1224    fast_return_value_void = oddballs[i];
1225    value = TestFastReturnValues<void>();
1226    switch (fast_return_value_void) {
1227      case kNullReturnValue:
1228        CHECK(value->IsNull());
1229        break;
1230      case kUndefinedReturnValue:
1231        CHECK(value->IsUndefined());
1232        break;
1233      case kEmptyStringReturnValue:
1234        CHECK(value->IsString());
1235        CHECK_EQ(0, v8::String::Cast(*value)->Length());
1236        break;
1237    }
1238  }
1239  // check handles
1240  fast_return_value_object_is_empty = false;
1241  value = TestFastReturnValues<Object>();
1242  CHECK(value->IsObject());
1243  fast_return_value_object_is_empty = true;
1244  value = TestFastReturnValues<Object>();
1245  CHECK(value->IsUndefined());
1246}
1247
1248
1249THREADED_TEST(FunctionTemplateSetLength) {
1250  LocalContext env;
1251  v8::Isolate* isolate = env->GetIsolate();
1252  v8::HandleScope scope(isolate);
1253  {
1254    Local<v8::FunctionTemplate> fun_templ =
1255        v8::FunctionTemplate::New(isolate,
1256                                  handle_callback,
1257                                  Handle<v8::Value>(),
1258                                  Handle<v8::Signature>(),
1259                                  23);
1260    Local<Function> fun = fun_templ->GetFunction();
1261    env->Global()->Set(v8_str("obj"), fun);
1262    Local<Script> script = v8_compile("obj.length");
1263    CHECK_EQ(23, script->Run()->Int32Value());
1264  }
1265  {
1266    Local<v8::FunctionTemplate> fun_templ =
1267        v8::FunctionTemplate::New(isolate, handle_callback);
1268    fun_templ->SetLength(22);
1269    Local<Function> fun = fun_templ->GetFunction();
1270    env->Global()->Set(v8_str("obj"), fun);
1271    Local<Script> script = v8_compile("obj.length");
1272    CHECK_EQ(22, script->Run()->Int32Value());
1273  }
1274  {
1275    // Without setting length it defaults to 0.
1276    Local<v8::FunctionTemplate> fun_templ =
1277        v8::FunctionTemplate::New(isolate, handle_callback);
1278    Local<Function> fun = fun_templ->GetFunction();
1279    env->Global()->Set(v8_str("obj"), fun);
1280    Local<Script> script = v8_compile("obj.length");
1281    CHECK_EQ(0, script->Run()->Int32Value());
1282  }
1283}
1284
1285
1286static void* expected_ptr;
1287static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1288  void* ptr = v8::External::Cast(*args.Data())->Value();
1289  CHECK_EQ(expected_ptr, ptr);
1290  args.GetReturnValue().Set(true);
1291}
1292
1293
1294static void TestExternalPointerWrapping() {
1295  LocalContext env;
1296  v8::Isolate* isolate = env->GetIsolate();
1297  v8::HandleScope scope(isolate);
1298
1299  v8::Handle<v8::Value> data =
1300      v8::External::New(isolate, expected_ptr);
1301
1302  v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1303  obj->Set(v8_str("func"),
1304           v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1305  env->Global()->Set(v8_str("obj"), obj);
1306
1307  CHECK(CompileRun(
1308        "function foo() {\n"
1309        "  for (var i = 0; i < 13; i++) obj.func();\n"
1310        "}\n"
1311        "foo(), true")->BooleanValue());
1312}
1313
1314
1315THREADED_TEST(ExternalWrap) {
1316  // Check heap allocated object.
1317  int* ptr = new int;
1318  expected_ptr = ptr;
1319  TestExternalPointerWrapping();
1320  delete ptr;
1321
1322  // Check stack allocated object.
1323  int foo;
1324  expected_ptr = &foo;
1325  TestExternalPointerWrapping();
1326
1327  // Check not aligned addresses.
1328  const int n = 100;
1329  char* s = new char[n];
1330  for (int i = 0; i < n; i++) {
1331    expected_ptr = s + i;
1332    TestExternalPointerWrapping();
1333  }
1334
1335  delete[] s;
1336
1337  // Check several invalid addresses.
1338  expected_ptr = reinterpret_cast<void*>(1);
1339  TestExternalPointerWrapping();
1340
1341  expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1342  TestExternalPointerWrapping();
1343
1344  expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1345  TestExternalPointerWrapping();
1346
1347#if defined(V8_HOST_ARCH_X64)
1348  // Check a value with a leading 1 bit in x64 Smi encoding.
1349  expected_ptr = reinterpret_cast<void*>(0x400000000);
1350  TestExternalPointerWrapping();
1351
1352  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1353  TestExternalPointerWrapping();
1354
1355  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1356  TestExternalPointerWrapping();
1357#endif
1358}
1359
1360
1361THREADED_TEST(FindInstanceInPrototypeChain) {
1362  LocalContext env;
1363  v8::Isolate* isolate = env->GetIsolate();
1364  v8::HandleScope scope(isolate);
1365
1366  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1367  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1368  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1369  derived->Inherit(base);
1370
1371  Local<v8::Function> base_function = base->GetFunction();
1372  Local<v8::Function> derived_function = derived->GetFunction();
1373  Local<v8::Function> other_function = other->GetFunction();
1374
1375  Local<v8::Object> base_instance = base_function->NewInstance();
1376  Local<v8::Object> derived_instance = derived_function->NewInstance();
1377  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1378  Local<v8::Object> other_instance = other_function->NewInstance();
1379  derived_instance2->Set(v8_str("__proto__"), derived_instance);
1380  other_instance->Set(v8_str("__proto__"), derived_instance2);
1381
1382  // base_instance is only an instance of base.
1383  CHECK_EQ(base_instance,
1384           base_instance->FindInstanceInPrototypeChain(base));
1385  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1386  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1387
1388  // derived_instance is an instance of base and derived.
1389  CHECK_EQ(derived_instance,
1390           derived_instance->FindInstanceInPrototypeChain(base));
1391  CHECK_EQ(derived_instance,
1392           derived_instance->FindInstanceInPrototypeChain(derived));
1393  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1394
1395  // other_instance is an instance of other and its immediate
1396  // prototype derived_instance2 is an instance of base and derived.
1397  // Note, derived_instance is an instance of base and derived too,
1398  // but it comes after derived_instance2 in the prototype chain of
1399  // other_instance.
1400  CHECK_EQ(derived_instance2,
1401           other_instance->FindInstanceInPrototypeChain(base));
1402  CHECK_EQ(derived_instance2,
1403           other_instance->FindInstanceInPrototypeChain(derived));
1404  CHECK_EQ(other_instance,
1405           other_instance->FindInstanceInPrototypeChain(other));
1406}
1407
1408
1409THREADED_TEST(TinyInteger) {
1410  LocalContext env;
1411  v8::Isolate* isolate = env->GetIsolate();
1412  v8::HandleScope scope(isolate);
1413
1414  int32_t value = 239;
1415  Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1416  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1417
1418  value_obj = v8::Integer::New(isolate, value);
1419  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1420}
1421
1422
1423THREADED_TEST(BigSmiInteger) {
1424  LocalContext env;
1425  v8::HandleScope scope(env->GetIsolate());
1426  v8::Isolate* isolate = CcTest::isolate();
1427
1428  int32_t value = i::Smi::kMaxValue;
1429  // We cannot add one to a Smi::kMaxValue without wrapping.
1430  if (i::SmiValuesAre31Bits()) {
1431    CHECK(i::Smi::IsValid(value));
1432    CHECK(!i::Smi::IsValid(value + 1));
1433
1434    Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1435    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1436
1437    value_obj = v8::Integer::New(isolate, value);
1438    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1439  }
1440}
1441
1442
1443THREADED_TEST(BigInteger) {
1444  LocalContext env;
1445  v8::HandleScope scope(env->GetIsolate());
1446  v8::Isolate* isolate = CcTest::isolate();
1447
1448  // We cannot add one to a Smi::kMaxValue without wrapping.
1449  if (i::SmiValuesAre31Bits()) {
1450    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1451    // The code will not be run in that case, due to the "if" guard.
1452    int32_t value =
1453        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1454    CHECK(value > i::Smi::kMaxValue);
1455    CHECK(!i::Smi::IsValid(value));
1456
1457    Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1458    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1459
1460    value_obj = v8::Integer::New(isolate, value);
1461    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1462  }
1463}
1464
1465
1466THREADED_TEST(TinyUnsignedInteger) {
1467  LocalContext env;
1468  v8::HandleScope scope(env->GetIsolate());
1469  v8::Isolate* isolate = CcTest::isolate();
1470
1471  uint32_t value = 239;
1472
1473  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1474  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1475
1476  value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1477  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1478}
1479
1480
1481THREADED_TEST(BigUnsignedSmiInteger) {
1482  LocalContext env;
1483  v8::HandleScope scope(env->GetIsolate());
1484  v8::Isolate* isolate = CcTest::isolate();
1485
1486  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1487  CHECK(i::Smi::IsValid(value));
1488  CHECK(!i::Smi::IsValid(value + 1));
1489
1490  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1491  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1492
1493  value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1494  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1495}
1496
1497
1498THREADED_TEST(BigUnsignedInteger) {
1499  LocalContext env;
1500  v8::HandleScope scope(env->GetIsolate());
1501  v8::Isolate* isolate = CcTest::isolate();
1502
1503  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1504  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1505  CHECK(!i::Smi::IsValid(value));
1506
1507  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1508  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1509
1510  value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1511  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1512}
1513
1514
1515THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1516  LocalContext env;
1517  v8::HandleScope scope(env->GetIsolate());
1518  v8::Isolate* isolate = CcTest::isolate();
1519
1520  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1521  uint32_t value = INT32_MAX_AS_UINT + 1;
1522  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1523
1524  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1525  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1526
1527  value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1528  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1529}
1530
1531
1532THREADED_TEST(IsNativeError) {
1533  LocalContext env;
1534  v8::HandleScope scope(env->GetIsolate());
1535  v8::Handle<Value> syntax_error = CompileRun(
1536      "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1537  CHECK(syntax_error->IsNativeError());
1538  v8::Handle<Value> not_error = CompileRun("{a:42}");
1539  CHECK(!not_error->IsNativeError());
1540  v8::Handle<Value> not_object = CompileRun("42");
1541  CHECK(!not_object->IsNativeError());
1542}
1543
1544
1545THREADED_TEST(ArgumentsObject) {
1546  LocalContext env;
1547  v8::HandleScope scope(env->GetIsolate());
1548  v8::Handle<Value> arguments_object =
1549      CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1550  CHECK(arguments_object->IsArgumentsObject());
1551  v8::Handle<Value> array = CompileRun("[1,2,3]");
1552  CHECK(!array->IsArgumentsObject());
1553  v8::Handle<Value> object = CompileRun("{a:42}");
1554  CHECK(!object->IsArgumentsObject());
1555}
1556
1557
1558THREADED_TEST(IsMapOrSet) {
1559  LocalContext env;
1560  v8::HandleScope scope(env->GetIsolate());
1561  v8::Handle<Value> map = CompileRun("new Map()");
1562  v8::Handle<Value> set = CompileRun("new Set()");
1563  v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1564  v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1565  CHECK(map->IsMap());
1566  CHECK(set->IsSet());
1567  CHECK(weak_map->IsWeakMap());
1568  CHECK(weak_set->IsWeakSet());
1569
1570  CHECK(!map->IsSet());
1571  CHECK(!map->IsWeakMap());
1572  CHECK(!map->IsWeakSet());
1573
1574  CHECK(!set->IsMap());
1575  CHECK(!set->IsWeakMap());
1576  CHECK(!set->IsWeakSet());
1577
1578  CHECK(!weak_map->IsMap());
1579  CHECK(!weak_map->IsSet());
1580  CHECK(!weak_map->IsWeakSet());
1581
1582  CHECK(!weak_set->IsMap());
1583  CHECK(!weak_set->IsSet());
1584  CHECK(!weak_set->IsWeakMap());
1585
1586  v8::Handle<Value> object = CompileRun("{a:42}");
1587  CHECK(!object->IsMap());
1588  CHECK(!object->IsSet());
1589  CHECK(!object->IsWeakMap());
1590  CHECK(!object->IsWeakSet());
1591}
1592
1593
1594THREADED_TEST(StringObject) {
1595  LocalContext env;
1596  v8::HandleScope scope(env->GetIsolate());
1597  v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1598  CHECK(boxed_string->IsStringObject());
1599  v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1600  CHECK(!unboxed_string->IsStringObject());
1601  v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1602  CHECK(!boxed_not_string->IsStringObject());
1603  v8::Handle<Value> not_object = CompileRun("0");
1604  CHECK(!not_object->IsStringObject());
1605  v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1606  CHECK(!as_boxed.IsEmpty());
1607  Local<v8::String> the_string = as_boxed->ValueOf();
1608  CHECK(!the_string.IsEmpty());
1609  ExpectObject("\"test\"", the_string);
1610  v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1611  CHECK(new_boxed_string->IsStringObject());
1612  as_boxed = new_boxed_string.As<v8::StringObject>();
1613  the_string = as_boxed->ValueOf();
1614  CHECK(!the_string.IsEmpty());
1615  ExpectObject("\"test\"", the_string);
1616}
1617
1618
1619THREADED_TEST(NumberObject) {
1620  LocalContext env;
1621  v8::HandleScope scope(env->GetIsolate());
1622  v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1623  CHECK(boxed_number->IsNumberObject());
1624  v8::Handle<Value> unboxed_number = CompileRun("42");
1625  CHECK(!unboxed_number->IsNumberObject());
1626  v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1627  CHECK(!boxed_not_number->IsNumberObject());
1628  v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1629  CHECK(!as_boxed.IsEmpty());
1630  double the_number = as_boxed->ValueOf();
1631  CHECK_EQ(42.0, the_number);
1632  v8::Handle<v8::Value> new_boxed_number =
1633      v8::NumberObject::New(env->GetIsolate(), 43);
1634  CHECK(new_boxed_number->IsNumberObject());
1635  as_boxed = new_boxed_number.As<v8::NumberObject>();
1636  the_number = as_boxed->ValueOf();
1637  CHECK_EQ(43.0, the_number);
1638}
1639
1640
1641THREADED_TEST(BooleanObject) {
1642  LocalContext env;
1643  v8::HandleScope scope(env->GetIsolate());
1644  v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1645  CHECK(boxed_boolean->IsBooleanObject());
1646  v8::Handle<Value> unboxed_boolean = CompileRun("true");
1647  CHECK(!unboxed_boolean->IsBooleanObject());
1648  v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1649  CHECK(!boxed_not_boolean->IsBooleanObject());
1650  v8::Handle<v8::BooleanObject> as_boxed =
1651      boxed_boolean.As<v8::BooleanObject>();
1652  CHECK(!as_boxed.IsEmpty());
1653  bool the_boolean = as_boxed->ValueOf();
1654  CHECK_EQ(true, the_boolean);
1655  v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1656  v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1657  CHECK(boxed_true->IsBooleanObject());
1658  CHECK(boxed_false->IsBooleanObject());
1659  as_boxed = boxed_true.As<v8::BooleanObject>();
1660  CHECK_EQ(true, as_boxed->ValueOf());
1661  as_boxed = boxed_false.As<v8::BooleanObject>();
1662  CHECK_EQ(false, as_boxed->ValueOf());
1663}
1664
1665
1666THREADED_TEST(PrimitiveAndWrappedBooleans) {
1667  LocalContext env;
1668  v8::HandleScope scope(env->GetIsolate());
1669
1670  Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1671  CHECK(primitive_false->IsBoolean());
1672  CHECK(!primitive_false->IsBooleanObject());
1673  CHECK(!primitive_false->BooleanValue());
1674  CHECK(!primitive_false->IsTrue());
1675  CHECK(primitive_false->IsFalse());
1676
1677  Local<Value> false_value = BooleanObject::New(false);
1678  CHECK(!false_value->IsBoolean());
1679  CHECK(false_value->IsBooleanObject());
1680  CHECK(false_value->BooleanValue());
1681  CHECK(!false_value->IsTrue());
1682  CHECK(!false_value->IsFalse());
1683
1684  Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1685  CHECK(!false_boolean_object->IsBoolean());
1686  CHECK(false_boolean_object->IsBooleanObject());
1687  // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1688  // CHECK(false_boolean_object->BooleanValue());
1689  CHECK(!false_boolean_object->ValueOf());
1690  CHECK(!false_boolean_object->IsTrue());
1691  CHECK(!false_boolean_object->IsFalse());
1692
1693  Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1694  CHECK(primitive_true->IsBoolean());
1695  CHECK(!primitive_true->IsBooleanObject());
1696  CHECK(primitive_true->BooleanValue());
1697  CHECK(primitive_true->IsTrue());
1698  CHECK(!primitive_true->IsFalse());
1699
1700  Local<Value> true_value = BooleanObject::New(true);
1701  CHECK(!true_value->IsBoolean());
1702  CHECK(true_value->IsBooleanObject());
1703  CHECK(true_value->BooleanValue());
1704  CHECK(!true_value->IsTrue());
1705  CHECK(!true_value->IsFalse());
1706
1707  Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1708  CHECK(!true_boolean_object->IsBoolean());
1709  CHECK(true_boolean_object->IsBooleanObject());
1710  // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1711  // CHECK(true_boolean_object->BooleanValue());
1712  CHECK(true_boolean_object->ValueOf());
1713  CHECK(!true_boolean_object->IsTrue());
1714  CHECK(!true_boolean_object->IsFalse());
1715}
1716
1717
1718THREADED_TEST(Number) {
1719  LocalContext env;
1720  v8::HandleScope scope(env->GetIsolate());
1721  double PI = 3.1415926;
1722  Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1723  CHECK_EQ(PI, pi_obj->NumberValue());
1724}
1725
1726
1727THREADED_TEST(ToNumber) {
1728  LocalContext env;
1729  v8::Isolate* isolate = CcTest::isolate();
1730  v8::HandleScope scope(isolate);
1731  Local<String> str = v8_str("3.1415926");
1732  CHECK_EQ(3.1415926, str->NumberValue());
1733  v8::Handle<v8::Boolean> t = v8::True(isolate);
1734  CHECK_EQ(1.0, t->NumberValue());
1735  v8::Handle<v8::Boolean> f = v8::False(isolate);
1736  CHECK_EQ(0.0, f->NumberValue());
1737}
1738
1739
1740THREADED_TEST(Date) {
1741  LocalContext env;
1742  v8::HandleScope scope(env->GetIsolate());
1743  double PI = 3.1415926;
1744  Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1745  CHECK_EQ(3.0, date->NumberValue());
1746  date.As<v8::Date>()->Set(v8_str("property"),
1747                           v8::Integer::New(env->GetIsolate(), 42));
1748  CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1749}
1750
1751
1752THREADED_TEST(Boolean) {
1753  LocalContext env;
1754  v8::Isolate* isolate = env->GetIsolate();
1755  v8::HandleScope scope(isolate);
1756  v8::Handle<v8::Boolean> t = v8::True(isolate);
1757  CHECK(t->Value());
1758  v8::Handle<v8::Boolean> f = v8::False(isolate);
1759  CHECK(!f->Value());
1760  v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1761  CHECK(!u->BooleanValue());
1762  v8::Handle<v8::Primitive> n = v8::Null(isolate);
1763  CHECK(!n->BooleanValue());
1764  v8::Handle<String> str1 = v8_str("");
1765  CHECK(!str1->BooleanValue());
1766  v8::Handle<String> str2 = v8_str("x");
1767  CHECK(str2->BooleanValue());
1768  CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1769  CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1770  CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1771  CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1772  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1773}
1774
1775
1776static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1777  ApiTestFuzzer::Fuzz();
1778  args.GetReturnValue().Set(v8_num(13.4));
1779}
1780
1781
1782static void GetM(Local<String> name,
1783                 const v8::PropertyCallbackInfo<v8::Value>& info) {
1784  ApiTestFuzzer::Fuzz();
1785  info.GetReturnValue().Set(v8_num(876));
1786}
1787
1788
1789THREADED_TEST(GlobalPrototype) {
1790  v8::Isolate* isolate = CcTest::isolate();
1791  v8::HandleScope scope(isolate);
1792  v8::Handle<v8::FunctionTemplate> func_templ =
1793      v8::FunctionTemplate::New(isolate);
1794  func_templ->PrototypeTemplate()->Set(
1795      isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1796  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1797  templ->Set(isolate, "x", v8_num(200));
1798  templ->SetAccessor(v8_str("m"), GetM);
1799  LocalContext env(0, templ);
1800  v8::Handle<Script> script(v8_compile("dummy()"));
1801  v8::Handle<Value> result(script->Run());
1802  CHECK_EQ(13.4, result->NumberValue());
1803  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1804  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1805}
1806
1807
1808THREADED_TEST(ObjectTemplate) {
1809  v8::Isolate* isolate = CcTest::isolate();
1810  v8::HandleScope scope(isolate);
1811  Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1812  templ1->Set(isolate, "x", v8_num(10));
1813  templ1->Set(isolate, "y", v8_num(13));
1814  LocalContext env;
1815  Local<v8::Object> instance1 = templ1->NewInstance();
1816  env->Global()->Set(v8_str("p"), instance1);
1817  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1818  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1819  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1820  fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1821  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1822  templ2->Set(isolate, "a", v8_num(12));
1823  templ2->Set(isolate, "b", templ1);
1824  Local<v8::Object> instance2 = templ2->NewInstance();
1825  env->Global()->Set(v8_str("q"), instance2);
1826  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1827  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1828  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1829  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1830}
1831
1832
1833static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1834  ApiTestFuzzer::Fuzz();
1835  args.GetReturnValue().Set(v8_num(17.2));
1836}
1837
1838
1839static void GetKnurd(Local<String> property,
1840                     const v8::PropertyCallbackInfo<v8::Value>& info) {
1841  ApiTestFuzzer::Fuzz();
1842  info.GetReturnValue().Set(v8_num(15.2));
1843}
1844
1845
1846THREADED_TEST(DescriptorInheritance) {
1847  v8::Isolate* isolate = CcTest::isolate();
1848  v8::HandleScope scope(isolate);
1849  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1850  super->PrototypeTemplate()->Set(isolate, "flabby",
1851                                  v8::FunctionTemplate::New(isolate,
1852                                                            GetFlabby));
1853  super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1854
1855  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1856
1857  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1858  base1->Inherit(super);
1859  base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1860
1861  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1862  base2->Inherit(super);
1863  base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1864
1865  LocalContext env;
1866
1867  env->Global()->Set(v8_str("s"), super->GetFunction());
1868  env->Global()->Set(v8_str("base1"), base1->GetFunction());
1869  env->Global()->Set(v8_str("base2"), base2->GetFunction());
1870
1871  // Checks right __proto__ chain.
1872  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1873  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1874
1875  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1876
1877  // Instance accessor should not be visible on function object or its prototype
1878  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1879  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1880  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1881
1882  env->Global()->Set(v8_str("obj"),
1883                     base1->GetFunction()->NewInstance());
1884  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1885  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1886  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1887  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1888  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1889
1890  env->Global()->Set(v8_str("obj2"),
1891                     base2->GetFunction()->NewInstance());
1892  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1893  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1894  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1895  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1896  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1897
1898  // base1 and base2 cannot cross reference to each's prototype
1899  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1900  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1901}
1902
1903
1904int echo_named_call_count;
1905
1906
1907static void EchoNamedProperty(Local<String> name,
1908                              const v8::PropertyCallbackInfo<v8::Value>& info) {
1909  ApiTestFuzzer::Fuzz();
1910  CHECK_EQ(v8_str("data"), info.Data());
1911  echo_named_call_count++;
1912  info.GetReturnValue().Set(name);
1913}
1914
1915
1916// Helper functions for Interceptor/Accessor interaction tests
1917
1918void SimpleAccessorGetter(Local<String> name,
1919                          const v8::PropertyCallbackInfo<v8::Value>& info) {
1920  Handle<Object> self = Handle<Object>::Cast(info.This());
1921  info.GetReturnValue().Set(
1922      self->Get(String::Concat(v8_str("accessor_"), name)));
1923}
1924
1925void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1926                          const v8::PropertyCallbackInfo<void>& info) {
1927  Handle<Object> self = Handle<Object>::Cast(info.This());
1928  self->Set(String::Concat(v8_str("accessor_"), name), value);
1929}
1930
1931void SymbolAccessorGetter(Local<Name> name,
1932                          const v8::PropertyCallbackInfo<v8::Value>& info) {
1933  CHECK(name->IsSymbol());
1934  Local<Symbol> sym = Local<Symbol>::Cast(name);
1935  if (sym->Name()->IsUndefined())
1936    return;
1937  SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
1938}
1939
1940void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
1941                          const v8::PropertyCallbackInfo<void>& info) {
1942  CHECK(name->IsSymbol());
1943  Local<Symbol> sym = Local<Symbol>::Cast(name);
1944  if (sym->Name()->IsUndefined())
1945    return;
1946  SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
1947}
1948
1949void EmptyInterceptorGetter(Local<String> name,
1950                            const v8::PropertyCallbackInfo<v8::Value>& info) {
1951}
1952
1953void EmptyInterceptorSetter(Local<String> name,
1954                            Local<Value> value,
1955                            const v8::PropertyCallbackInfo<v8::Value>& info) {
1956}
1957
1958void InterceptorGetter(Local<String> name,
1959                       const v8::PropertyCallbackInfo<v8::Value>& info) {
1960  // Intercept names that start with 'interceptor_'.
1961  String::Utf8Value utf8(name);
1962  char* name_str = *utf8;
1963  char prefix[] = "interceptor_";
1964  int i;
1965  for (i = 0; name_str[i] && prefix[i]; ++i) {
1966    if (name_str[i] != prefix[i]) return;
1967  }
1968  Handle<Object> self = Handle<Object>::Cast(info.This());
1969  info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1970}
1971
1972void InterceptorSetter(Local<String> name,
1973                       Local<Value> value,
1974                       const v8::PropertyCallbackInfo<v8::Value>& info) {
1975  // Intercept accesses that set certain integer values, for which the name does
1976  // not start with 'accessor_'.
1977  String::Utf8Value utf8(name);
1978  char* name_str = *utf8;
1979  char prefix[] = "accessor_";
1980  int i;
1981  for (i = 0; name_str[i] && prefix[i]; ++i) {
1982    if (name_str[i] != prefix[i]) break;
1983  }
1984  if (!prefix[i]) return;
1985
1986  if (value->IsInt32() && value->Int32Value() < 10000) {
1987    Handle<Object> self = Handle<Object>::Cast(info.This());
1988    self->SetHiddenValue(name, value);
1989    info.GetReturnValue().Set(value);
1990  }
1991}
1992
1993void AddAccessor(Handle<FunctionTemplate> templ,
1994                 Handle<String> name,
1995                 v8::AccessorGetterCallback getter,
1996                 v8::AccessorSetterCallback setter) {
1997  templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1998}
1999
2000void AddInterceptor(Handle<FunctionTemplate> templ,
2001                    v8::NamedPropertyGetterCallback getter,
2002                    v8::NamedPropertySetterCallback setter) {
2003  templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
2004}
2005
2006
2007void AddAccessor(Handle<FunctionTemplate> templ,
2008                 Handle<Name> name,
2009                 v8::AccessorNameGetterCallback getter,
2010                 v8::AccessorNameSetterCallback setter) {
2011  templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2012}
2013
2014
2015THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
2016  v8::HandleScope scope(CcTest::isolate());
2017  Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2018  Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2019  child->Inherit(parent);
2020  AddAccessor(parent, v8_str("age"),
2021              SimpleAccessorGetter, SimpleAccessorSetter);
2022  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2023  LocalContext env;
2024  env->Global()->Set(v8_str("Child"), child->GetFunction());
2025  CompileRun("var child = new Child;"
2026             "child.age = 10;");
2027  ExpectBoolean("child.hasOwnProperty('age')", false);
2028  ExpectInt32("child.age", 10);
2029  ExpectInt32("child.accessor_age", 10);
2030}
2031
2032
2033THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
2034  v8::Isolate* isolate = CcTest::isolate();
2035  v8::HandleScope scope(isolate);
2036  LocalContext env;
2037  v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2038  i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2039  CHECK(a->map()->instance_descriptors()->IsFixedArray());
2040  CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2041  CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2042  CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2043  // But we should still have an ExecutableAccessorInfo.
2044  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2045  i::LookupResult lookup(i_isolate);
2046  i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2047  i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2048  CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2049  CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
2050}
2051
2052
2053THREADED_TEST(EmptyInterceptorBreakTransitions) {
2054  v8::HandleScope scope(CcTest::isolate());
2055  Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2056  AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2057  LocalContext env;
2058  env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2059  CompileRun("var o1 = new Constructor;"
2060             "o1.a = 1;"  // Ensure a and x share the descriptor array.
2061             "Object.defineProperty(o1, 'x', {value: 10});");
2062  CompileRun("var o2 = new Constructor;"
2063             "o2.a = 1;"
2064             "Object.defineProperty(o2, 'x', {value: 10});");
2065}
2066
2067
2068THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2069  v8::Isolate* isolate = CcTest::isolate();
2070  v8::HandleScope scope(isolate);
2071  Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2072  Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2073  child->Inherit(parent);
2074  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2075  LocalContext env;
2076  env->Global()->Set(v8_str("Child"), child->GetFunction());
2077  CompileRun("var child = new Child;"
2078             "var parent = child.__proto__;"
2079             "Object.defineProperty(parent, 'age', "
2080             "  {get: function(){ return this.accessor_age; }, "
2081             "   set: function(v){ this.accessor_age = v; }, "
2082             "   enumerable: true, configurable: true});"
2083             "child.age = 10;");
2084  ExpectBoolean("child.hasOwnProperty('age')", false);
2085  ExpectInt32("child.age", 10);
2086  ExpectInt32("child.accessor_age", 10);
2087}
2088
2089
2090THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2091  v8::Isolate* isolate = CcTest::isolate();
2092  v8::HandleScope scope(isolate);
2093  Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2094  Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2095  child->Inherit(parent);
2096  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2097  LocalContext env;
2098  env->Global()->Set(v8_str("Child"), child->GetFunction());
2099  CompileRun("var child = new Child;"
2100             "var parent = child.__proto__;"
2101             "parent.name = 'Alice';");
2102  ExpectBoolean("child.hasOwnProperty('name')", false);
2103  ExpectString("child.name", "Alice");
2104  CompileRun("child.name = 'Bob';");
2105  ExpectString("child.name", "Bob");
2106  ExpectBoolean("child.hasOwnProperty('name')", true);
2107  ExpectString("parent.name", "Alice");
2108}
2109
2110
2111THREADED_TEST(SwitchFromInterceptorToAccessor) {
2112  v8::HandleScope scope(CcTest::isolate());
2113  Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2114  AddAccessor(templ, v8_str("age"),
2115              SimpleAccessorGetter, SimpleAccessorSetter);
2116  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2117  LocalContext env;
2118  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2119  CompileRun("var obj = new Obj;"
2120             "function setAge(i){ obj.age = i; };"
2121             "for(var i = 0; i <= 10000; i++) setAge(i);");
2122  // All i < 10000 go to the interceptor.
2123  ExpectInt32("obj.interceptor_age", 9999);
2124  // The last i goes to the accessor.
2125  ExpectInt32("obj.accessor_age", 10000);
2126}
2127
2128
2129THREADED_TEST(SwitchFromAccessorToInterceptor) {
2130  v8::HandleScope scope(CcTest::isolate());
2131  Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2132  AddAccessor(templ, v8_str("age"),
2133              SimpleAccessorGetter, SimpleAccessorSetter);
2134  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2135  LocalContext env;
2136  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2137  CompileRun("var obj = new Obj;"
2138             "function setAge(i){ obj.age = i; };"
2139             "for(var i = 20000; i >= 9999; i--) setAge(i);");
2140  // All i >= 10000 go to the accessor.
2141  ExpectInt32("obj.accessor_age", 10000);
2142  // The last i goes to the interceptor.
2143  ExpectInt32("obj.interceptor_age", 9999);
2144}
2145
2146
2147THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2148  v8::HandleScope scope(CcTest::isolate());
2149  Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2150  Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2151  child->Inherit(parent);
2152  AddAccessor(parent, v8_str("age"),
2153              SimpleAccessorGetter, SimpleAccessorSetter);
2154  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2155  LocalContext env;
2156  env->Global()->Set(v8_str("Child"), child->GetFunction());
2157  CompileRun("var child = new Child;"
2158             "function setAge(i){ child.age = i; };"
2159             "for(var i = 0; i <= 10000; i++) setAge(i);");
2160  // All i < 10000 go to the interceptor.
2161  ExpectInt32("child.interceptor_age", 9999);
2162  // The last i goes to the accessor.
2163  ExpectInt32("child.accessor_age", 10000);
2164}
2165
2166
2167THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2168  v8::HandleScope scope(CcTest::isolate());
2169  Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2170  Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2171  child->Inherit(parent);
2172  AddAccessor(parent, v8_str("age"),
2173              SimpleAccessorGetter, SimpleAccessorSetter);
2174  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2175  LocalContext env;
2176  env->Global()->Set(v8_str("Child"), child->GetFunction());
2177  CompileRun("var child = new Child;"
2178             "function setAge(i){ child.age = i; };"
2179             "for(var i = 20000; i >= 9999; i--) setAge(i);");
2180  // All i >= 10000 go to the accessor.
2181  ExpectInt32("child.accessor_age", 10000);
2182  // The last i goes to the interceptor.
2183  ExpectInt32("child.interceptor_age", 9999);
2184}
2185
2186
2187THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2188  v8::HandleScope scope(CcTest::isolate());
2189  Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2190  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2191  LocalContext env;
2192  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2193  CompileRun("var obj = new Obj;"
2194             "function setter(i) { this.accessor_age = i; };"
2195             "function getter() { return this.accessor_age; };"
2196             "function setAge(i) { obj.age = i; };"
2197             "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2198             "for(var i = 0; i <= 10000; i++) setAge(i);");
2199  // All i < 10000 go to the interceptor.
2200  ExpectInt32("obj.interceptor_age", 9999);
2201  // The last i goes to the JavaScript accessor.
2202  ExpectInt32("obj.accessor_age", 10000);
2203  // The installed JavaScript getter is still intact.
2204  // This last part is a regression test for issue 1651 and relies on the fact
2205  // that both interceptor and accessor are being installed on the same object.
2206  ExpectInt32("obj.age", 10000);
2207  ExpectBoolean("obj.hasOwnProperty('age')", true);
2208  ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2209}
2210
2211
2212THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2213  v8::HandleScope scope(CcTest::isolate());
2214  Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2215  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2216  LocalContext env;
2217  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2218  CompileRun("var obj = new Obj;"
2219             "function setter(i) { this.accessor_age = i; };"
2220             "function getter() { return this.accessor_age; };"
2221             "function setAge(i) { obj.age = i; };"
2222             "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2223             "for(var i = 20000; i >= 9999; i--) setAge(i);");
2224  // All i >= 10000 go to the accessor.
2225  ExpectInt32("obj.accessor_age", 10000);
2226  // The last i goes to the interceptor.
2227  ExpectInt32("obj.interceptor_age", 9999);
2228  // The installed JavaScript getter is still intact.
2229  // This last part is a regression test for issue 1651 and relies on the fact
2230  // that both interceptor and accessor are being installed on the same object.
2231  ExpectInt32("obj.age", 10000);
2232  ExpectBoolean("obj.hasOwnProperty('age')", true);
2233  ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2234}
2235
2236
2237THREADED_TEST(SwitchFromInterceptorToProperty) {
2238  v8::HandleScope scope(CcTest::isolate());
2239  Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2240  Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2241  child->Inherit(parent);
2242  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2243  LocalContext env;
2244  env->Global()->Set(v8_str("Child"), child->GetFunction());
2245  CompileRun("var child = new Child;"
2246             "function setAge(i){ child.age = i; };"
2247             "for(var i = 0; i <= 10000; i++) setAge(i);");
2248  // All i < 10000 go to the interceptor.
2249  ExpectInt32("child.interceptor_age", 9999);
2250  // The last i goes to child's own property.
2251  ExpectInt32("child.age", 10000);
2252}
2253
2254
2255THREADED_TEST(SwitchFromPropertyToInterceptor) {
2256  v8::HandleScope scope(CcTest::isolate());
2257  Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2258  Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2259  child->Inherit(parent);
2260  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2261  LocalContext env;
2262  env->Global()->Set(v8_str("Child"), child->GetFunction());
2263  CompileRun("var child = new Child;"
2264             "function setAge(i){ child.age = i; };"
2265             "for(var i = 20000; i >= 9999; i--) setAge(i);");
2266  // All i >= 10000 go to child's own property.
2267  ExpectInt32("child.age", 10000);
2268  // The last i goes to the interceptor.
2269  ExpectInt32("child.interceptor_age", 9999);
2270}
2271
2272
2273THREADED_TEST(NamedPropertyHandlerGetter) {
2274  echo_named_call_count = 0;
2275  v8::HandleScope scope(CcTest::isolate());
2276  v8::Handle<v8::FunctionTemplate> templ =
2277      v8::FunctionTemplate::New(CcTest::isolate());
2278  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2279                                                     0, 0, 0, 0,
2280                                                     v8_str("data"));
2281  LocalContext env;
2282  env->Global()->Set(v8_str("obj"),
2283                     templ->GetFunction()->NewInstance());
2284  CHECK_EQ(echo_named_call_count, 0);
2285  v8_compile("obj.x")->Run();
2286  CHECK_EQ(echo_named_call_count, 1);
2287  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2288  v8::Handle<Value> str = CompileRun(code);
2289  String::Utf8Value value(str);
2290  CHECK_EQ(*value, "oddlepoddle");
2291  // Check default behavior
2292  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2293  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2294  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2295}
2296
2297
2298int echo_indexed_call_count = 0;
2299
2300
2301static void EchoIndexedProperty(
2302    uint32_t index,
2303    const v8::PropertyCallbackInfo<v8::Value>& info) {
2304  ApiTestFuzzer::Fuzz();
2305  CHECK_EQ(v8_num(637), info.Data());
2306  echo_indexed_call_count++;
2307  info.GetReturnValue().Set(v8_num(index));
2308}
2309
2310
2311THREADED_TEST(IndexedPropertyHandlerGetter) {
2312  v8::Isolate* isolate = CcTest::isolate();
2313  v8::HandleScope scope(isolate);
2314  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2315  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2316                                                       0, 0, 0, 0,
2317                                                       v8_num(637));
2318  LocalContext env;
2319  env->Global()->Set(v8_str("obj"),
2320                     templ->GetFunction()->NewInstance());
2321  Local<Script> script = v8_compile("obj[900]");
2322  CHECK_EQ(script->Run()->Int32Value(), 900);
2323}
2324
2325
2326v8::Handle<v8::Object> bottom;
2327
2328static void CheckThisIndexedPropertyHandler(
2329    uint32_t index,
2330    const v8::PropertyCallbackInfo<v8::Value>& info) {
2331  CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2332  ApiTestFuzzer::Fuzz();
2333  CHECK(info.This()->Equals(bottom));
2334}
2335
2336static void CheckThisNamedPropertyHandler(
2337    Local<String> name,
2338    const v8::PropertyCallbackInfo<v8::Value>& info) {
2339  CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2340  ApiTestFuzzer::Fuzz();
2341  CHECK(info.This()->Equals(bottom));
2342}
2343
2344void CheckThisIndexedPropertySetter(
2345    uint32_t index,
2346    Local<Value> value,
2347    const v8::PropertyCallbackInfo<v8::Value>& info) {
2348  CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2349  ApiTestFuzzer::Fuzz();
2350  CHECK(info.This()->Equals(bottom));
2351}
2352
2353
2354void CheckThisNamedPropertySetter(
2355    Local<String> property,
2356    Local<Value> value,
2357    const v8::PropertyCallbackInfo<v8::Value>& info) {
2358  CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2359  ApiTestFuzzer::Fuzz();
2360  CHECK(info.This()->Equals(bottom));
2361}
2362
2363void CheckThisIndexedPropertyQuery(
2364    uint32_t index,
2365    const v8::PropertyCallbackInfo<v8::Integer>& info) {
2366  CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2367  ApiTestFuzzer::Fuzz();
2368  CHECK(info.This()->Equals(bottom));
2369}
2370
2371
2372void CheckThisNamedPropertyQuery(
2373    Local<String> property,
2374    const v8::PropertyCallbackInfo<v8::Integer>& info) {
2375  CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2376  ApiTestFuzzer::Fuzz();
2377  CHECK(info.This()->Equals(bottom));
2378}
2379
2380
2381void CheckThisIndexedPropertyDeleter(
2382    uint32_t index,
2383    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2384  CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2385  ApiTestFuzzer::Fuzz();
2386  CHECK(info.This()->Equals(bottom));
2387}
2388
2389
2390void CheckThisNamedPropertyDeleter(
2391    Local<String> property,
2392    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2393  CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2394  ApiTestFuzzer::Fuzz();
2395  CHECK(info.This()->Equals(bottom));
2396}
2397
2398
2399void CheckThisIndexedPropertyEnumerator(
2400    const v8::PropertyCallbackInfo<v8::Array>& info) {
2401  CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2402  ApiTestFuzzer::Fuzz();
2403  CHECK(info.This()->Equals(bottom));
2404}
2405
2406
2407void CheckThisNamedPropertyEnumerator(
2408    const v8::PropertyCallbackInfo<v8::Array>& info) {
2409  CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2410  ApiTestFuzzer::Fuzz();
2411  CHECK(info.This()->Equals(bottom));
2412}
2413
2414
2415THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2416  LocalContext env;
2417  v8::Isolate* isolate = env->GetIsolate();
2418  v8::HandleScope scope(isolate);
2419
2420  // Set up a prototype chain with three interceptors.
2421  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2422  templ->InstanceTemplate()->SetIndexedPropertyHandler(
2423      CheckThisIndexedPropertyHandler,
2424      CheckThisIndexedPropertySetter,
2425      CheckThisIndexedPropertyQuery,
2426      CheckThisIndexedPropertyDeleter,
2427      CheckThisIndexedPropertyEnumerator);
2428
2429  templ->InstanceTemplate()->SetNamedPropertyHandler(
2430      CheckThisNamedPropertyHandler,
2431      CheckThisNamedPropertySetter,
2432      CheckThisNamedPropertyQuery,
2433      CheckThisNamedPropertyDeleter,
2434      CheckThisNamedPropertyEnumerator);
2435
2436  bottom = templ->GetFunction()->NewInstance();
2437  Local<v8::Object> top = templ->GetFunction()->NewInstance();
2438  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2439
2440  bottom->SetPrototype(middle);
2441  middle->SetPrototype(top);
2442  env->Global()->Set(v8_str("obj"), bottom);
2443
2444  // Indexed and named get.
2445  CompileRun("obj[0]");
2446  CompileRun("obj.x");
2447
2448  // Indexed and named set.
2449  CompileRun("obj[1] = 42");
2450  CompileRun("obj.y = 42");
2451
2452  // Indexed and named query.
2453  CompileRun("0 in obj");
2454  CompileRun("'x' in obj");
2455
2456  // Indexed and named deleter.
2457  CompileRun("delete obj[0]");
2458  CompileRun("delete obj.x");
2459
2460  // Enumerators.
2461  CompileRun("for (var p in obj) ;");
2462}
2463
2464
2465static void PrePropertyHandlerGet(
2466    Local<String> key,
2467    const v8::PropertyCallbackInfo<v8::Value>& info) {
2468  ApiTestFuzzer::Fuzz();
2469  if (v8_str("pre")->Equals(key)) {
2470    info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2471  }
2472}
2473
2474
2475static void PrePropertyHandlerQuery(
2476    Local<String> key,
2477    const v8::PropertyCallbackInfo<v8::Integer>& info) {
2478  if (v8_str("pre")->Equals(key)) {
2479    info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2480  }
2481}
2482
2483
2484THREADED_TEST(PrePropertyHandler) {
2485  v8::Isolate* isolate = CcTest::isolate();
2486  v8::HandleScope scope(isolate);
2487  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2488  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2489                                                    0,
2490                                                    PrePropertyHandlerQuery);
2491  LocalContext env(NULL, desc->InstanceTemplate());
2492  CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2493  v8::Handle<Value> result_pre = CompileRun("pre");
2494  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2495  v8::Handle<Value> result_on = CompileRun("on");
2496  CHECK_EQ(v8_str("Object: on"), result_on);
2497  v8::Handle<Value> result_post = CompileRun("post");
2498  CHECK(result_post.IsEmpty());
2499}
2500
2501
2502THREADED_TEST(UndefinedIsNotEnumerable) {
2503  LocalContext env;
2504  v8::HandleScope scope(env->GetIsolate());
2505  v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2506  CHECK(result->IsFalse());
2507}
2508
2509
2510v8::Handle<Script> call_recursively_script;
2511static const int kTargetRecursionDepth = 200;  // near maximum
2512
2513
2514static void CallScriptRecursivelyCall(
2515    const v8::FunctionCallbackInfo<v8::Value>& args) {
2516  ApiTestFuzzer::Fuzz();
2517  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2518  if (depth == kTargetRecursionDepth) return;
2519  args.This()->Set(v8_str("depth"),
2520                   v8::Integer::New(args.GetIsolate(), depth + 1));
2521  args.GetReturnValue().Set(call_recursively_script->Run());
2522}
2523
2524
2525static void CallFunctionRecursivelyCall(
2526    const v8::FunctionCallbackInfo<v8::Value>& args) {
2527  ApiTestFuzzer::Fuzz();
2528  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2529  if (depth == kTargetRecursionDepth) {
2530    printf("[depth = %d]\n", depth);
2531    return;
2532  }
2533  args.This()->Set(v8_str("depth"),
2534                   v8::Integer::New(args.GetIsolate(), depth + 1));
2535  v8::Handle<Value> function =
2536      args.This()->Get(v8_str("callFunctionRecursively"));
2537  args.GetReturnValue().Set(
2538      function.As<Function>()->Call(args.This(), 0, NULL));
2539}
2540
2541
2542THREADED_TEST(DeepCrossLanguageRecursion) {
2543  v8::Isolate* isolate = CcTest::isolate();
2544  v8::HandleScope scope(isolate);
2545  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2546  global->Set(v8_str("callScriptRecursively"),
2547              v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2548  global->Set(v8_str("callFunctionRecursively"),
2549              v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2550  LocalContext env(NULL, global);
2551
2552  env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2553  call_recursively_script = v8_compile("callScriptRecursively()");
2554  call_recursively_script->Run();
2555  call_recursively_script = v8::Handle<Script>();
2556
2557  env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2558  CompileRun("callFunctionRecursively()");
2559}
2560
2561
2562static void ThrowingPropertyHandlerGet(
2563    Local<String> key,
2564    const v8::PropertyCallbackInfo<v8::Value>& info) {
2565  ApiTestFuzzer::Fuzz();
2566  info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2567}
2568
2569
2570static void ThrowingPropertyHandlerSet(
2571    Local<String> key,
2572    Local<Value>,
2573    const v8::PropertyCallbackInfo<v8::Value>& info) {
2574  info.GetIsolate()->ThrowException(key);
2575  info.GetReturnValue().SetUndefined();  // not the same as empty handle
2576}
2577
2578
2579THREADED_TEST(CallbackExceptionRegression) {
2580  v8::Isolate* isolate = CcTest::isolate();
2581  v8::HandleScope scope(isolate);
2582  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2583  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2584                               ThrowingPropertyHandlerSet);
2585  LocalContext env;
2586  env->Global()->Set(v8_str("obj"), obj->NewInstance());
2587  v8::Handle<Value> otto = CompileRun(
2588      "try { with (obj) { otto; } } catch (e) { e; }");
2589  CHECK_EQ(v8_str("otto"), otto);
2590  v8::Handle<Value> netto = CompileRun(
2591      "try { with (obj) { netto = 4; } } catch (e) { e; }");
2592  CHECK_EQ(v8_str("netto"), netto);
2593}
2594
2595
2596THREADED_TEST(FunctionPrototype) {
2597  v8::Isolate* isolate = CcTest::isolate();
2598  v8::HandleScope scope(isolate);
2599  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2600  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2601  LocalContext env;
2602  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2603  Local<Script> script = v8_compile("Foo.prototype.plak");
2604  CHECK_EQ(script->Run()->Int32Value(), 321);
2605}
2606
2607
2608THREADED_TEST(InternalFields) {
2609  LocalContext env;
2610  v8::Isolate* isolate = env->GetIsolate();
2611  v8::HandleScope scope(isolate);
2612
2613  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2614  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2615  instance_templ->SetInternalFieldCount(1);
2616  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2617  CHECK_EQ(1, obj->InternalFieldCount());
2618  CHECK(obj->GetInternalField(0)->IsUndefined());
2619  obj->SetInternalField(0, v8_num(17));
2620  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2621}
2622
2623
2624THREADED_TEST(GlobalObjectInternalFields) {
2625  v8::Isolate* isolate = CcTest::isolate();
2626  v8::HandleScope scope(isolate);
2627  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2628  global_template->SetInternalFieldCount(1);
2629  LocalContext env(NULL, global_template);
2630  v8::Handle<v8::Object> global_proxy = env->Global();
2631  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2632  CHECK_EQ(1, global->InternalFieldCount());
2633  CHECK(global->GetInternalField(0)->IsUndefined());
2634  global->SetInternalField(0, v8_num(17));
2635  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2636}
2637
2638
2639THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2640  LocalContext env;
2641  v8::HandleScope scope(CcTest::isolate());
2642
2643  v8::Local<v8::Object> global = env->Global();
2644  global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2645  CHECK(global->HasRealIndexedProperty(0));
2646}
2647
2648
2649static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2650                                               void* value) {
2651  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2652  obj->SetAlignedPointerInInternalField(0, value);
2653  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2654  CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2655}
2656
2657
2658THREADED_TEST(InternalFieldsAlignedPointers) {
2659  LocalContext env;
2660  v8::Isolate* isolate = env->GetIsolate();
2661  v8::HandleScope scope(isolate);
2662
2663  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2664  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2665  instance_templ->SetInternalFieldCount(1);
2666  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2667  CHECK_EQ(1, obj->InternalFieldCount());
2668
2669  CheckAlignedPointerInInternalField(obj, NULL);
2670
2671  int* heap_allocated = new int[100];
2672  CheckAlignedPointerInInternalField(obj, heap_allocated);
2673  delete[] heap_allocated;
2674
2675  int stack_allocated[100];
2676  CheckAlignedPointerInInternalField(obj, stack_allocated);
2677
2678  void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2679  CheckAlignedPointerInInternalField(obj, huge);
2680
2681  v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2682  CHECK_EQ(1, Object::InternalFieldCount(persistent));
2683  CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2684}
2685
2686
2687static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2688                                              int index,
2689                                              void* value) {
2690  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2691  (*env)->SetAlignedPointerInEmbedderData(index, value);
2692  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2693  CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2694}
2695
2696
2697static void* AlignedTestPointer(int i) {
2698  return reinterpret_cast<void*>(i * 1234);
2699}
2700
2701
2702THREADED_TEST(EmbedderDataAlignedPointers) {
2703  LocalContext env;
2704  v8::HandleScope scope(env->GetIsolate());
2705
2706  CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2707
2708  int* heap_allocated = new int[100];
2709  CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2710  delete[] heap_allocated;
2711
2712  int stack_allocated[100];
2713  CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2714
2715  void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2716  CheckAlignedPointerInEmbedderData(&env, 3, huge);
2717
2718  // Test growing of the embedder data's backing store.
2719  for (int i = 0; i < 100; i++) {
2720    env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2721  }
2722  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2723  for (int i = 0; i < 100; i++) {
2724    CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2725  }
2726}
2727
2728
2729static void CheckEmbedderData(LocalContext* env,
2730                              int index,
2731                              v8::Handle<Value> data) {
2732  (*env)->SetEmbedderData(index, data);
2733  CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2734}
2735
2736
2737THREADED_TEST(EmbedderData) {
2738  LocalContext env;
2739  v8::Isolate* isolate = env->GetIsolate();
2740  v8::HandleScope scope(isolate);
2741
2742  CheckEmbedderData(
2743      &env, 3,
2744      v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2745  CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2746                                                     "over the lazy dog."));
2747  CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2748  CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2749}
2750
2751
2752THREADED_TEST(IdentityHash) {
2753  LocalContext env;
2754  v8::Isolate* isolate = env->GetIsolate();
2755  v8::HandleScope scope(isolate);
2756
2757  // Ensure that the test starts with an fresh heap to test whether the hash
2758  // code is based on the address.
2759  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2760  Local<v8::Object> obj = v8::Object::New(isolate);
2761  int hash = obj->GetIdentityHash();
2762  int hash1 = obj->GetIdentityHash();
2763  CHECK_EQ(hash, hash1);
2764  int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2765  // Since the identity hash is essentially a random number two consecutive
2766  // objects should not be assigned the same hash code. If the test below fails
2767  // the random number generator should be evaluated.
2768  CHECK_NE(hash, hash2);
2769  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2770  int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2771  // Make sure that the identity hash is not based on the initial address of
2772  // the object alone. If the test below fails the random number generator
2773  // should be evaluated.
2774  CHECK_NE(hash, hash3);
2775  int hash4 = obj->GetIdentityHash();
2776  CHECK_EQ(hash, hash4);
2777
2778  // Check identity hashes behaviour in the presence of JS accessors.
2779  // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2780  {
2781    CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2782    Local<v8::Object> o1 = v8::Object::New(isolate);
2783    Local<v8::Object> o2 = v8::Object::New(isolate);
2784    CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2785  }
2786  {
2787    CompileRun(
2788        "function cnst() { return 42; };\n"
2789        "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2790    Local<v8::Object> o1 = v8::Object::New(isolate);
2791    Local<v8::Object> o2 = v8::Object::New(isolate);
2792    CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2793  }
2794}
2795
2796
2797THREADED_TEST(GlobalProxyIdentityHash) {
2798  LocalContext env;
2799  v8::Isolate* isolate = env->GetIsolate();
2800  v8::HandleScope scope(isolate);
2801  Handle<Object> global_proxy = env->Global();
2802  int hash1 = global_proxy->GetIdentityHash();
2803  // Hash should be retained after being detached.
2804  env->DetachGlobal();
2805  int hash2 = global_proxy->GetIdentityHash();
2806  CHECK_EQ(hash1, hash2);
2807  {
2808    // Re-attach global proxy to a new context, hash should stay the same.
2809    LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2810    int hash3 = global_proxy->GetIdentityHash();
2811    CHECK_EQ(hash1, hash3);
2812  }
2813}
2814
2815
2816THREADED_TEST(SymbolProperties) {
2817  LocalContext env;
2818  v8::Isolate* isolate = env->GetIsolate();
2819  v8::HandleScope scope(isolate);
2820
2821  v8::Local<v8::Object> obj = v8::Object::New(isolate);
2822  v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2823  v8::Local<v8::Symbol> sym2 =
2824      v8::Symbol::New(isolate, v8_str("my-symbol"));
2825  v8::Local<v8::Symbol> sym3 =
2826      v8::Symbol::New(isolate, v8_str("sym3"));
2827
2828  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2829
2830  // Check basic symbol functionality.
2831  CHECK(sym1->IsSymbol());
2832  CHECK(sym2->IsSymbol());
2833  CHECK(!obj->IsSymbol());
2834
2835  CHECK(sym1->Equals(sym1));
2836  CHECK(sym2->Equals(sym2));
2837  CHECK(!sym1->Equals(sym2));
2838  CHECK(!sym2->Equals(sym1));
2839  CHECK(sym1->StrictEquals(sym1));
2840  CHECK(sym2->StrictEquals(sym2));
2841  CHECK(!sym1->StrictEquals(sym2));
2842  CHECK(!sym2->StrictEquals(sym1));
2843
2844  CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2845
2846  v8::Local<v8::Value> sym_val = sym2;
2847  CHECK(sym_val->IsSymbol());
2848  CHECK(sym_val->Equals(sym2));
2849  CHECK(sym_val->StrictEquals(sym2));
2850  CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2851
2852  v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2853  CHECK(sym_obj->IsSymbolObject());
2854  CHECK(!sym2->IsSymbolObject());
2855  CHECK(!obj->IsSymbolObject());
2856  CHECK(!sym_obj->Equals(sym2));
2857  CHECK(!sym_obj->StrictEquals(sym2));
2858  CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2859  CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2860
2861  // Make sure delete of a non-existent symbol property works.
2862  CHECK(obj->Delete(sym1));
2863  CHECK(!obj->Has(sym1));
2864
2865  CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2866  CHECK(obj->Has(sym1));
2867  CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2868  CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2869  CHECK(obj->Has(sym1));
2870  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2871  CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2872
2873  CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2874  int num_props = obj->GetPropertyNames()->Length();
2875  CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2876                 v8::Integer::New(isolate, 20)));
2877  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2878  CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2879
2880  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2881
2882  CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
2883  CHECK(obj->Get(sym3)->IsUndefined());
2884  CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
2885  CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2886  CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2887      v8::Integer::New(isolate, 42)));
2888
2889  // Add another property and delete it afterwards to force the object in
2890  // slow case.
2891  CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2892  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2893  CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2894  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2895  CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
2896
2897  CHECK(obj->Has(sym1));
2898  CHECK(obj->Has(sym2));
2899  CHECK(obj->Has(sym3));
2900  CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2901  CHECK(obj->Delete(sym2));
2902  CHECK(obj->Has(sym1));
2903  CHECK(!obj->Has(sym2));
2904  CHECK(obj->Has(sym3));
2905  CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2906  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2907  CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2908  CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2909      v8::Integer::New(isolate, 42)));
2910  CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
2911
2912  // Symbol properties are inherited.
2913  v8::Local<v8::Object> child = v8::Object::New(isolate);
2914  child->SetPrototype(obj);
2915  CHECK(child->Has(sym1));
2916  CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2917  CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2918  CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2919      v8::Integer::New(isolate, 42)));
2920  CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2921}
2922
2923
2924THREADED_TEST(SymbolTemplateProperties) {
2925  LocalContext env;
2926  v8::Isolate* isolate = env->GetIsolate();
2927  v8::HandleScope scope(isolate);
2928  v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
2929  v8::Local<v8::Name> name = v8::Symbol::New(isolate);
2930  CHECK(!name.IsEmpty());
2931  foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
2932  v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
2933  CHECK(!new_instance.IsEmpty());
2934  CHECK(new_instance->Has(name));
2935}
2936
2937
2938THREADED_TEST(PrivateProperties) {
2939  LocalContext env;
2940  v8::Isolate* isolate = env->GetIsolate();
2941  v8::HandleScope scope(isolate);
2942
2943  v8::Local<v8::Object> obj = v8::Object::New(isolate);
2944  v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2945  v8::Local<v8::Private> priv2 =
2946      v8::Private::New(isolate, v8_str("my-private"));
2947
2948  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2949
2950  CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2951
2952  // Make sure delete of a non-existent private symbol property works.
2953  CHECK(obj->DeletePrivate(priv1));
2954  CHECK(!obj->HasPrivate(priv1));
2955
2956  CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2957  CHECK(obj->HasPrivate(priv1));
2958  CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2959  CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2960  CHECK(obj->HasPrivate(priv1));
2961  CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2962
2963  CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2964  int num_props = obj->GetPropertyNames()->Length();
2965  CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2966                 v8::Integer::New(isolate, 20)));
2967  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2968  CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2969
2970  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2971
2972  // Add another property and delete it afterwards to force the object in
2973  // slow case.
2974  CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2975  CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2976  CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2977  CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2978  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2979
2980  CHECK(obj->HasPrivate(priv1));
2981  CHECK(obj->HasPrivate(priv2));
2982  CHECK(obj->DeletePrivate(priv2));
2983  CHECK(obj->HasPrivate(priv1));
2984  CHECK(!obj->HasPrivate(priv2));
2985  CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2986  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2987
2988  // Private properties are inherited (for the time being).
2989  v8::Local<v8::Object> child = v8::Object::New(isolate);
2990  child->SetPrototype(obj);
2991  CHECK(child->HasPrivate(priv1));
2992  CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2993  CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2994}
2995
2996
2997THREADED_TEST(GlobalSymbols) {
2998  LocalContext env;
2999  v8::Isolate* isolate = env->GetIsolate();
3000  v8::HandleScope scope(isolate);
3001
3002  v8::Local<String> name = v8_str("my-symbol");
3003  v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3004  v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3005  CHECK(glob2->SameValue(glob));
3006
3007  v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3008  v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3009  CHECK(glob_api2->SameValue(glob_api));
3010  CHECK(!glob_api->SameValue(glob));
3011
3012  v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3013  CHECK(!sym->SameValue(glob));
3014
3015  CompileRun("var sym2 = Symbol.for('my-symbol')");
3016  v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
3017  CHECK(sym2->SameValue(glob));
3018  CHECK(!sym2->SameValue(glob_api));
3019}
3020
3021
3022static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3023                                 const char* name) {
3024  LocalContext env;
3025  v8::Isolate* isolate = env->GetIsolate();
3026  v8::HandleScope scope(isolate);
3027
3028  v8::Local<v8::Symbol> symbol = getter(isolate);
3029  std::string script = std::string("var sym = ") + name;
3030  CompileRun(script.c_str());
3031  v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
3032
3033  CHECK(!value.IsEmpty());
3034  CHECK(!symbol.IsEmpty());
3035  CHECK(value->SameValue(symbol));
3036}
3037
3038
3039THREADED_TEST(WellKnownSymbols) {
3040  CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3041  CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3042}
3043
3044
3045THREADED_TEST(GlobalPrivates) {
3046  LocalContext env;
3047  v8::Isolate* isolate = env->GetIsolate();
3048  v8::HandleScope scope(isolate);
3049
3050  v8::Local<String> name = v8_str("my-private");
3051  v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3052  v8::Local<v8::Object> obj = v8::Object::New(isolate);
3053  CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
3054
3055  v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3056  CHECK(obj->HasPrivate(glob2));
3057
3058  v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3059  CHECK(!obj->HasPrivate(priv));
3060
3061  CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
3062  v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
3063  CHECK(!obj->Has(intern));
3064}
3065
3066
3067class ScopedArrayBufferContents {
3068 public:
3069  explicit ScopedArrayBufferContents(
3070      const v8::ArrayBuffer::Contents& contents)
3071    : contents_(contents) {}
3072  ~ScopedArrayBufferContents() { free(contents_.Data()); }
3073  void* Data() const { return contents_.Data(); }
3074  size_t ByteLength() const { return contents_.ByteLength(); }
3075 private:
3076  const v8::ArrayBuffer::Contents contents_;
3077};
3078
3079template <typename T>
3080static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
3081  CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3082  for (int i = 0; i < value->InternalFieldCount(); i++) {
3083    CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
3084  }
3085}
3086
3087
3088THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3089  LocalContext env;
3090  v8::Isolate* isolate = env->GetIsolate();
3091  v8::HandleScope handle_scope(isolate);
3092
3093  Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3094  CheckInternalFieldsAreZero(ab);
3095  CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3096  CHECK(!ab->IsExternal());
3097  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3098
3099  ScopedArrayBufferContents ab_contents(ab->Externalize());
3100  CHECK(ab->IsExternal());
3101
3102  CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3103  uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3104  DCHECK(data != NULL);
3105  env->Global()->Set(v8_str("ab"), ab);
3106
3107  v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
3108  CHECK_EQ(1024, result->Int32Value());
3109
3110  result = CompileRun("var u8 = new Uint8Array(ab);"
3111                      "u8[0] = 0xFF;"
3112                      "u8[1] = 0xAA;"
3113                      "u8.length");
3114  CHECK_EQ(1024, result->Int32Value());
3115  CHECK_EQ(0xFF, data[0]);
3116  CHECK_EQ(0xAA, data[1]);
3117  data[0] = 0xCC;
3118  data[1] = 0x11;
3119  result = CompileRun("u8[0] + u8[1]");
3120  CHECK_EQ(0xDD, result->Int32Value());
3121}
3122
3123
3124THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3125  LocalContext env;
3126  v8::Isolate* isolate = env->GetIsolate();
3127  v8::HandleScope handle_scope(isolate);
3128
3129
3130  v8::Local<v8::Value> result =
3131      CompileRun("var ab1 = new ArrayBuffer(2);"
3132                 "var u8_a = new Uint8Array(ab1);"
3133                 "u8_a[0] = 0xAA;"
3134                 "u8_a[1] = 0xFF; u8_a.buffer");
3135  Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3136  CheckInternalFieldsAreZero(ab1);
3137  CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3138  CHECK(!ab1->IsExternal());
3139  ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3140  CHECK(ab1->IsExternal());
3141
3142  result = CompileRun("ab1.byteLength");
3143  CHECK_EQ(2, result->Int32Value());
3144  result = CompileRun("u8_a[0]");
3145  CHECK_EQ(0xAA, result->Int32Value());
3146  result = CompileRun("u8_a[1]");
3147  CHECK_EQ(0xFF, result->Int32Value());
3148  result = CompileRun("var u8_b = new Uint8Array(ab1);"
3149                      "u8_b[0] = 0xBB;"
3150                      "u8_a[0]");
3151  CHECK_EQ(0xBB, result->Int32Value());
3152  result = CompileRun("u8_b[1]");
3153  CHECK_EQ(0xFF, result->Int32Value());
3154
3155  CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3156  uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3157  CHECK_EQ(0xBB, ab1_data[0]);
3158  CHECK_EQ(0xFF, ab1_data[1]);
3159  ab1_data[0] = 0xCC;
3160  ab1_data[1] = 0x11;
3161  result = CompileRun("u8_a[0] + u8_a[1]");
3162  CHECK_EQ(0xDD, result->Int32Value());
3163}
3164
3165
3166THREADED_TEST(ArrayBuffer_External) {
3167  LocalContext env;
3168  v8::Isolate* isolate = env->GetIsolate();
3169  v8::HandleScope handle_scope(isolate);
3170
3171  i::ScopedVector<uint8_t> my_data(100);
3172  memset(my_data.start(), 0, 100);
3173  Local<v8::ArrayBuffer> ab3 =
3174      v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3175  CheckInternalFieldsAreZero(ab3);
3176  CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3177  CHECK(ab3->IsExternal());
3178
3179  env->Global()->Set(v8_str("ab3"), ab3);
3180
3181  v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3182  CHECK_EQ(100, result->Int32Value());
3183
3184  result = CompileRun("var u8_b = new Uint8Array(ab3);"
3185                      "u8_b[0] = 0xBB;"
3186                      "u8_b[1] = 0xCC;"
3187                      "u8_b.length");
3188  CHECK_EQ(100, result->Int32Value());
3189  CHECK_EQ(0xBB, my_data[0]);
3190  CHECK_EQ(0xCC, my_data[1]);
3191  my_data[0] = 0xCC;
3192  my_data[1] = 0x11;
3193  result = CompileRun("u8_b[0] + u8_b[1]");
3194  CHECK_EQ(0xDD, result->Int32Value());
3195}
3196
3197
3198static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3199  CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3200  CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3201}
3202
3203
3204static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3205  CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3206  CHECK_EQ(0, static_cast<int>(ta->Length()));
3207  CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3208}
3209
3210
3211static void CheckIsTypedArrayVarNeutered(const char* name) {
3212  i::ScopedVector<char> source(1024);
3213  i::SNPrintF(source,
3214      "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3215      name, name, name);
3216  CHECK(CompileRun(source.start())->IsTrue());
3217  v8::Handle<v8::TypedArray> ta =
3218    v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3219  CheckIsNeutered(ta);
3220}
3221
3222
3223template <typename TypedArray, int kElementSize>
3224static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3225                                         int byteOffset,
3226                                         int length) {
3227  v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3228  CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3229  CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3230  CHECK_EQ(length, static_cast<int>(ta->Length()));
3231  CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3232  return ta;
3233}
3234
3235
3236THREADED_TEST(ArrayBuffer_NeuteringApi) {
3237  LocalContext env;
3238  v8::Isolate* isolate = env->GetIsolate();
3239  v8::HandleScope handle_scope(isolate);
3240
3241  v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3242
3243  v8::Handle<v8::Uint8Array> u8a =
3244    CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3245  v8::Handle<v8::Uint8ClampedArray> u8c =
3246    CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3247  v8::Handle<v8::Int8Array> i8a =
3248    CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3249
3250  v8::Handle<v8::Uint16Array> u16a =
3251    CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3252  v8::Handle<v8::Int16Array> i16a =
3253    CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3254
3255  v8::Handle<v8::Uint32Array> u32a =
3256    CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3257  v8::Handle<v8::Int32Array> i32a =
3258    CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3259
3260  v8::Handle<v8::Float32Array> f32a =
3261    CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3262  v8::Handle<v8::Float64Array> f64a =
3263    CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3264
3265  v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3266  CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3267  CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3268  CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3269
3270  ScopedArrayBufferContents contents(buffer->Externalize());
3271  buffer->Neuter();
3272  CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3273  CheckIsNeutered(u8a);
3274  CheckIsNeutered(u8c);
3275  CheckIsNeutered(i8a);
3276  CheckIsNeutered(u16a);
3277  CheckIsNeutered(i16a);
3278  CheckIsNeutered(u32a);
3279  CheckIsNeutered(i32a);
3280  CheckIsNeutered(f32a);
3281  CheckIsNeutered(f64a);
3282  CheckDataViewIsNeutered(dv);
3283}
3284
3285
3286THREADED_TEST(ArrayBuffer_NeuteringScript) {
3287  LocalContext env;
3288  v8::Isolate* isolate = env->GetIsolate();
3289  v8::HandleScope handle_scope(isolate);
3290
3291  CompileRun(
3292      "var ab = new ArrayBuffer(1024);"
3293      "var u8a = new Uint8Array(ab, 1, 1023);"
3294      "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3295      "var i8a = new Int8Array(ab, 1, 1023);"
3296      "var u16a = new Uint16Array(ab, 2, 511);"
3297      "var i16a = new Int16Array(ab, 2, 511);"
3298      "var u32a = new Uint32Array(ab, 4, 255);"
3299      "var i32a = new Int32Array(ab, 4, 255);"
3300      "var f32a = new Float32Array(ab, 4, 255);"
3301      "var f64a = new Float64Array(ab, 8, 127);"
3302      "var dv = new DataView(ab, 1, 1023);");
3303
3304  v8::Handle<v8::ArrayBuffer> ab =
3305      Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3306
3307  v8::Handle<v8::DataView> dv =
3308    v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3309
3310  ScopedArrayBufferContents contents(ab->Externalize());
3311  ab->Neuter();
3312  CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3313  CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3314
3315  CheckIsTypedArrayVarNeutered("u8a");
3316  CheckIsTypedArrayVarNeutered("u8c");
3317  CheckIsTypedArrayVarNeutered("i8a");
3318  CheckIsTypedArrayVarNeutered("u16a");
3319  CheckIsTypedArrayVarNeutered("i16a");
3320  CheckIsTypedArrayVarNeutered("u32a");
3321  CheckIsTypedArrayVarNeutered("i32a");
3322  CheckIsTypedArrayVarNeutered("f32a");
3323  CheckIsTypedArrayVarNeutered("f64a");
3324
3325  CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3326  CheckDataViewIsNeutered(dv);
3327}
3328
3329
3330
3331THREADED_TEST(HiddenProperties) {
3332  LocalContext env;
3333  v8::Isolate* isolate = env->GetIsolate();
3334  v8::HandleScope scope(isolate);
3335
3336  v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3337  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3338  v8::Local<v8::String> empty = v8_str("");
3339  v8::Local<v8::String> prop_name = v8_str("prop_name");
3340
3341  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3342
3343  // Make sure delete of a non-existent hidden value works
3344  CHECK(obj->DeleteHiddenValue(key));
3345
3346  CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3347  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3348  CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3349  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3350
3351  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3352
3353  // Make sure we do not find the hidden property.
3354  CHECK(!obj->Has(empty));
3355  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3356  CHECK(obj->Get(empty)->IsUndefined());
3357  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3358  CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3359  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3360  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3361
3362  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3363
3364  // Add another property and delete it afterwards to force the object in
3365  // slow case.
3366  CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3367  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3368  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3369  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3370  CHECK(obj->Delete(prop_name));
3371  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3372
3373  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3374
3375  CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3376  CHECK(obj->GetHiddenValue(key).IsEmpty());
3377
3378  CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3379  CHECK(obj->DeleteHiddenValue(key));
3380  CHECK(obj->GetHiddenValue(key).IsEmpty());
3381}
3382
3383
3384THREADED_TEST(Regress97784) {
3385  // Regression test for crbug.com/97784
3386  // Messing with the Object.prototype should not have effect on
3387  // hidden properties.
3388  LocalContext env;
3389  v8::HandleScope scope(env->GetIsolate());
3390
3391  v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3392  v8::Local<v8::String> key = v8_str("hidden");
3393
3394  CompileRun(
3395      "set_called = false;"
3396      "Object.defineProperty("
3397      "    Object.prototype,"
3398      "    'hidden',"
3399      "    {get: function() { return 45; },"
3400      "     set: function() { set_called = true; }})");
3401
3402  CHECK(obj->GetHiddenValue(key).IsEmpty());
3403  // Make sure that the getter and setter from Object.prototype is not invoked.
3404  // If it did we would have full access to the hidden properties in
3405  // the accessor.
3406  CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3407  ExpectFalse("set_called");
3408  CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3409}
3410
3411
3412static bool interceptor_for_hidden_properties_called;
3413static void InterceptorForHiddenProperties(
3414    Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3415  interceptor_for_hidden_properties_called = true;
3416}
3417
3418
3419THREADED_TEST(HiddenPropertiesWithInterceptors) {
3420  LocalContext context;
3421  v8::Isolate* isolate = context->GetIsolate();
3422  v8::HandleScope scope(isolate);
3423
3424  interceptor_for_hidden_properties_called = false;
3425
3426  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3427
3428  // Associate an interceptor with an object and start setting hidden values.
3429  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3430  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3431  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3432  Local<v8::Function> function = fun_templ->GetFunction();
3433  Local<v8::Object> obj = function->NewInstance();
3434  CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3435  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3436  CHECK(!interceptor_for_hidden_properties_called);
3437}
3438
3439
3440THREADED_TEST(External) {
3441  v8::HandleScope scope(CcTest::isolate());
3442  int x = 3;
3443  Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3444  LocalContext env;
3445  env->Global()->Set(v8_str("ext"), ext);
3446  Local<Value> reext_obj = CompileRun("this.ext");
3447  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3448  int* ptr = static_cast<int*>(reext->Value());
3449  CHECK_EQ(x, 3);
3450  *ptr = 10;
3451  CHECK_EQ(x, 10);
3452
3453  // Make sure unaligned pointers are wrapped properly.
3454  char* data = i::StrDup("0123456789");
3455  Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3456  Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3457  Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3458  Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3459
3460  char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3461  CHECK_EQ('0', *char_ptr);
3462  char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3463  CHECK_EQ('1', *char_ptr);
3464  char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3465  CHECK_EQ('2', *char_ptr);
3466  char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3467  CHECK_EQ('3', *char_ptr);
3468  i::DeleteArray(data);
3469}
3470
3471
3472THREADED_TEST(GlobalHandle) {
3473  v8::Isolate* isolate = CcTest::isolate();
3474  v8::Persistent<String> global;
3475  {
3476    v8::HandleScope scope(isolate);
3477    global.Reset(isolate, v8_str("str"));
3478  }
3479  {
3480    v8::HandleScope scope(isolate);
3481    CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3482  }
3483  global.Reset();
3484  {
3485    v8::HandleScope scope(isolate);
3486    global.Reset(isolate, v8_str("str"));
3487  }
3488  {
3489    v8::HandleScope scope(isolate);
3490    CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3491  }
3492  global.Reset();
3493}
3494
3495
3496THREADED_TEST(ResettingGlobalHandle) {
3497  v8::Isolate* isolate = CcTest::isolate();
3498  v8::Persistent<String> global;
3499  {
3500    v8::HandleScope scope(isolate);
3501    global.Reset(isolate, v8_str("str"));
3502  }
3503  v8::internal::GlobalHandles* global_handles =
3504      reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3505  int initial_handle_count = global_handles->global_handles_count();
3506  {
3507    v8::HandleScope scope(isolate);
3508    CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3509  }
3510  {
3511    v8::HandleScope scope(isolate);
3512    global.Reset(isolate, v8_str("longer"));
3513  }
3514  CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3515  {
3516    v8::HandleScope scope(isolate);
3517    CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3518  }
3519  global.Reset();
3520  CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3521}
3522
3523
3524THREADED_TEST(ResettingGlobalHandleToEmpty) {
3525  v8::Isolate* isolate = CcTest::isolate();
3526  v8::Persistent<String> global;
3527  {
3528    v8::HandleScope scope(isolate);
3529    global.Reset(isolate, v8_str("str"));
3530  }
3531  v8::internal::GlobalHandles* global_handles =
3532      reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3533  int initial_handle_count = global_handles->global_handles_count();
3534  {
3535    v8::HandleScope scope(isolate);
3536    CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3537  }
3538  {
3539    v8::HandleScope scope(isolate);
3540    Local<String> empty;
3541    global.Reset(isolate, empty);
3542  }
3543  CHECK(global.IsEmpty());
3544  CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3545}
3546
3547
3548template<class T>
3549static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3550  return unique.Pass();
3551}
3552
3553
3554template<class T>
3555static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3556                                            const v8::Persistent<T> & global) {
3557  v8::UniquePersistent<String> unique(isolate, global);
3558  return unique.Pass();
3559}
3560
3561
3562THREADED_TEST(UniquePersistent) {
3563  v8::Isolate* isolate = CcTest::isolate();
3564  v8::Persistent<String> global;
3565  {
3566    v8::HandleScope scope(isolate);
3567    global.Reset(isolate, v8_str("str"));
3568  }
3569  v8::internal::GlobalHandles* global_handles =
3570      reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3571  int initial_handle_count = global_handles->global_handles_count();
3572  {
3573    v8::UniquePersistent<String> unique(isolate, global);
3574    CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3575    // Test assignment via Pass
3576    {
3577      v8::UniquePersistent<String> copy = unique.Pass();
3578      CHECK(unique.IsEmpty());
3579      CHECK(copy == global);
3580      CHECK_EQ(initial_handle_count + 1,
3581               global_handles->global_handles_count());
3582      unique = copy.Pass();
3583    }
3584    // Test ctor via Pass
3585    {
3586      v8::UniquePersistent<String> copy(unique.Pass());
3587      CHECK(unique.IsEmpty());
3588      CHECK(copy == global);
3589      CHECK_EQ(initial_handle_count + 1,
3590               global_handles->global_handles_count());
3591      unique = copy.Pass();
3592    }
3593    // Test pass through function call
3594    {
3595      v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3596      CHECK(unique.IsEmpty());
3597      CHECK(copy == global);
3598      CHECK_EQ(initial_handle_count + 1,
3599               global_handles->global_handles_count());
3600      unique = copy.Pass();
3601    }
3602    CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3603  }
3604  // Test pass from function call
3605  {
3606    v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3607    CHECK(unique == global);
3608    CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3609  }
3610  CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3611  global.Reset();
3612}
3613
3614
3615template<typename K, typename V>
3616class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3617 public:
3618  typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3619      MapType;
3620  static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3621  struct WeakCallbackDataType {
3622    MapType* map;
3623    K key;
3624  };
3625  static WeakCallbackDataType* WeakCallbackParameter(
3626      MapType* map, const K& key, Local<V> value) {
3627    WeakCallbackDataType* data = new WeakCallbackDataType;
3628    data->map = map;
3629    data->key = key;
3630    return data;
3631  }
3632  static MapType* MapFromWeakCallbackData(
3633      const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3634    return data.GetParameter()->map;
3635  }
3636  static K KeyFromWeakCallbackData(
3637      const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3638    return data.GetParameter()->key;
3639  }
3640  static void DisposeCallbackData(WeakCallbackDataType* data) {
3641    delete data;
3642  }
3643  static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3644      K key) { }
3645};
3646
3647
3648template<typename Map>
3649static void TestPersistentValueMap() {
3650  LocalContext env;
3651  v8::Isolate* isolate = env->GetIsolate();
3652  Map map(isolate);
3653  v8::internal::GlobalHandles* global_handles =
3654      reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3655  int initial_handle_count = global_handles->global_handles_count();
3656  CHECK_EQ(0, static_cast<int>(map.Size()));
3657  {
3658    HandleScope scope(isolate);
3659    Local<v8::Object> obj = map.Get(7);
3660    CHECK(obj.IsEmpty());
3661    Local<v8::Object> expected = v8::Object::New(isolate);
3662    map.Set(7, expected);
3663    CHECK_EQ(1, static_cast<int>(map.Size()));
3664    obj = map.Get(7);
3665    CHECK_EQ(expected, obj);
3666    {
3667      typename Map::PersistentValueReference ref = map.GetReference(7);
3668      CHECK_EQ(expected, ref.NewLocal(isolate));
3669    }
3670    v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3671    CHECK_EQ(0, static_cast<int>(map.Size()));
3672    CHECK(expected == removed);
3673    removed = map.Remove(7);
3674    CHECK(removed.IsEmpty());
3675    map.Set(8, expected);
3676    CHECK_EQ(1, static_cast<int>(map.Size()));
3677    map.Set(8, expected);
3678    CHECK_EQ(1, static_cast<int>(map.Size()));
3679    {
3680      typename Map::PersistentValueReference ref;
3681      Local<v8::Object> expected2 = v8::Object::New(isolate);
3682      removed = map.Set(8,
3683          v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3684      CHECK_EQ(1, static_cast<int>(map.Size()));
3685      CHECK(expected == removed);
3686      CHECK_EQ(expected2, ref.NewLocal(isolate));
3687    }
3688  }
3689  CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3690  if (map.IsWeak()) {
3691    reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3692        CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3693  } else {
3694    map.Clear();
3695  }
3696  CHECK_EQ(0, static_cast<int>(map.Size()));
3697  CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3698}
3699
3700
3701TEST(PersistentValueMap) {
3702  // Default case, w/o weak callbacks:
3703  TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3704
3705  // Custom traits with weak callbacks:
3706  typedef v8::PersistentValueMap<int, v8::Object,
3707      WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3708  TestPersistentValueMap<WeakPersistentValueMap>();
3709}
3710
3711
3712TEST(PersistentValueVector) {
3713  LocalContext env;
3714  v8::Isolate* isolate = env->GetIsolate();
3715  v8::internal::GlobalHandles* global_handles =
3716      reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3717  int handle_count = global_handles->global_handles_count();
3718  HandleScope scope(isolate);
3719
3720  v8::PersistentValueVector<v8::Object> vector(isolate);
3721
3722  Local<v8::Object> obj1 = v8::Object::New(isolate);
3723  Local<v8::Object> obj2 = v8::Object::New(isolate);
3724  v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3725
3726  CHECK(vector.IsEmpty());
3727  CHECK_EQ(0, static_cast<int>(vector.Size()));
3728
3729  vector.ReserveCapacity(3);
3730  CHECK(vector.IsEmpty());
3731
3732  vector.Append(obj1);
3733  vector.Append(obj2);
3734  vector.Append(obj1);
3735  vector.Append(obj3.Pass());
3736  vector.Append(obj1);
3737
3738  CHECK(!vector.IsEmpty());
3739  CHECK_EQ(5, static_cast<int>(vector.Size()));
3740  CHECK(obj3.IsEmpty());
3741  CHECK_EQ(obj1, vector.Get(0));
3742  CHECK_EQ(obj1, vector.Get(2));
3743  CHECK_EQ(obj1, vector.Get(4));
3744  CHECK_EQ(obj2, vector.Get(1));
3745
3746  CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3747
3748  vector.Clear();
3749  CHECK(vector.IsEmpty());
3750  CHECK_EQ(0, static_cast<int>(vector.Size()));
3751  CHECK_EQ(handle_count, global_handles->global_handles_count());
3752}
3753
3754
3755THREADED_TEST(GlobalHandleUpcast) {
3756  v8::Isolate* isolate = CcTest::isolate();
3757  v8::HandleScope scope(isolate);
3758  v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3759  v8::Persistent<String> global_string(isolate, local);
3760  v8::Persistent<Value>& global_value =
3761      v8::Persistent<Value>::Cast(global_string);
3762  CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3763  CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3764  global_string.Reset();
3765}
3766
3767
3768THREADED_TEST(HandleEquality) {
3769  v8::Isolate* isolate = CcTest::isolate();
3770  v8::Persistent<String> global1;
3771  v8::Persistent<String> global2;
3772  {
3773    v8::HandleScope scope(isolate);
3774    global1.Reset(isolate, v8_str("str"));
3775    global2.Reset(isolate, v8_str("str2"));
3776  }
3777  CHECK_EQ(global1 == global1, true);
3778  CHECK_EQ(global1 != global1, false);
3779  {
3780    v8::HandleScope scope(isolate);
3781    Local<String> local1 = Local<String>::New(isolate, global1);
3782    Local<String> local2 = Local<String>::New(isolate, global2);
3783
3784    CHECK_EQ(global1 == local1, true);
3785    CHECK_EQ(global1 != local1, false);
3786    CHECK_EQ(local1 == global1, true);
3787    CHECK_EQ(local1 != global1, false);
3788
3789    CHECK_EQ(global1 == local2, false);
3790    CHECK_EQ(global1 != local2, true);
3791    CHECK_EQ(local2 == global1, false);
3792    CHECK_EQ(local2 != global1, true);
3793
3794    CHECK_EQ(local1 == local2, false);
3795    CHECK_EQ(local1 != local2, true);
3796
3797    Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3798    CHECK_EQ(local1 == anotherLocal1, true);
3799    CHECK_EQ(local1 != anotherLocal1, false);
3800  }
3801  global1.Reset();
3802  global2.Reset();
3803}
3804
3805
3806THREADED_TEST(LocalHandle) {
3807  v8::HandleScope scope(CcTest::isolate());
3808  v8::Local<String> local =
3809      v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3810  CHECK_EQ(local->Length(), 3);
3811}
3812
3813
3814class WeakCallCounter {
3815 public:
3816  explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3817  int id() { return id_; }
3818  void increment() { number_of_weak_calls_++; }
3819  int NumberOfWeakCalls() { return number_of_weak_calls_; }
3820 private:
3821  int id_;
3822  int number_of_weak_calls_;
3823};
3824
3825
3826template<typename T>
3827struct WeakCallCounterAndPersistent {
3828  explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3829      : counter(counter) {}
3830  WeakCallCounter* counter;
3831  v8::Persistent<T> handle;
3832};
3833
3834
3835template <typename T>
3836static void WeakPointerCallback(
3837    const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3838  CHECK_EQ(1234, data.GetParameter()->counter->id());
3839  data.GetParameter()->counter->increment();
3840  data.GetParameter()->handle.Reset();
3841}
3842
3843
3844template<typename T>
3845static UniqueId MakeUniqueId(const Persistent<T>& p) {
3846  return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3847}
3848
3849
3850THREADED_TEST(ApiObjectGroups) {
3851  LocalContext env;
3852  v8::Isolate* iso = env->GetIsolate();
3853  HandleScope scope(iso);
3854
3855  WeakCallCounter counter(1234);
3856
3857  WeakCallCounterAndPersistent<Value> g1s1(&counter);
3858  WeakCallCounterAndPersistent<Value> g1s2(&counter);
3859  WeakCallCounterAndPersistent<Value> g1c1(&counter);
3860  WeakCallCounterAndPersistent<Value> g2s1(&counter);
3861  WeakCallCounterAndPersistent<Value> g2s2(&counter);
3862  WeakCallCounterAndPersistent<Value> g2c1(&counter);
3863
3864  {
3865    HandleScope scope(iso);
3866    g1s1.handle.Reset(iso, Object::New(iso));
3867    g1s2.handle.Reset(iso, Object::New(iso));
3868    g1c1.handle.Reset(iso, Object::New(iso));
3869    g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3870    g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3871    g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3872
3873    g2s1.handle.Reset(iso, Object::New(iso));
3874    g2s2.handle.Reset(iso, Object::New(iso));
3875    g2c1.handle.Reset(iso, Object::New(iso));
3876    g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3877    g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3878    g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3879  }
3880
3881  WeakCallCounterAndPersistent<Value> root(&counter);
3882  root.handle.Reset(iso, g1s1.handle);  // make a root.
3883
3884  // Connect group 1 and 2, make a cycle.
3885  {
3886    HandleScope scope(iso);
3887    CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3888            Set(0, Local<Value>::New(iso, g2s2.handle)));
3889    CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3890            Set(0, Local<Value>::New(iso, g1s1.handle)));
3891  }
3892
3893  {
3894    UniqueId id1 = MakeUniqueId(g1s1.handle);
3895    UniqueId id2 = MakeUniqueId(g2s2.handle);
3896    iso->SetObjectGroupId(g1s1.handle, id1);
3897    iso->SetObjectGroupId(g1s2.handle, id1);
3898    iso->SetReferenceFromGroup(id1, g1c1.handle);
3899    iso->SetObjectGroupId(g2s1.handle, id2);
3900    iso->SetObjectGroupId(g2s2.handle, id2);
3901    iso->SetReferenceFromGroup(id2, g2c1.handle);
3902  }
3903  // Do a single full GC, ensure incremental marking is stopped.
3904  v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3905      iso)->heap();
3906  heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3907
3908  // All object should be alive.
3909  CHECK_EQ(0, counter.NumberOfWeakCalls());
3910
3911  // Weaken the root.
3912  root.handle.SetWeak(&root, &WeakPointerCallback);
3913  // But make children strong roots---all the objects (except for children)
3914  // should be collectable now.
3915  g1c1.handle.ClearWeak();
3916  g2c1.handle.ClearWeak();
3917
3918  // Groups are deleted, rebuild groups.
3919  {
3920    UniqueId id1 = MakeUniqueId(g1s1.handle);
3921    UniqueId id2 = MakeUniqueId(g2s2.handle);
3922    iso->SetObjectGroupId(g1s1.handle, id1);
3923    iso->SetObjectGroupId(g1s2.handle, id1);
3924    iso->SetReferenceFromGroup(id1, g1c1.handle);
3925    iso->SetObjectGroupId(g2s1.handle, id2);
3926    iso->SetObjectGroupId(g2s2.handle, id2);
3927    iso->SetReferenceFromGroup(id2, g2c1.handle);
3928  }
3929
3930  heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3931
3932  // All objects should be gone. 5 global handles in total.
3933  CHECK_EQ(5, counter.NumberOfWeakCalls());
3934
3935  // And now make children weak again and collect them.
3936  g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3937  g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3938
3939  heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3940  CHECK_EQ(7, counter.NumberOfWeakCalls());
3941}
3942
3943
3944THREADED_TEST(ApiObjectGroupsForSubtypes) {
3945  LocalContext env;
3946  v8::Isolate* iso = env->GetIsolate();
3947  HandleScope scope(iso);
3948
3949  WeakCallCounter counter(1234);
3950
3951  WeakCallCounterAndPersistent<Object> g1s1(&counter);
3952  WeakCallCounterAndPersistent<String> g1s2(&counter);
3953  WeakCallCounterAndPersistent<String> g1c1(&counter);
3954  WeakCallCounterAndPersistent<Object> g2s1(&counter);
3955  WeakCallCounterAndPersistent<String> g2s2(&counter);
3956  WeakCallCounterAndPersistent<String> g2c1(&counter);
3957
3958  {
3959    HandleScope scope(iso);
3960    g1s1.handle.Reset(iso, Object::New(iso));
3961    g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3962    g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3963    g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3964    g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3965    g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3966
3967    g2s1.handle.Reset(iso, Object::New(iso));
3968    g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3969    g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3970    g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3971    g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3972    g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3973  }
3974
3975  WeakCallCounterAndPersistent<Value> root(&counter);
3976  root.handle.Reset(iso, g1s1.handle);  // make a root.
3977
3978  // Connect group 1 and 2, make a cycle.
3979  {
3980    HandleScope scope(iso);
3981    CHECK(Local<Object>::New(iso, g1s1.handle)
3982              ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3983    CHECK(Local<Object>::New(iso, g2s1.handle)
3984              ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3985  }
3986
3987  {
3988    UniqueId id1 = MakeUniqueId(g1s1.handle);
3989    UniqueId id2 = MakeUniqueId(g2s2.handle);
3990    iso->SetObjectGroupId(g1s1.handle, id1);
3991    iso->SetObjectGroupId(g1s2.handle, id1);
3992    iso->SetReference(g1s1.handle, g1c1.handle);
3993    iso->SetObjectGroupId(g2s1.handle, id2);
3994    iso->SetObjectGroupId(g2s2.handle, id2);
3995    iso->SetReferenceFromGroup(id2, g2c1.handle);
3996  }
3997  // Do a single full GC, ensure incremental marking is stopped.
3998  v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3999      iso)->heap();
4000  heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4001
4002  // All object should be alive.
4003  CHECK_EQ(0, counter.NumberOfWeakCalls());
4004
4005  // Weaken the root.
4006  root.handle.SetWeak(&root, &WeakPointerCallback);
4007  // But make children strong roots---all the objects (except for children)
4008  // should be collectable now.
4009  g1c1.handle.ClearWeak();
4010  g2c1.handle.ClearWeak();
4011
4012  // Groups are deleted, rebuild groups.
4013  {
4014    UniqueId id1 = MakeUniqueId(g1s1.handle);
4015    UniqueId id2 = MakeUniqueId(g2s2.handle);
4016    iso->SetObjectGroupId(g1s1.handle, id1);
4017    iso->SetObjectGroupId(g1s2.handle, id1);
4018    iso->SetReference(g1s1.handle, g1c1.handle);
4019    iso->SetObjectGroupId(g2s1.handle, id2);
4020    iso->SetObjectGroupId(g2s2.handle, id2);
4021    iso->SetReferenceFromGroup(id2, g2c1.handle);
4022  }
4023
4024  heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4025
4026  // All objects should be gone. 5 global handles in total.
4027  CHECK_EQ(5, counter.NumberOfWeakCalls());
4028
4029  // And now make children weak again and collect them.
4030  g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4031  g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4032
4033  heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4034  CHECK_EQ(7, counter.NumberOfWeakCalls());
4035}
4036
4037
4038THREADED_TEST(ApiObjectGroupsCycle) {
4039  LocalContext env;
4040  v8::Isolate* iso = env->GetIsolate();
4041  HandleScope scope(iso);
4042
4043  WeakCallCounter counter(1234);
4044
4045  WeakCallCounterAndPersistent<Value> g1s1(&counter);
4046  WeakCallCounterAndPersistent<Value> g1s2(&counter);
4047  WeakCallCounterAndPersistent<Value> g2s1(&counter);
4048  WeakCallCounterAndPersistent<Value> g2s2(&counter);
4049  WeakCallCounterAndPersistent<Value> g3s1(&counter);
4050  WeakCallCounterAndPersistent<Value> g3s2(&counter);
4051  WeakCallCounterAndPersistent<Value> g4s1(&counter);
4052  WeakCallCounterAndPersistent<Value> g4s2(&counter);
4053
4054  {
4055    HandleScope scope(iso);
4056    g1s1.handle.Reset(iso, Object::New(iso));
4057    g1s2.handle.Reset(iso, Object::New(iso));
4058    g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4059    g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4060    CHECK(g1s1.handle.IsWeak());
4061    CHECK(g1s2.handle.IsWeak());
4062
4063    g2s1.handle.Reset(iso, Object::New(iso));
4064    g2s2.handle.Reset(iso, Object::New(iso));
4065    g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4066    g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4067    CHECK(g2s1.handle.IsWeak());
4068    CHECK(g2s2.handle.IsWeak());
4069
4070    g3s1.handle.Reset(iso, Object::New(iso));
4071    g3s2.handle.Reset(iso, Object::New(iso));
4072    g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4073    g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4074    CHECK(g3s1.handle.IsWeak());
4075    CHECK(g3s2.handle.IsWeak());
4076
4077    g4s1.handle.Reset(iso, Object::New(iso));
4078    g4s2.handle.Reset(iso, Object::New(iso));
4079    g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
4080    g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
4081    CHECK(g4s1.handle.IsWeak());
4082    CHECK(g4s2.handle.IsWeak());
4083  }
4084
4085  WeakCallCounterAndPersistent<Value> root(&counter);
4086  root.handle.Reset(iso, g1s1.handle);  // make a root.
4087
4088  // Connect groups.  We're building the following cycle:
4089  // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4090  // groups.
4091  {
4092    UniqueId id1 = MakeUniqueId(g1s1.handle);
4093    UniqueId id2 = MakeUniqueId(g2s1.handle);
4094    UniqueId id3 = MakeUniqueId(g3s1.handle);
4095    UniqueId id4 = MakeUniqueId(g4s1.handle);
4096    iso->SetObjectGroupId(g1s1.handle, id1);
4097    iso->SetObjectGroupId(g1s2.handle, id1);
4098    iso->SetReferenceFromGroup(id1, g2s1.handle);
4099    iso->SetObjectGroupId(g2s1.handle, id2);
4100    iso->SetObjectGroupId(g2s2.handle, id2);
4101    iso->SetReferenceFromGroup(id2, g3s1.handle);
4102    iso->SetObjectGroupId(g3s1.handle, id3);
4103    iso->SetObjectGroupId(g3s2.handle, id3);
4104    iso->SetReferenceFromGroup(id3, g4s1.handle);
4105    iso->SetObjectGroupId(g4s1.handle, id4);
4106    iso->SetObjectGroupId(g4s2.handle, id4);
4107    iso->SetReferenceFromGroup(id4, g1s1.handle);
4108  }
4109  // Do a single full GC
4110  v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4111      iso)->heap();
4112  heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4113
4114  // All object should be alive.
4115  CHECK_EQ(0, counter.NumberOfWeakCalls());
4116
4117  // Weaken the root.
4118  root.handle.SetWeak(&root, &WeakPointerCallback);
4119
4120  // Groups are deleted, rebuild groups.
4121  {
4122    UniqueId id1 = MakeUniqueId(g1s1.handle);
4123    UniqueId id2 = MakeUniqueId(g2s1.handle);
4124    UniqueId id3 = MakeUniqueId(g3s1.handle);
4125    UniqueId id4 = MakeUniqueId(g4s1.handle);
4126    iso->SetObjectGroupId(g1s1.handle, id1);
4127    iso->SetObjectGroupId(g1s2.handle, id1);
4128    iso->SetReferenceFromGroup(id1, g2s1.handle);
4129    iso->SetObjectGroupId(g2s1.handle, id2);
4130    iso->SetObjectGroupId(g2s2.handle, id2);
4131    iso->SetReferenceFromGroup(id2, g3s1.handle);
4132    iso->SetObjectGroupId(g3s1.handle, id3);
4133    iso->SetObjectGroupId(g3s2.handle, id3);
4134    iso->SetReferenceFromGroup(id3, g4s1.handle);
4135    iso->SetObjectGroupId(g4s1.handle, id4);
4136    iso->SetObjectGroupId(g4s2.handle, id4);
4137    iso->SetReferenceFromGroup(id4, g1s1.handle);
4138  }
4139
4140  heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4141
4142  // All objects should be gone. 9 global handles in total.
4143  CHECK_EQ(9, counter.NumberOfWeakCalls());
4144}
4145
4146
4147// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4148// on the buildbots, so was made non-threaded for the time being.
4149TEST(ApiObjectGroupsCycleForScavenger) {
4150  i::FLAG_stress_compaction = false;
4151  i::FLAG_gc_global = false;
4152  LocalContext env;
4153  v8::Isolate* iso = env->GetIsolate();
4154  HandleScope scope(iso);
4155
4156  WeakCallCounter counter(1234);
4157
4158  WeakCallCounterAndPersistent<Value> g1s1(&counter);
4159  WeakCallCounterAndPersistent<Value> g1s2(&counter);
4160  WeakCallCounterAndPersistent<Value> g2s1(&counter);
4161  WeakCallCounterAndPersistent<Value> g2s2(&counter);
4162  WeakCallCounterAndPersistent<Value> g3s1(&counter);
4163  WeakCallCounterAndPersistent<Value> g3s2(&counter);
4164
4165  {
4166    HandleScope scope(iso);
4167    g1s1.handle.Reset(iso, Object::New(iso));
4168    g1s2.handle.Reset(iso, Object::New(iso));
4169    g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4170    g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4171
4172    g2s1.handle.Reset(iso, Object::New(iso));
4173    g2s2.handle.Reset(iso, Object::New(iso));
4174    g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4175    g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4176
4177    g3s1.handle.Reset(iso, Object::New(iso));
4178    g3s2.handle.Reset(iso, Object::New(iso));
4179    g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4180    g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4181  }
4182
4183  // Make a root.
4184  WeakCallCounterAndPersistent<Value> root(&counter);
4185  root.handle.Reset(iso, g1s1.handle);
4186  root.handle.MarkPartiallyDependent();
4187
4188  // Connect groups.  We're building the following cycle:
4189  // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4190  // groups.
4191  {
4192    HandleScope handle_scope(iso);
4193    g1s1.handle.MarkPartiallyDependent();
4194    g1s2.handle.MarkPartiallyDependent();
4195    g2s1.handle.MarkPartiallyDependent();
4196    g2s2.handle.MarkPartiallyDependent();
4197    g3s1.handle.MarkPartiallyDependent();
4198    g3s2.handle.MarkPartiallyDependent();
4199    iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4200    iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4201    Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4202        v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4203    iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4204    iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4205    Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4206        v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4207    iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4208    iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4209    Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4210        v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4211  }
4212
4213  v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4214      iso)->heap();
4215  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4216
4217  // All objects should be alive.
4218  CHECK_EQ(0, counter.NumberOfWeakCalls());
4219
4220  // Weaken the root.
4221  root.handle.SetWeak(&root, &WeakPointerCallback);
4222  root.handle.MarkPartiallyDependent();
4223
4224  // Groups are deleted, rebuild groups.
4225  {
4226    HandleScope handle_scope(iso);
4227    g1s1.handle.MarkPartiallyDependent();
4228    g1s2.handle.MarkPartiallyDependent();
4229    g2s1.handle.MarkPartiallyDependent();
4230    g2s2.handle.MarkPartiallyDependent();
4231    g3s1.handle.MarkPartiallyDependent();
4232    g3s2.handle.MarkPartiallyDependent();
4233    iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4234    iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4235    Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4236        v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4237    iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4238    iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4239    Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4240        v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4241    iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4242    iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4243    Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4244        v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4245  }
4246
4247  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4248
4249  // All objects should be gone. 7 global handles in total.
4250  CHECK_EQ(7, counter.NumberOfWeakCalls());
4251}
4252
4253
4254THREADED_TEST(ScriptException) {
4255  LocalContext env;
4256  v8::HandleScope scope(env->GetIsolate());
4257  Local<Script> script = v8_compile("throw 'panama!';");
4258  v8::TryCatch try_catch;
4259  Local<Value> result = script->Run();
4260  CHECK(result.IsEmpty());
4261  CHECK(try_catch.HasCaught());
4262  String::Utf8Value exception_value(try_catch.Exception());
4263  CHECK_EQ(*exception_value, "panama!");
4264}
4265
4266
4267TEST(TryCatchCustomException) {
4268  LocalContext env;
4269  v8::HandleScope scope(env->GetIsolate());
4270  v8::TryCatch try_catch;
4271  CompileRun("function CustomError() { this.a = 'b'; }"
4272             "(function f() { throw new CustomError(); })();");
4273  CHECK(try_catch.HasCaught());
4274  CHECK(try_catch.Exception()->ToObject()->
4275            Get(v8_str("a"))->Equals(v8_str("b")));
4276}
4277
4278
4279bool message_received;
4280
4281
4282static void check_message_0(v8::Handle<v8::Message> message,
4283                            v8::Handle<Value> data) {
4284  CHECK_EQ(5.76, data->NumberValue());
4285  CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4286  CHECK(!message->IsSharedCrossOrigin());
4287  message_received = true;
4288}
4289
4290
4291THREADED_TEST(MessageHandler0) {
4292  message_received = false;
4293  v8::HandleScope scope(CcTest::isolate());
4294  CHECK(!message_received);
4295  LocalContext context;
4296  v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4297  v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4298  script->Run();
4299  CHECK(message_received);
4300  // clear out the message listener
4301  v8::V8::RemoveMessageListeners(check_message_0);
4302}
4303
4304
4305static void check_message_1(v8::Handle<v8::Message> message,
4306                            v8::Handle<Value> data) {
4307  CHECK(data->IsNumber());
4308  CHECK_EQ(1337, data->Int32Value());
4309  CHECK(!message->IsSharedCrossOrigin());
4310  message_received = true;
4311}
4312
4313
4314TEST(MessageHandler1) {
4315  message_received = false;
4316  v8::HandleScope scope(CcTest::isolate());
4317  CHECK(!message_received);
4318  v8::V8::AddMessageListener(check_message_1);
4319  LocalContext context;
4320  CompileRun("throw 1337;");
4321  CHECK(message_received);
4322  // clear out the message listener
4323  v8::V8::RemoveMessageListeners(check_message_1);
4324}
4325
4326
4327static void check_message_2(v8::Handle<v8::Message> message,
4328                            v8::Handle<Value> data) {
4329  LocalContext context;
4330  CHECK(data->IsObject());
4331  v8::Local<v8::Value> hidden_property =
4332      v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4333  CHECK(v8_str("hidden value")->Equals(hidden_property));
4334  CHECK(!message->IsSharedCrossOrigin());
4335  message_received = true;
4336}
4337
4338
4339TEST(MessageHandler2) {
4340  message_received = false;
4341  v8::HandleScope scope(CcTest::isolate());
4342  CHECK(!message_received);
4343  v8::V8::AddMessageListener(check_message_2);
4344  LocalContext context;
4345  v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4346  v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4347                                           v8_str("hidden value"));
4348  context->Global()->Set(v8_str("error"), error);
4349  CompileRun("throw error;");
4350  CHECK(message_received);
4351  // clear out the message listener
4352  v8::V8::RemoveMessageListeners(check_message_2);
4353}
4354
4355
4356static void check_message_3(v8::Handle<v8::Message> message,
4357                            v8::Handle<Value> data) {
4358  CHECK(message->IsSharedCrossOrigin());
4359  CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4360  message_received = true;
4361}
4362
4363
4364TEST(MessageHandler3) {
4365  message_received = false;
4366  v8::Isolate* isolate = CcTest::isolate();
4367  v8::HandleScope scope(isolate);
4368  CHECK(!message_received);
4369  v8::V8::AddMessageListener(check_message_3);
4370  LocalContext context;
4371  v8::ScriptOrigin origin =
4372      v8::ScriptOrigin(v8_str("6.75"),
4373                       v8::Integer::New(isolate, 1),
4374                       v8::Integer::New(isolate, 2),
4375                       v8::True(isolate));
4376  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4377                                                  &origin);
4378  script->Run();
4379  CHECK(message_received);
4380  // clear out the message listener
4381  v8::V8::RemoveMessageListeners(check_message_3);
4382}
4383
4384
4385static void check_message_4(v8::Handle<v8::Message> message,
4386                            v8::Handle<Value> data) {
4387  CHECK(!message->IsSharedCrossOrigin());
4388  CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4389  message_received = true;
4390}
4391
4392
4393TEST(MessageHandler4) {
4394  message_received = false;
4395  v8::Isolate* isolate = CcTest::isolate();
4396  v8::HandleScope scope(isolate);
4397  CHECK(!message_received);
4398  v8::V8::AddMessageListener(check_message_4);
4399  LocalContext context;
4400  v8::ScriptOrigin origin =
4401      v8::ScriptOrigin(v8_str("6.75"),
4402                       v8::Integer::New(isolate, 1),
4403                       v8::Integer::New(isolate, 2),
4404                       v8::False(isolate));
4405  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4406                                                  &origin);
4407  script->Run();
4408  CHECK(message_received);
4409  // clear out the message listener
4410  v8::V8::RemoveMessageListeners(check_message_4);
4411}
4412
4413
4414static void check_message_5a(v8::Handle<v8::Message> message,
4415                            v8::Handle<Value> data) {
4416  CHECK(message->IsSharedCrossOrigin());
4417  CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4418  message_received = true;
4419}
4420
4421
4422static void check_message_5b(v8::Handle<v8::Message> message,
4423                            v8::Handle<Value> data) {
4424  CHECK(!message->IsSharedCrossOrigin());
4425  CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4426  message_received = true;
4427}
4428
4429
4430TEST(MessageHandler5) {
4431  message_received = false;
4432  v8::Isolate* isolate = CcTest::isolate();
4433  v8::HandleScope scope(isolate);
4434  CHECK(!message_received);
4435  v8::V8::AddMessageListener(check_message_5a);
4436  LocalContext context;
4437  v8::ScriptOrigin origin =
4438      v8::ScriptOrigin(v8_str("6.75"),
4439                       v8::Integer::New(isolate, 1),
4440                       v8::Integer::New(isolate, 2),
4441                       v8::True(isolate));
4442  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4443                                                  &origin);
4444  script->Run();
4445  CHECK(message_received);
4446  // clear out the message listener
4447  v8::V8::RemoveMessageListeners(check_message_5a);
4448
4449  message_received = false;
4450  v8::V8::AddMessageListener(check_message_5b);
4451  origin =
4452      v8::ScriptOrigin(v8_str("6.75"),
4453                       v8::Integer::New(isolate, 1),
4454                       v8::Integer::New(isolate, 2),
4455                       v8::False(isolate));
4456  script = Script::Compile(v8_str("throw 'error'"),
4457                           &origin);
4458  script->Run();
4459  CHECK(message_received);
4460  // clear out the message listener
4461  v8::V8::RemoveMessageListeners(check_message_5b);
4462}
4463
4464
4465THREADED_TEST(GetSetProperty) {
4466  LocalContext context;
4467  v8::Isolate* isolate = context->GetIsolate();
4468  v8::HandleScope scope(isolate);
4469  context->Global()->Set(v8_str("foo"), v8_num(14));
4470  context->Global()->Set(v8_str("12"), v8_num(92));
4471  context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4472  context->Global()->Set(v8_num(13), v8_num(56));
4473  Local<Value> foo = CompileRun("this.foo");
4474  CHECK_EQ(14, foo->Int32Value());
4475  Local<Value> twelve = CompileRun("this[12]");
4476  CHECK_EQ(92, twelve->Int32Value());
4477  Local<Value> sixteen = CompileRun("this[16]");
4478  CHECK_EQ(32, sixteen->Int32Value());
4479  Local<Value> thirteen = CompileRun("this[13]");
4480  CHECK_EQ(56, thirteen->Int32Value());
4481  CHECK_EQ(92,
4482           context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4483  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4484  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4485  CHECK_EQ(32,
4486           context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4487  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4488  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4489  CHECK_EQ(56,
4490           context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4491  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4492  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4493}
4494
4495
4496THREADED_TEST(PropertyAttributes) {
4497  LocalContext context;
4498  v8::HandleScope scope(context->GetIsolate());
4499  // none
4500  Local<String> prop = v8_str("none");
4501  context->Global()->Set(prop, v8_num(7));
4502  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4503  // read-only
4504  prop = v8_str("read_only");
4505  context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4506  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4507  CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4508  CompileRun("read_only = 9");
4509  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4510  context->Global()->Set(prop, v8_num(10));
4511  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4512  // dont-delete
4513  prop = v8_str("dont_delete");
4514  context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4515  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4516  CompileRun("delete dont_delete");
4517  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4518  CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4519  // dont-enum
4520  prop = v8_str("dont_enum");
4521  context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4522  CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4523  // absent
4524  prop = v8_str("absent");
4525  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4526  Local<Value> fake_prop = v8_num(1);
4527  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4528  // exception
4529  TryCatch try_catch;
4530  Local<Value> exception =
4531      CompileRun("({ toString: function() { throw 'exception';} })");
4532  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4533  CHECK(try_catch.HasCaught());
4534  String::Utf8Value exception_value(try_catch.Exception());
4535  CHECK_EQ("exception", *exception_value);
4536  try_catch.Reset();
4537}
4538
4539
4540THREADED_TEST(Array) {
4541  LocalContext context;
4542  v8::HandleScope scope(context->GetIsolate());
4543  Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4544  CHECK_EQ(0, array->Length());
4545  CHECK(array->Get(0)->IsUndefined());
4546  CHECK(!array->Has(0));
4547  CHECK(array->Get(100)->IsUndefined());
4548  CHECK(!array->Has(100));
4549  array->Set(2, v8_num(7));
4550  CHECK_EQ(3, array->Length());
4551  CHECK(!array->Has(0));
4552  CHECK(!array->Has(1));
4553  CHECK(array->Has(2));
4554  CHECK_EQ(7, array->Get(2)->Int32Value());
4555  Local<Value> obj = CompileRun("[1, 2, 3]");
4556  Local<v8::Array> arr = obj.As<v8::Array>();
4557  CHECK_EQ(3, arr->Length());
4558  CHECK_EQ(1, arr->Get(0)->Int32Value());
4559  CHECK_EQ(2, arr->Get(1)->Int32Value());
4560  CHECK_EQ(3, arr->Get(2)->Int32Value());
4561  array = v8::Array::New(context->GetIsolate(), 27);
4562  CHECK_EQ(27, array->Length());
4563  array = v8::Array::New(context->GetIsolate(), -27);
4564  CHECK_EQ(0, array->Length());
4565}
4566
4567
4568void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4569  v8::EscapableHandleScope scope(args.GetIsolate());
4570  ApiTestFuzzer::Fuzz();
4571  Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4572  for (int i = 0; i < args.Length(); i++)
4573    result->Set(i, args[i]);
4574  args.GetReturnValue().Set(scope.Escape(result));
4575}
4576
4577
4578THREADED_TEST(Vector) {
4579  v8::Isolate* isolate = CcTest::isolate();
4580  v8::HandleScope scope(isolate);
4581  Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4582  global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4583  LocalContext context(0, global);
4584
4585  const char* fun = "f()";
4586  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4587  CHECK_EQ(0, a0->Length());
4588
4589  const char* fun2 = "f(11)";
4590  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4591  CHECK_EQ(1, a1->Length());
4592  CHECK_EQ(11, a1->Get(0)->Int32Value());
4593
4594  const char* fun3 = "f(12, 13)";
4595  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4596  CHECK_EQ(2, a2->Length());
4597  CHECK_EQ(12, a2->Get(0)->Int32Value());
4598  CHECK_EQ(13, a2->Get(1)->Int32Value());
4599
4600  const char* fun4 = "f(14, 15, 16)";
4601  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4602  CHECK_EQ(3, a3->Length());
4603  CHECK_EQ(14, a3->Get(0)->Int32Value());
4604  CHECK_EQ(15, a3->Get(1)->Int32Value());
4605  CHECK_EQ(16, a3->Get(2)->Int32Value());
4606
4607  const char* fun5 = "f(17, 18, 19, 20)";
4608  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4609  CHECK_EQ(4, a4->Length());
4610  CHECK_EQ(17, a4->Get(0)->Int32Value());
4611  CHECK_EQ(18, a4->Get(1)->Int32Value());
4612  CHECK_EQ(19, a4->Get(2)->Int32Value());
4613  CHECK_EQ(20, a4->Get(3)->Int32Value());
4614}
4615
4616
4617THREADED_TEST(FunctionCall) {
4618  LocalContext context;
4619  v8::Isolate* isolate = context->GetIsolate();
4620  v8::HandleScope scope(isolate);
4621  CompileRun(
4622    "function Foo() {"
4623    "  var result = [];"
4624    "  for (var i = 0; i < arguments.length; i++) {"
4625    "    result.push(arguments[i]);"
4626    "  }"
4627    "  return result;"
4628    "}"
4629    "function ReturnThisSloppy() {"
4630    "  return this;"
4631    "}"
4632    "function ReturnThisStrict() {"
4633    "  'use strict';"
4634    "  return this;"
4635    "}");
4636  Local<Function> Foo =
4637      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4638  Local<Function> ReturnThisSloppy =
4639      Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4640  Local<Function> ReturnThisStrict =
4641      Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4642
4643  v8::Handle<Value>* args0 = NULL;
4644  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4645  CHECK_EQ(0, a0->Length());
4646
4647  v8::Handle<Value> args1[] = { v8_num(1.1) };
4648  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4649  CHECK_EQ(1, a1->Length());
4650  CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4651
4652  v8::Handle<Value> args2[] = { v8_num(2.2),
4653                                v8_num(3.3) };
4654  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4655  CHECK_EQ(2, a2->Length());
4656  CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4657  CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4658
4659  v8::Handle<Value> args3[] = { v8_num(4.4),
4660                                v8_num(5.5),
4661                                v8_num(6.6) };
4662  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4663  CHECK_EQ(3, a3->Length());
4664  CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4665  CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4666  CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4667
4668  v8::Handle<Value> args4[] = { v8_num(7.7),
4669                                v8_num(8.8),
4670                                v8_num(9.9),
4671                                v8_num(10.11) };
4672  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4673  CHECK_EQ(4, a4->Length());
4674  CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4675  CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4676  CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4677  CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4678
4679  Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4680  CHECK(r1->StrictEquals(context->Global()));
4681  Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4682  CHECK(r2->StrictEquals(context->Global()));
4683  Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4684  CHECK(r3->IsNumberObject());
4685  CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4686  Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4687  CHECK(r4->IsStringObject());
4688  CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4689  Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4690  CHECK(r5->IsBooleanObject());
4691  CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4692
4693  Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4694  CHECK(r6->IsUndefined());
4695  Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4696  CHECK(r7->IsNull());
4697  Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4698  CHECK(r8->StrictEquals(v8_num(42)));
4699  Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4700  CHECK(r9->StrictEquals(v8_str("hello")));
4701  Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4702  CHECK(r10->StrictEquals(v8::True(isolate)));
4703}
4704
4705
4706THREADED_TEST(ConstructCall) {
4707  LocalContext context;
4708  v8::Isolate* isolate = context->GetIsolate();
4709  v8::HandleScope scope(isolate);
4710  CompileRun(
4711    "function Foo() {"
4712    "  var result = [];"
4713    "  for (var i = 0; i < arguments.length; i++) {"
4714    "    result.push(arguments[i]);"
4715    "  }"
4716    "  return result;"
4717    "}");
4718  Local<Function> Foo =
4719      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4720
4721  v8::Handle<Value>* args0 = NULL;
4722  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4723  CHECK_EQ(0, a0->Length());
4724
4725  v8::Handle<Value> args1[] = { v8_num(1.1) };
4726  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4727  CHECK_EQ(1, a1->Length());
4728  CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4729
4730  v8::Handle<Value> args2[] = { v8_num(2.2),
4731                                v8_num(3.3) };
4732  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4733  CHECK_EQ(2, a2->Length());
4734  CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4735  CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4736
4737  v8::Handle<Value> args3[] = { v8_num(4.4),
4738                                v8_num(5.5),
4739                                v8_num(6.6) };
4740  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4741  CHECK_EQ(3, a3->Length());
4742  CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4743  CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4744  CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4745
4746  v8::Handle<Value> args4[] = { v8_num(7.7),
4747                                v8_num(8.8),
4748                                v8_num(9.9),
4749                                v8_num(10.11) };
4750  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4751  CHECK_EQ(4, a4->Length());
4752  CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4753  CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4754  CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4755  CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4756}
4757
4758
4759static void CheckUncle(v8::TryCatch* try_catch) {
4760  CHECK(try_catch->HasCaught());
4761  String::Utf8Value str_value(try_catch->Exception());
4762  CHECK_EQ(*str_value, "uncle?");
4763  try_catch->Reset();
4764}
4765
4766
4767THREADED_TEST(ConversionNumber) {
4768  LocalContext env;
4769  v8::HandleScope scope(env->GetIsolate());
4770  // Very large number.
4771  CompileRun("var obj = Math.pow(2,32) * 1237;");
4772  Local<Value> obj = env->Global()->Get(v8_str("obj"));
4773  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4774  CHECK_EQ(0, obj->ToInt32()->Value());
4775  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4776  // Large number.
4777  CompileRun("var obj = -1234567890123;");
4778  obj = env->Global()->Get(v8_str("obj"));
4779  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4780  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4781  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4782  // Small positive integer.
4783  CompileRun("var obj = 42;");
4784  obj = env->Global()->Get(v8_str("obj"));
4785  CHECK_EQ(42.0, obj->ToNumber()->Value());
4786  CHECK_EQ(42, obj->ToInt32()->Value());
4787  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4788  // Negative integer.
4789  CompileRun("var obj = -37;");
4790  obj = env->Global()->Get(v8_str("obj"));
4791  CHECK_EQ(-37.0, obj->ToNumber()->Value());
4792  CHECK_EQ(-37, obj->ToInt32()->Value());
4793  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4794  // Positive non-int32 integer.
4795  CompileRun("var obj = 0x81234567;");
4796  obj = env->Global()->Get(v8_str("obj"));
4797  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4798  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4799  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4800  // Fraction.
4801  CompileRun("var obj = 42.3;");
4802  obj = env->Global()->Get(v8_str("obj"));
4803  CHECK_EQ(42.3, obj->ToNumber()->Value());
4804  CHECK_EQ(42, obj->ToInt32()->Value());
4805  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4806  // Large negative fraction.
4807  CompileRun("var obj = -5726623061.75;");
4808  obj = env->Global()->Get(v8_str("obj"));
4809  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4810  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4811  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4812}
4813
4814
4815THREADED_TEST(isNumberType) {
4816  LocalContext env;
4817  v8::HandleScope scope(env->GetIsolate());
4818  // Very large number.
4819  CompileRun("var obj = Math.pow(2,32) * 1237;");
4820  Local<Value> obj = env->Global()->Get(v8_str("obj"));
4821  CHECK(!obj->IsInt32());
4822  CHECK(!obj->IsUint32());
4823  // Large negative number.
4824  CompileRun("var obj = -1234567890123;");
4825  obj = env->Global()->Get(v8_str("obj"));
4826  CHECK(!obj->IsInt32());
4827  CHECK(!obj->IsUint32());
4828  // Small positive integer.
4829  CompileRun("var obj = 42;");
4830  obj = env->Global()->Get(v8_str("obj"));
4831  CHECK(obj->IsInt32());
4832  CHECK(obj->IsUint32());
4833  // Negative integer.
4834  CompileRun("var obj = -37;");
4835  obj = env->Global()->Get(v8_str("obj"));
4836  CHECK(obj->IsInt32());
4837  CHECK(!obj->IsUint32());
4838  // Positive non-int32 integer.
4839  CompileRun("var obj = 0x81234567;");
4840  obj = env->Global()->Get(v8_str("obj"));
4841  CHECK(!obj->IsInt32());
4842  CHECK(obj->IsUint32());
4843  // Fraction.
4844  CompileRun("var obj = 42.3;");
4845  obj = env->Global()->Get(v8_str("obj"));
4846  CHECK(!obj->IsInt32());
4847  CHECK(!obj->IsUint32());
4848  // Large negative fraction.
4849  CompileRun("var obj = -5726623061.75;");
4850  obj = env->Global()->Get(v8_str("obj"));
4851  CHECK(!obj->IsInt32());
4852  CHECK(!obj->IsUint32());
4853  // Positive zero
4854  CompileRun("var obj = 0.0;");
4855  obj = env->Global()->Get(v8_str("obj"));
4856  CHECK(obj->IsInt32());
4857  CHECK(obj->IsUint32());
4858  // Positive zero
4859  CompileRun("var obj = -0.0;");
4860  obj = env->Global()->Get(v8_str("obj"));
4861  CHECK(!obj->IsInt32());
4862  CHECK(!obj->IsUint32());
4863}
4864
4865
4866THREADED_TEST(ConversionException) {
4867  LocalContext env;
4868  v8::Isolate* isolate = env->GetIsolate();
4869  v8::HandleScope scope(isolate);
4870  CompileRun(
4871    "function TestClass() { };"
4872    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4873    "var obj = new TestClass();");
4874  Local<Value> obj = env->Global()->Get(v8_str("obj"));
4875
4876  v8::TryCatch try_catch;
4877
4878  Local<Value> to_string_result = obj->ToString();
4879  CHECK(to_string_result.IsEmpty());
4880  CheckUncle(&try_catch);
4881
4882  Local<Value> to_number_result = obj->ToNumber();
4883  CHECK(to_number_result.IsEmpty());
4884  CheckUncle(&try_catch);
4885
4886  Local<Value> to_integer_result = obj->ToInteger();
4887  CHECK(to_integer_result.IsEmpty());
4888  CheckUncle(&try_catch);
4889
4890  Local<Value> to_uint32_result = obj->ToUint32();
4891  CHECK(to_uint32_result.IsEmpty());
4892  CheckUncle(&try_catch);
4893
4894  Local<Value> to_int32_result = obj->ToInt32();
4895  CHECK(to_int32_result.IsEmpty());
4896  CheckUncle(&try_catch);
4897
4898  Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4899  CHECK(to_object_result.IsEmpty());
4900  CHECK(try_catch.HasCaught());
4901  try_catch.Reset();
4902
4903  int32_t int32_value = obj->Int32Value();
4904  CHECK_EQ(0, int32_value);
4905  CheckUncle(&try_catch);
4906
4907  uint32_t uint32_value = obj->Uint32Value();
4908  CHECK_EQ(0, uint32_value);
4909  CheckUncle(&try_catch);
4910
4911  double number_value = obj->NumberValue();
4912  CHECK_NE(0, std::isnan(number_value));
4913  CheckUncle(&try_catch);
4914
4915  int64_t integer_value = obj->IntegerValue();
4916  CHECK_EQ(0.0, static_cast<double>(integer_value));
4917  CheckUncle(&try_catch);
4918}
4919
4920
4921void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4922  ApiTestFuzzer::Fuzz();
4923  args.GetIsolate()->ThrowException(v8_str("konto"));
4924}
4925
4926
4927void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4928  if (args.Length() < 1) {
4929    args.GetReturnValue().Set(false);
4930    return;
4931  }
4932  v8::HandleScope scope(args.GetIsolate());
4933  v8::TryCatch try_catch;
4934  Local<Value> result = CompileRun(args[0]->ToString());
4935  CHECK(!try_catch.HasCaught() || result.IsEmpty());
4936  args.GetReturnValue().Set(try_catch.HasCaught());
4937}
4938
4939
4940THREADED_TEST(APICatch) {
4941  v8::Isolate* isolate = CcTest::isolate();
4942  v8::HandleScope scope(isolate);
4943  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4944  templ->Set(v8_str("ThrowFromC"),
4945             v8::FunctionTemplate::New(isolate, ThrowFromC));
4946  LocalContext context(0, templ);
4947  CompileRun(
4948    "var thrown = false;"
4949    "try {"
4950    "  ThrowFromC();"
4951    "} catch (e) {"
4952    "  thrown = true;"
4953    "}");
4954  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4955  CHECK(thrown->BooleanValue());
4956}
4957
4958
4959THREADED_TEST(APIThrowTryCatch) {
4960  v8::Isolate* isolate = CcTest::isolate();
4961  v8::HandleScope scope(isolate);
4962  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4963  templ->Set(v8_str("ThrowFromC"),
4964             v8::FunctionTemplate::New(isolate, ThrowFromC));
4965  LocalContext context(0, templ);
4966  v8::TryCatch try_catch;
4967  CompileRun("ThrowFromC();");
4968  CHECK(try_catch.HasCaught());
4969}
4970
4971
4972// Test that a try-finally block doesn't shadow a try-catch block
4973// when setting up an external handler.
4974//
4975// BUG(271): Some of the exception propagation does not work on the
4976// ARM simulator because the simulator separates the C++ stack and the
4977// JS stack.  This test therefore fails on the simulator.  The test is
4978// not threaded to allow the threading tests to run on the simulator.
4979TEST(TryCatchInTryFinally) {
4980  v8::Isolate* isolate = CcTest::isolate();
4981  v8::HandleScope scope(isolate);
4982  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4983  templ->Set(v8_str("CCatcher"),
4984             v8::FunctionTemplate::New(isolate, CCatcher));
4985  LocalContext context(0, templ);
4986  Local<Value> result = CompileRun("try {"
4987                                   "  try {"
4988                                   "    CCatcher('throw 7;');"
4989                                   "  } finally {"
4990                                   "  }"
4991                                   "} catch (e) {"
4992                                   "}");
4993  CHECK(result->IsTrue());
4994}
4995
4996
4997static void check_reference_error_message(
4998    v8::Handle<v8::Message> message,
4999    v8::Handle<v8::Value> data) {
5000  const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
5001  CHECK(message->Get()->Equals(v8_str(reference_error)));
5002}
5003
5004
5005static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
5006  ApiTestFuzzer::Fuzz();
5007  CHECK(false);
5008}
5009
5010
5011// Test that overwritten methods are not invoked on uncaught exception
5012// formatting. However, they are invoked when performing normal error
5013// string conversions.
5014TEST(APIThrowMessageOverwrittenToString) {
5015  v8::Isolate* isolate = CcTest::isolate();
5016  v8::HandleScope scope(isolate);
5017  v8::V8::AddMessageListener(check_reference_error_message);
5018  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5019  templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
5020  LocalContext context(NULL, templ);
5021  CompileRun("asdf;");
5022  CompileRun("var limit = {};"
5023             "limit.valueOf = fail;"
5024             "Error.stackTraceLimit = limit;");
5025  CompileRun("asdf");
5026  CompileRun("Array.prototype.pop = fail;");
5027  CompileRun("Object.prototype.hasOwnProperty = fail;");
5028  CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
5029  CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
5030  CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
5031  CompileRun("ReferenceError.prototype.toString ="
5032             "  function() { return 'Whoops' }");
5033  CompileRun("asdf;");
5034  CompileRun("ReferenceError.prototype.constructor.name = void 0;");
5035  CompileRun("asdf;");
5036  CompileRun("ReferenceError.prototype.constructor = void 0;");
5037  CompileRun("asdf;");
5038  CompileRun("ReferenceError.prototype.__proto__ = new Object();");
5039  CompileRun("asdf;");
5040  CompileRun("ReferenceError.prototype = new Object();");
5041  CompileRun("asdf;");
5042  v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
5043  CHECK(string->Equals(v8_str("Whoops")));
5044  CompileRun("ReferenceError.prototype.constructor = new Object();"
5045             "ReferenceError.prototype.constructor.name = 1;"
5046             "Number.prototype.toString = function() { return 'Whoops'; };"
5047             "ReferenceError.prototype.toString = Object.prototype.toString;");
5048  CompileRun("asdf;");
5049  v8::V8::RemoveMessageListeners(check_reference_error_message);
5050}
5051
5052
5053static void check_custom_error_tostring(
5054    v8::Handle<v8::Message> message,
5055    v8::Handle<v8::Value> data) {
5056  const char* uncaught_error = "Uncaught MyError toString";
5057  CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5058}
5059
5060
5061TEST(CustomErrorToString) {
5062  LocalContext context;
5063  v8::HandleScope scope(context->GetIsolate());
5064  v8::V8::AddMessageListener(check_custom_error_tostring);
5065  CompileRun(
5066    "function MyError(name, message) {                   "
5067    "  this.name = name;                                 "
5068    "  this.message = message;                           "
5069    "}                                                   "
5070    "MyError.prototype = Object.create(Error.prototype); "
5071    "MyError.prototype.toString = function() {           "
5072    "  return 'MyError toString';                        "
5073    "};                                                  "
5074    "throw new MyError('my name', 'my message');         ");
5075  v8::V8::RemoveMessageListeners(check_custom_error_tostring);
5076}
5077
5078
5079static void check_custom_error_message(
5080    v8::Handle<v8::Message> message,
5081    v8::Handle<v8::Value> data) {
5082  const char* uncaught_error = "Uncaught MyError: my message";
5083  printf("%s\n", *v8::String::Utf8Value(message->Get()));
5084  CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5085}
5086
5087
5088TEST(CustomErrorMessage) {
5089  LocalContext context;
5090  v8::HandleScope scope(context->GetIsolate());
5091  v8::V8::AddMessageListener(check_custom_error_message);
5092
5093  // Handlebars.
5094  CompileRun(
5095    "function MyError(msg) {                             "
5096    "  this.name = 'MyError';                            "
5097    "  this.message = msg;                               "
5098    "}                                                   "
5099    "MyError.prototype = new Error();                    "
5100    "throw new MyError('my message');                    ");
5101
5102  // Closure.
5103  CompileRun(
5104    "function MyError(msg) {                             "
5105    "  this.name = 'MyError';                            "
5106    "  this.message = msg;                               "
5107    "}                                                   "
5108    "inherits = function(childCtor, parentCtor) {        "
5109    "    function tempCtor() {};                         "
5110    "    tempCtor.prototype = parentCtor.prototype;      "
5111    "    childCtor.superClass_ = parentCtor.prototype;   "
5112    "    childCtor.prototype = new tempCtor();           "
5113    "    childCtor.prototype.constructor = childCtor;    "
5114    "};                                                  "
5115    "inherits(MyError, Error);                           "
5116    "throw new MyError('my message');                    ");
5117
5118  // Object.create.
5119  CompileRun(
5120    "function MyError(msg) {                             "
5121    "  this.name = 'MyError';                            "
5122    "  this.message = msg;                               "
5123    "}                                                   "
5124    "MyError.prototype = Object.create(Error.prototype); "
5125    "throw new MyError('my message');                    ");
5126
5127  v8::V8::RemoveMessageListeners(check_custom_error_message);
5128}
5129
5130
5131static void receive_message(v8::Handle<v8::Message> message,
5132                            v8::Handle<v8::Value> data) {
5133  message->Get();
5134  message_received = true;
5135}
5136
5137
5138TEST(APIThrowMessage) {
5139  message_received = false;
5140  v8::Isolate* isolate = CcTest::isolate();
5141  v8::HandleScope scope(isolate);
5142  v8::V8::AddMessageListener(receive_message);
5143  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5144  templ->Set(v8_str("ThrowFromC"),
5145             v8::FunctionTemplate::New(isolate, ThrowFromC));
5146  LocalContext context(0, templ);
5147  CompileRun("ThrowFromC();");
5148  CHECK(message_received);
5149  v8::V8::RemoveMessageListeners(receive_message);
5150}
5151
5152
5153TEST(APIThrowMessageAndVerboseTryCatch) {
5154  message_received = false;
5155  v8::Isolate* isolate = CcTest::isolate();
5156  v8::HandleScope scope(isolate);
5157  v8::V8::AddMessageListener(receive_message);
5158  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5159  templ->Set(v8_str("ThrowFromC"),
5160             v8::FunctionTemplate::New(isolate, ThrowFromC));
5161  LocalContext context(0, templ);
5162  v8::TryCatch try_catch;
5163  try_catch.SetVerbose(true);
5164  Local<Value> result = CompileRun("ThrowFromC();");
5165  CHECK(try_catch.HasCaught());
5166  CHECK(result.IsEmpty());
5167  CHECK(message_received);
5168  v8::V8::RemoveMessageListeners(receive_message);
5169}
5170
5171
5172TEST(APIStackOverflowAndVerboseTryCatch) {
5173  message_received = false;
5174  LocalContext context;
5175  v8::HandleScope scope(context->GetIsolate());
5176  v8::V8::AddMessageListener(receive_message);
5177  v8::TryCatch try_catch;
5178  try_catch.SetVerbose(true);
5179  Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5180  CHECK(try_catch.HasCaught());
5181  CHECK(result.IsEmpty());
5182  CHECK(message_received);
5183  v8::V8::RemoveMessageListeners(receive_message);
5184}
5185
5186
5187THREADED_TEST(ExternalScriptException) {
5188  v8::Isolate* isolate = CcTest::isolate();
5189  v8::HandleScope scope(isolate);
5190  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5191  templ->Set(v8_str("ThrowFromC"),
5192             v8::FunctionTemplate::New(isolate, ThrowFromC));
5193  LocalContext context(0, templ);
5194
5195  v8::TryCatch try_catch;
5196  Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5197  CHECK(result.IsEmpty());
5198  CHECK(try_catch.HasCaught());
5199  String::Utf8Value exception_value(try_catch.Exception());
5200  CHECK_EQ("konto", *exception_value);
5201}
5202
5203
5204
5205void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5206  ApiTestFuzzer::Fuzz();
5207  CHECK_EQ(4, args.Length());
5208  int count = args[0]->Int32Value();
5209  int cInterval = args[2]->Int32Value();
5210  if (count == 0) {
5211    args.GetIsolate()->ThrowException(v8_str("FromC"));
5212    return;
5213  } else {
5214    Local<v8::Object> global =
5215        args.GetIsolate()->GetCurrentContext()->Global();
5216    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5217    v8::Handle<Value> argv[] = { v8_num(count - 1),
5218                                 args[1],
5219                                 args[2],
5220                                 args[3] };
5221    if (count % cInterval == 0) {
5222      v8::TryCatch try_catch;
5223      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5224      int expected = args[3]->Int32Value();
5225      if (try_catch.HasCaught()) {
5226        CHECK_EQ(expected, count);
5227        CHECK(result.IsEmpty());
5228        CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5229      } else {
5230        CHECK_NE(expected, count);
5231      }
5232      args.GetReturnValue().Set(result);
5233      return;
5234    } else {
5235      args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5236      return;
5237    }
5238  }
5239}
5240
5241
5242void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5243  ApiTestFuzzer::Fuzz();
5244  CHECK_EQ(3, args.Length());
5245  bool equality = args[0]->BooleanValue();
5246  int count = args[1]->Int32Value();
5247  int expected = args[2]->Int32Value();
5248  if (equality) {
5249    CHECK_EQ(count, expected);
5250  } else {
5251    CHECK_NE(count, expected);
5252  }
5253}
5254
5255
5256THREADED_TEST(EvalInTryFinally) {
5257  LocalContext context;
5258  v8::HandleScope scope(context->GetIsolate());
5259  v8::TryCatch try_catch;
5260  CompileRun("(function() {"
5261             "  try {"
5262             "    eval('asldkf (*&^&*^');"
5263             "  } finally {"
5264             "    return;"
5265             "  }"
5266             "})()");
5267  CHECK(!try_catch.HasCaught());
5268}
5269
5270
5271// This test works by making a stack of alternating JavaScript and C
5272// activations.  These activations set up exception handlers with regular
5273// intervals, one interval for C activations and another for JavaScript
5274// activations.  When enough activations have been created an exception is
5275// thrown and we check that the right activation catches the exception and that
5276// no other activations do.  The right activation is always the topmost one with
5277// a handler, regardless of whether it is in JavaScript or C.
5278//
5279// The notation used to describe a test case looks like this:
5280//
5281//    *JS[4] *C[3] @JS[2] C[1] JS[0]
5282//
5283// Each entry is an activation, either JS or C.  The index is the count at that
5284// level.  Stars identify activations with exception handlers, the @ identifies
5285// the exception handler that should catch the exception.
5286//
5287// BUG(271): Some of the exception propagation does not work on the
5288// ARM simulator because the simulator separates the C++ stack and the
5289// JS stack.  This test therefore fails on the simulator.  The test is
5290// not threaded to allow the threading tests to run on the simulator.
5291TEST(ExceptionOrder) {
5292  v8::Isolate* isolate = CcTest::isolate();
5293  v8::HandleScope scope(isolate);
5294  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5295  templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5296  templ->Set(v8_str("CThrowCountDown"),
5297             v8::FunctionTemplate::New(isolate, CThrowCountDown));
5298  LocalContext context(0, templ);
5299  CompileRun(
5300    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5301    "  if (count == 0) throw 'FromJS';"
5302    "  if (count % jsInterval == 0) {"
5303    "    try {"
5304    "      var value = CThrowCountDown(count - 1,"
5305    "                                  jsInterval,"
5306    "                                  cInterval,"
5307    "                                  expected);"
5308    "      check(false, count, expected);"
5309    "      return value;"
5310    "    } catch (e) {"
5311    "      check(true, count, expected);"
5312    "    }"
5313    "  } else {"
5314    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5315    "  }"
5316    "}");
5317  Local<Function> fun =
5318      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5319
5320  const int argc = 4;
5321  //                             count      jsInterval cInterval  expected
5322
5323  // *JS[4] *C[3] @JS[2] C[1] JS[0]
5324  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5325  fun->Call(fun, argc, a0);
5326
5327  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5328  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5329  fun->Call(fun, argc, a1);
5330
5331  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5332  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5333  fun->Call(fun, argc, a2);
5334
5335  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5336  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5337  fun->Call(fun, argc, a3);
5338
5339  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5340  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5341  fun->Call(fun, argc, a4);
5342
5343  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5344  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5345  fun->Call(fun, argc, a5);
5346}
5347
5348
5349void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5350  ApiTestFuzzer::Fuzz();
5351  CHECK_EQ(1, args.Length());
5352  args.GetIsolate()->ThrowException(args[0]);
5353}
5354
5355
5356THREADED_TEST(ThrowValues) {
5357  v8::Isolate* isolate = CcTest::isolate();
5358  v8::HandleScope scope(isolate);
5359  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5360  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5361  LocalContext context(0, templ);
5362  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5363    "function Run(obj) {"
5364    "  try {"
5365    "    Throw(obj);"
5366    "  } catch (e) {"
5367    "    return e;"
5368    "  }"
5369    "  return 'no exception';"
5370    "}"
5371    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5372  CHECK_EQ(5, result->Length());
5373  CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5374  CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5375  CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5376  CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5377  CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5378  CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5379  CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5380}
5381
5382
5383THREADED_TEST(CatchZero) {
5384  LocalContext context;
5385  v8::HandleScope scope(context->GetIsolate());
5386  v8::TryCatch try_catch;
5387  CHECK(!try_catch.HasCaught());
5388  CompileRun("throw 10");
5389  CHECK(try_catch.HasCaught());
5390  CHECK_EQ(10, try_catch.Exception()->Int32Value());
5391  try_catch.Reset();
5392  CHECK(!try_catch.HasCaught());
5393  CompileRun("throw 0");
5394  CHECK(try_catch.HasCaught());
5395  CHECK_EQ(0, try_catch.Exception()->Int32Value());
5396}
5397
5398
5399THREADED_TEST(CatchExceptionFromWith) {
5400  LocalContext context;
5401  v8::HandleScope scope(context->GetIsolate());
5402  v8::TryCatch try_catch;
5403  CHECK(!try_catch.HasCaught());
5404  CompileRun("var o = {}; with (o) { throw 42; }");
5405  CHECK(try_catch.HasCaught());
5406}
5407
5408
5409THREADED_TEST(TryCatchAndFinallyHidingException) {
5410  LocalContext context;
5411  v8::HandleScope scope(context->GetIsolate());
5412  v8::TryCatch try_catch;
5413  CHECK(!try_catch.HasCaught());
5414  CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5415  CompileRun("f({toString: function() { throw 42; }});");
5416  CHECK(!try_catch.HasCaught());
5417}
5418
5419
5420void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5421  v8::TryCatch try_catch;
5422}
5423
5424
5425THREADED_TEST(TryCatchAndFinally) {
5426  LocalContext context;
5427  v8::Isolate* isolate = context->GetIsolate();
5428  v8::HandleScope scope(isolate);
5429  context->Global()->Set(
5430      v8_str("native_with_try_catch"),
5431      v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5432  v8::TryCatch try_catch;
5433  CHECK(!try_catch.HasCaught());
5434  CompileRun(
5435      "try {\n"
5436      "  throw new Error('a');\n"
5437      "} finally {\n"
5438      "  native_with_try_catch();\n"
5439      "}\n");
5440  CHECK(try_catch.HasCaught());
5441}
5442
5443
5444static void TryCatchNested1Helper(int depth) {
5445  if (depth > 0) {
5446    v8::TryCatch try_catch;
5447    try_catch.SetVerbose(true);
5448    TryCatchNested1Helper(depth - 1);
5449    CHECK(try_catch.HasCaught());
5450    try_catch.ReThrow();
5451  } else {
5452    CcTest::isolate()->ThrowException(v8_str("E1"));
5453  }
5454}
5455
5456
5457static void TryCatchNested2Helper(int depth) {
5458  if (depth > 0) {
5459    v8::TryCatch try_catch;
5460    try_catch.SetVerbose(true);
5461    TryCatchNested2Helper(depth - 1);
5462    CHECK(try_catch.HasCaught());
5463    try_catch.ReThrow();
5464  } else {
5465    CompileRun("throw 'E2';");
5466  }
5467}
5468
5469
5470TEST(TryCatchNested) {
5471  v8::V8::Initialize();
5472  LocalContext context;
5473  v8::HandleScope scope(context->GetIsolate());
5474
5475  {
5476    // Test nested try-catch with a native throw in the end.
5477    v8::TryCatch try_catch;
5478    TryCatchNested1Helper(5);
5479    CHECK(try_catch.HasCaught());
5480    CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5481  }
5482
5483  {
5484    // Test nested try-catch with a JavaScript throw in the end.
5485    v8::TryCatch try_catch;
5486    TryCatchNested2Helper(5);
5487    CHECK(try_catch.HasCaught());
5488    CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5489  }
5490}
5491
5492
5493void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5494  CHECK(try_catch->HasCaught());
5495  Handle<Message> message = try_catch->Message();
5496  Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5497  CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5498  CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5499                     "Uncaught Error: a"));
5500  CHECK_EQ(1, message->GetLineNumber());
5501  CHECK_EQ(6, message->GetStartColumn());
5502}
5503
5504
5505void TryCatchMixedNestingHelper(
5506    const v8::FunctionCallbackInfo<v8::Value>& args) {
5507  ApiTestFuzzer::Fuzz();
5508  v8::TryCatch try_catch;
5509  CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5510  CHECK(try_catch.HasCaught());
5511  TryCatchMixedNestingCheck(&try_catch);
5512  try_catch.ReThrow();
5513}
5514
5515
5516// This test ensures that an outer TryCatch in the following situation:
5517//   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5518// does not clobber the Message object generated for the inner TryCatch.
5519// This exercises the ability of TryCatch.ReThrow() to restore the
5520// inner pending Message before throwing the exception again.
5521TEST(TryCatchMixedNesting) {
5522  v8::Isolate* isolate = CcTest::isolate();
5523  v8::HandleScope scope(isolate);
5524  v8::V8::Initialize();
5525  v8::TryCatch try_catch;
5526  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5527  templ->Set(v8_str("TryCatchMixedNestingHelper"),
5528             v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5529  LocalContext context(0, templ);
5530  CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5531  TryCatchMixedNestingCheck(&try_catch);
5532}
5533
5534
5535void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5536  ApiTestFuzzer::Fuzz();
5537  v8::TryCatch try_catch;
5538  args.GetIsolate()->ThrowException(v8_str("boom"));
5539  CHECK(try_catch.HasCaught());
5540}
5541
5542
5543TEST(TryCatchNative) {
5544  v8::Isolate* isolate = CcTest::isolate();
5545  v8::HandleScope scope(isolate);
5546  v8::V8::Initialize();
5547  v8::TryCatch try_catch;
5548  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5549  templ->Set(v8_str("TryCatchNativeHelper"),
5550             v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5551  LocalContext context(0, templ);
5552  CompileRun("TryCatchNativeHelper();");
5553  CHECK(!try_catch.HasCaught());
5554}
5555
5556
5557void TryCatchNativeResetHelper(
5558    const v8::FunctionCallbackInfo<v8::Value>& args) {
5559  ApiTestFuzzer::Fuzz();
5560  v8::TryCatch try_catch;
5561  args.GetIsolate()->ThrowException(v8_str("boom"));
5562  CHECK(try_catch.HasCaught());
5563  try_catch.Reset();
5564  CHECK(!try_catch.HasCaught());
5565}
5566
5567
5568TEST(TryCatchNativeReset) {
5569  v8::Isolate* isolate = CcTest::isolate();
5570  v8::HandleScope scope(isolate);
5571  v8::V8::Initialize();
5572  v8::TryCatch try_catch;
5573  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5574  templ->Set(v8_str("TryCatchNativeResetHelper"),
5575             v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5576  LocalContext context(0, templ);
5577  CompileRun("TryCatchNativeResetHelper();");
5578  CHECK(!try_catch.HasCaught());
5579}
5580
5581
5582THREADED_TEST(Equality) {
5583  LocalContext context;
5584  v8::Isolate* isolate = context->GetIsolate();
5585  v8::HandleScope scope(context->GetIsolate());
5586  // Check that equality works at all before relying on CHECK_EQ
5587  CHECK(v8_str("a")->Equals(v8_str("a")));
5588  CHECK(!v8_str("a")->Equals(v8_str("b")));
5589
5590  CHECK_EQ(v8_str("a"), v8_str("a"));
5591  CHECK_NE(v8_str("a"), v8_str("b"));
5592  CHECK_EQ(v8_num(1), v8_num(1));
5593  CHECK_EQ(v8_num(1.00), v8_num(1));
5594  CHECK_NE(v8_num(1), v8_num(2));
5595
5596  // Assume String is not internalized.
5597  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5598  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5599  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5600  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5601  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5602  CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5603  Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
5604  CHECK(!not_a_number->StrictEquals(not_a_number));
5605  CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5606  CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5607
5608  v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5609  v8::Persistent<v8::Object> alias(isolate, obj);
5610  CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5611  alias.Reset();
5612
5613  CHECK(v8_str("a")->SameValue(v8_str("a")));
5614  CHECK(!v8_str("a")->SameValue(v8_str("b")));
5615  CHECK(!v8_str("5")->SameValue(v8_num(5)));
5616  CHECK(v8_num(1)->SameValue(v8_num(1)));
5617  CHECK(!v8_num(1)->SameValue(v8_num(2)));
5618  CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5619  CHECK(not_a_number->SameValue(not_a_number));
5620  CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5621  CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5622}
5623
5624
5625THREADED_TEST(MultiRun) {
5626  LocalContext context;
5627  v8::HandleScope scope(context->GetIsolate());
5628  Local<Script> script = v8_compile("x");
5629  for (int i = 0; i < 10; i++)
5630    script->Run();
5631}
5632
5633
5634static void GetXValue(Local<String> name,
5635                      const v8::PropertyCallbackInfo<v8::Value>& info) {
5636  ApiTestFuzzer::Fuzz();
5637  CHECK_EQ(info.Data(), v8_str("donut"));
5638  CHECK_EQ(name, v8_str("x"));
5639  info.GetReturnValue().Set(name);
5640}
5641
5642
5643THREADED_TEST(SimplePropertyRead) {
5644  LocalContext context;
5645  v8::Isolate* isolate = context->GetIsolate();
5646  v8::HandleScope scope(isolate);
5647  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5648  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5649  context->Global()->Set(v8_str("obj"), templ->NewInstance());
5650  Local<Script> script = v8_compile("obj.x");
5651  for (int i = 0; i < 10; i++) {
5652    Local<Value> result = script->Run();
5653    CHECK_EQ(result, v8_str("x"));
5654  }
5655}
5656
5657
5658THREADED_TEST(DefinePropertyOnAPIAccessor) {
5659  LocalContext context;
5660  v8::Isolate* isolate = context->GetIsolate();
5661  v8::HandleScope scope(isolate);
5662  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5663  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5664  context->Global()->Set(v8_str("obj"), templ->NewInstance());
5665
5666  // Uses getOwnPropertyDescriptor to check the configurable status
5667  Local<Script> script_desc = v8_compile(
5668      "var prop = Object.getOwnPropertyDescriptor( "
5669      "obj, 'x');"
5670      "prop.configurable;");
5671  Local<Value> result = script_desc->Run();
5672  CHECK_EQ(result->BooleanValue(), true);
5673
5674  // Redefine get - but still configurable
5675  Local<Script> script_define = v8_compile(
5676      "var desc = { get: function(){return 42; },"
5677      "            configurable: true };"
5678      "Object.defineProperty(obj, 'x', desc);"
5679      "obj.x");
5680  result = script_define->Run();
5681  CHECK_EQ(result, v8_num(42));
5682
5683  // Check that the accessor is still configurable
5684  result = script_desc->Run();
5685  CHECK_EQ(result->BooleanValue(), true);
5686
5687  // Redefine to a non-configurable
5688  script_define = v8_compile(
5689      "var desc = { get: function(){return 43; },"
5690      "             configurable: false };"
5691      "Object.defineProperty(obj, 'x', desc);"
5692      "obj.x");
5693  result = script_define->Run();
5694  CHECK_EQ(result, v8_num(43));
5695  result = script_desc->Run();
5696  CHECK_EQ(result->BooleanValue(), false);
5697
5698  // Make sure that it is not possible to redefine again
5699  v8::TryCatch try_catch;
5700  result = script_define->Run();
5701  CHECK(try_catch.HasCaught());
5702  String::Utf8Value exception_value(try_catch.Exception());
5703  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5704}
5705
5706
5707THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5708  v8::Isolate* isolate = CcTest::isolate();
5709  v8::HandleScope scope(isolate);
5710  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5711  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5712  LocalContext context;
5713  context->Global()->Set(v8_str("obj"), templ->NewInstance());
5714
5715  Local<Script> script_desc = v8_compile(
5716      "var prop ="
5717      "Object.getOwnPropertyDescriptor( "
5718      "obj, 'x');"
5719      "prop.configurable;");
5720  Local<Value> result = script_desc->Run();
5721  CHECK_EQ(result->BooleanValue(), true);
5722
5723  Local<Script> script_define = v8_compile(
5724      "var desc = {get: function(){return 42; },"
5725      "            configurable: true };"
5726      "Object.defineProperty(obj, 'x', desc);"
5727      "obj.x");
5728  result = script_define->Run();
5729  CHECK_EQ(result, v8_num(42));
5730
5731
5732  result = script_desc->Run();
5733  CHECK_EQ(result->BooleanValue(), true);
5734
5735
5736  script_define = v8_compile(
5737      "var desc = {get: function(){return 43; },"
5738      "            configurable: false };"
5739      "Object.defineProperty(obj, 'x', desc);"
5740      "obj.x");
5741  result = script_define->Run();
5742  CHECK_EQ(result, v8_num(43));
5743  result = script_desc->Run();
5744
5745  CHECK_EQ(result->BooleanValue(), false);
5746
5747  v8::TryCatch try_catch;
5748  result = script_define->Run();
5749  CHECK(try_catch.HasCaught());
5750  String::Utf8Value exception_value(try_catch.Exception());
5751  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5752}
5753
5754
5755static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5756                                                char const* name) {
5757  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5758}
5759
5760
5761THREADED_TEST(DefineAPIAccessorOnObject) {
5762  v8::Isolate* isolate = CcTest::isolate();
5763  v8::HandleScope scope(isolate);
5764  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5765  LocalContext context;
5766
5767  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5768  CompileRun("var obj2 = {};");
5769
5770  CHECK(CompileRun("obj1.x")->IsUndefined());
5771  CHECK(CompileRun("obj2.x")->IsUndefined());
5772
5773  CHECK(GetGlobalProperty(&context, "obj1")->
5774      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5775
5776  ExpectString("obj1.x", "x");
5777  CHECK(CompileRun("obj2.x")->IsUndefined());
5778
5779  CHECK(GetGlobalProperty(&context, "obj2")->
5780      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5781
5782  ExpectString("obj1.x", "x");
5783  ExpectString("obj2.x", "x");
5784
5785  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5786  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5787
5788  CompileRun("Object.defineProperty(obj1, 'x',"
5789             "{ get: function() { return 'y'; }, configurable: true })");
5790
5791  ExpectString("obj1.x", "y");
5792  ExpectString("obj2.x", "x");
5793
5794  CompileRun("Object.defineProperty(obj2, 'x',"
5795             "{ get: function() { return 'y'; }, configurable: true })");
5796
5797  ExpectString("obj1.x", "y");
5798  ExpectString("obj2.x", "y");
5799
5800  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5801  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5802
5803  CHECK(GetGlobalProperty(&context, "obj1")->
5804      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5805  CHECK(GetGlobalProperty(&context, "obj2")->
5806      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5807
5808  ExpectString("obj1.x", "x");
5809  ExpectString("obj2.x", "x");
5810
5811  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5812  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5813
5814  // Define getters/setters, but now make them not configurable.
5815  CompileRun("Object.defineProperty(obj1, 'x',"
5816             "{ get: function() { return 'z'; }, configurable: false })");
5817  CompileRun("Object.defineProperty(obj2, 'x',"
5818             "{ get: function() { return 'z'; }, configurable: false })");
5819
5820  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5821  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5822
5823  ExpectString("obj1.x", "z");
5824  ExpectString("obj2.x", "z");
5825
5826  CHECK(!GetGlobalProperty(&context, "obj1")->
5827      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5828  CHECK(!GetGlobalProperty(&context, "obj2")->
5829      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5830
5831  ExpectString("obj1.x", "z");
5832  ExpectString("obj2.x", "z");
5833}
5834
5835
5836THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5837  v8::Isolate* isolate = CcTest::isolate();
5838  v8::HandleScope scope(isolate);
5839  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5840  LocalContext context;
5841
5842  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5843  CompileRun("var obj2 = {};");
5844
5845  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5846        v8_str("x"),
5847        GetXValue, NULL,
5848        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5849  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5850        v8_str("x"),
5851        GetXValue, NULL,
5852        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5853
5854  ExpectString("obj1.x", "x");
5855  ExpectString("obj2.x", "x");
5856
5857  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5858  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5859
5860  CHECK(!GetGlobalProperty(&context, "obj1")->
5861      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5862  CHECK(!GetGlobalProperty(&context, "obj2")->
5863      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5864
5865  {
5866    v8::TryCatch try_catch;
5867    CompileRun("Object.defineProperty(obj1, 'x',"
5868        "{get: function() { return 'func'; }})");
5869    CHECK(try_catch.HasCaught());
5870    String::Utf8Value exception_value(try_catch.Exception());
5871    CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5872  }
5873  {
5874    v8::TryCatch try_catch;
5875    CompileRun("Object.defineProperty(obj2, 'x',"
5876        "{get: function() { return 'func'; }})");
5877    CHECK(try_catch.HasCaught());
5878    String::Utf8Value exception_value(try_catch.Exception());
5879    CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5880  }
5881}
5882
5883
5884static void Get239Value(Local<String> name,
5885                        const v8::PropertyCallbackInfo<v8::Value>& info) {
5886  ApiTestFuzzer::Fuzz();
5887  CHECK_EQ(info.Data(), v8_str("donut"));
5888  CHECK_EQ(name, v8_str("239"));
5889  info.GetReturnValue().Set(name);
5890}
5891
5892
5893THREADED_TEST(ElementAPIAccessor) {
5894  v8::Isolate* isolate = CcTest::isolate();
5895  v8::HandleScope scope(isolate);
5896  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5897  LocalContext context;
5898
5899  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5900  CompileRun("var obj2 = {};");
5901
5902  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5903        v8_str("239"),
5904        Get239Value, NULL,
5905        v8_str("donut")));
5906  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5907        v8_str("239"),
5908        Get239Value, NULL,
5909        v8_str("donut")));
5910
5911  ExpectString("obj1[239]", "239");
5912  ExpectString("obj2[239]", "239");
5913  ExpectString("obj1['239']", "239");
5914  ExpectString("obj2['239']", "239");
5915}
5916
5917
5918v8::Persistent<Value> xValue;
5919
5920
5921static void SetXValue(Local<String> name,
5922                      Local<Value> value,
5923                      const v8::PropertyCallbackInfo<void>& info) {
5924  CHECK_EQ(value, v8_num(4));
5925  CHECK_EQ(info.Data(), v8_str("donut"));
5926  CHECK_EQ(name, v8_str("x"));
5927  CHECK(xValue.IsEmpty());
5928  xValue.Reset(info.GetIsolate(), value);
5929}
5930
5931
5932THREADED_TEST(SimplePropertyWrite) {
5933  v8::Isolate* isolate = CcTest::isolate();
5934  v8::HandleScope scope(isolate);
5935  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5936  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5937  LocalContext context;
5938  context->Global()->Set(v8_str("obj"), templ->NewInstance());
5939  Local<Script> script = v8_compile("obj.x = 4");
5940  for (int i = 0; i < 10; i++) {
5941    CHECK(xValue.IsEmpty());
5942    script->Run();
5943    CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5944    xValue.Reset();
5945  }
5946}
5947
5948
5949THREADED_TEST(SetterOnly) {
5950  v8::Isolate* isolate = CcTest::isolate();
5951  v8::HandleScope scope(isolate);
5952  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5953  templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5954  LocalContext context;
5955  context->Global()->Set(v8_str("obj"), templ->NewInstance());
5956  Local<Script> script = v8_compile("obj.x = 4; obj.x");
5957  for (int i = 0; i < 10; i++) {
5958    CHECK(xValue.IsEmpty());
5959    script->Run();
5960    CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5961    xValue.Reset();
5962  }
5963}
5964
5965
5966THREADED_TEST(NoAccessors) {
5967  v8::Isolate* isolate = CcTest::isolate();
5968  v8::HandleScope scope(isolate);
5969  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5970  templ->SetAccessor(v8_str("x"),
5971                     static_cast<v8::AccessorGetterCallback>(NULL),
5972                     NULL,
5973                     v8_str("donut"));
5974  LocalContext context;
5975  context->Global()->Set(v8_str("obj"), templ->NewInstance());
5976  Local<Script> script = v8_compile("obj.x = 4; obj.x");
5977  for (int i = 0; i < 10; i++) {
5978    script->Run();
5979  }
5980}
5981
5982
5983static void XPropertyGetter(Local<String> property,
5984                            const v8::PropertyCallbackInfo<v8::Value>& info) {
5985  ApiTestFuzzer::Fuzz();
5986  CHECK(info.Data()->IsUndefined());
5987  info.GetReturnValue().Set(property);
5988}
5989
5990
5991THREADED_TEST(NamedInterceptorPropertyRead) {
5992  v8::Isolate* isolate = CcTest::isolate();
5993  v8::HandleScope scope(isolate);
5994  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5995  templ->SetNamedPropertyHandler(XPropertyGetter);
5996  LocalContext context;
5997  context->Global()->Set(v8_str("obj"), templ->NewInstance());
5998  Local<Script> script = v8_compile("obj.x");
5999  for (int i = 0; i < 10; i++) {
6000    Local<Value> result = script->Run();
6001    CHECK_EQ(result, v8_str("x"));
6002  }
6003}
6004
6005
6006THREADED_TEST(NamedInterceptorDictionaryIC) {
6007  v8::Isolate* isolate = CcTest::isolate();
6008  v8::HandleScope scope(isolate);
6009  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6010  templ->SetNamedPropertyHandler(XPropertyGetter);
6011  LocalContext context;
6012  // Create an object with a named interceptor.
6013  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
6014  Local<Script> script = v8_compile("interceptor_obj.x");
6015  for (int i = 0; i < 10; i++) {
6016    Local<Value> result = script->Run();
6017    CHECK_EQ(result, v8_str("x"));
6018  }
6019  // Create a slow case object and a function accessing a property in
6020  // that slow case object (with dictionary probing in generated
6021  // code). Then force object with a named interceptor into slow-case,
6022  // pass it to the function, and check that the interceptor is called
6023  // instead of accessing the local property.
6024  Local<Value> result =
6025      CompileRun("function get_x(o) { return o.x; };"
6026                 "var obj = { x : 42, y : 0 };"
6027                 "delete obj.y;"
6028                 "for (var i = 0; i < 10; i++) get_x(obj);"
6029                 "interceptor_obj.x = 42;"
6030                 "interceptor_obj.y = 10;"
6031                 "delete interceptor_obj.y;"
6032                 "get_x(interceptor_obj)");
6033  CHECK_EQ(result, v8_str("x"));
6034}
6035
6036
6037THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
6038  v8::Isolate* isolate = CcTest::isolate();
6039  v8::HandleScope scope(isolate);
6040  v8::Local<Context> context1 = Context::New(isolate);
6041
6042  context1->Enter();
6043  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6044  templ->SetNamedPropertyHandler(XPropertyGetter);
6045  // Create an object with a named interceptor.
6046  v8::Local<v8::Object> object = templ->NewInstance();
6047  context1->Global()->Set(v8_str("interceptor_obj"), object);
6048
6049  // Force the object into the slow case.
6050  CompileRun("interceptor_obj.y = 0;"
6051             "delete interceptor_obj.y;");
6052  context1->Exit();
6053
6054  {
6055    // Introduce the object into a different context.
6056    // Repeat named loads to exercise ICs.
6057    LocalContext context2;
6058    context2->Global()->Set(v8_str("interceptor_obj"), object);
6059    Local<Value> result =
6060      CompileRun("function get_x(o) { return o.x; }"
6061                 "interceptor_obj.x = 42;"
6062                 "for (var i=0; i != 10; i++) {"
6063                 "  get_x(interceptor_obj);"
6064                 "}"
6065                 "get_x(interceptor_obj)");
6066    // Check that the interceptor was actually invoked.
6067    CHECK_EQ(result, v8_str("x"));
6068  }
6069
6070  // Return to the original context and force some object to the slow case
6071  // to cause the NormalizedMapCache to verify.
6072  context1->Enter();
6073  CompileRun("var obj = { x : 0 }; delete obj.x;");
6074  context1->Exit();
6075}
6076
6077
6078static void SetXOnPrototypeGetter(
6079    Local<String> property,
6080    const v8::PropertyCallbackInfo<v8::Value>& info) {
6081  // Set x on the prototype object and do not handle the get request.
6082  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
6083  proto.As<v8::Object>()->Set(v8_str("x"),
6084                              v8::Integer::New(info.GetIsolate(), 23));
6085}
6086
6087
6088// This is a regression test for http://crbug.com/20104. Map
6089// transitions should not interfere with post interceptor lookup.
6090THREADED_TEST(NamedInterceptorMapTransitionRead) {
6091  v8::Isolate* isolate = CcTest::isolate();
6092  v8::HandleScope scope(isolate);
6093  Local<v8::FunctionTemplate> function_template =
6094      v8::FunctionTemplate::New(isolate);
6095  Local<v8::ObjectTemplate> instance_template
6096      = function_template->InstanceTemplate();
6097  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
6098  LocalContext context;
6099  context->Global()->Set(v8_str("F"), function_template->GetFunction());
6100  // Create an instance of F and introduce a map transition for x.
6101  CompileRun("var o = new F(); o.x = 23;");
6102  // Create an instance of F and invoke the getter. The result should be 23.
6103  Local<Value> result = CompileRun("o = new F(); o.x");
6104  CHECK_EQ(result->Int32Value(), 23);
6105}
6106
6107
6108static void IndexedPropertyGetter(
6109    uint32_t index,
6110    const v8::PropertyCallbackInfo<v8::Value>& info) {
6111  ApiTestFuzzer::Fuzz();
6112  if (index == 37) {
6113    info.GetReturnValue().Set(v8_num(625));
6114  }
6115}
6116
6117
6118static void IndexedPropertySetter(
6119    uint32_t index,
6120    Local<Value> value,
6121    const v8::PropertyCallbackInfo<v8::Value>& info) {
6122  ApiTestFuzzer::Fuzz();
6123  if (index == 39) {
6124    info.GetReturnValue().Set(value);
6125  }
6126}
6127
6128
6129THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
6130  v8::Isolate* isolate = CcTest::isolate();
6131  v8::HandleScope scope(isolate);
6132  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6133  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
6134                                   IndexedPropertySetter);
6135  LocalContext context;
6136  context->Global()->Set(v8_str("obj"), templ->NewInstance());
6137  Local<Script> getter_script = v8_compile(
6138      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6139  Local<Script> setter_script = v8_compile(
6140      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6141      "obj[17] = 23;"
6142      "obj.foo;");
6143  Local<Script> interceptor_setter_script = v8_compile(
6144      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6145      "obj[39] = 47;"
6146      "obj.foo;");  // This setter should not run, due to the interceptor.
6147  Local<Script> interceptor_getter_script = v8_compile(
6148      "obj[37];");
6149  Local<Value> result = getter_script->Run();
6150  CHECK_EQ(v8_num(5), result);
6151  result = setter_script->Run();
6152  CHECK_EQ(v8_num(23), result);
6153  result = interceptor_setter_script->Run();
6154  CHECK_EQ(v8_num(23), result);
6155  result = interceptor_getter_script->Run();
6156  CHECK_EQ(v8_num(625), result);
6157}
6158
6159
6160static void UnboxedDoubleIndexedPropertyGetter(
6161    uint32_t index,
6162    const v8::PropertyCallbackInfo<v8::Value>& info) {
6163  ApiTestFuzzer::Fuzz();
6164  if (index < 25) {
6165    info.GetReturnValue().Set(v8_num(index));
6166  }
6167}
6168
6169
6170static void UnboxedDoubleIndexedPropertySetter(
6171    uint32_t index,
6172    Local<Value> value,
6173    const v8::PropertyCallbackInfo<v8::Value>& info) {
6174  ApiTestFuzzer::Fuzz();
6175  if (index < 25) {
6176    info.GetReturnValue().Set(v8_num(index));
6177  }
6178}
6179
6180
6181void UnboxedDoubleIndexedPropertyEnumerator(
6182    const v8::PropertyCallbackInfo<v8::Array>& info) {
6183  // Force the list of returned keys to be stored in a FastDoubleArray.
6184  Local<Script> indexed_property_names_script = v8_compile(
6185      "keys = new Array(); keys[125000] = 1;"
6186      "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6187      "keys.length = 25; keys;");
6188  Local<Value> result = indexed_property_names_script->Run();
6189  info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6190}
6191
6192
6193// Make sure that the the interceptor code in the runtime properly handles
6194// merging property name lists for double-array-backed arrays.
6195THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6196  v8::Isolate* isolate = CcTest::isolate();
6197  v8::HandleScope scope(isolate);
6198  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6199  templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6200                                   UnboxedDoubleIndexedPropertySetter,
6201                                   0,
6202                                   0,
6203                                   UnboxedDoubleIndexedPropertyEnumerator);
6204  LocalContext context;
6205  context->Global()->Set(v8_str("obj"), templ->NewInstance());
6206  // When obj is created, force it to be Stored in a FastDoubleArray.
6207  Local<Script> create_unboxed_double_script = v8_compile(
6208      "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6209      "key_count = 0; "
6210      "for (x in obj) {key_count++;};"
6211      "obj;");
6212  Local<Value> result = create_unboxed_double_script->Run();
6213  CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6214  Local<Script> key_count_check = v8_compile("key_count;");
6215  result = key_count_check->Run();
6216  CHECK_EQ(v8_num(40013), result);
6217}
6218
6219
6220void SloppyArgsIndexedPropertyEnumerator(
6221    const v8::PropertyCallbackInfo<v8::Array>& info) {
6222  // Force the list of returned keys to be stored in a Arguments object.
6223  Local<Script> indexed_property_names_script = v8_compile(
6224      "function f(w,x) {"
6225      " return arguments;"
6226      "}"
6227      "keys = f(0, 1, 2, 3);"
6228      "keys;");
6229  Local<Object> result =
6230      Local<Object>::Cast(indexed_property_names_script->Run());
6231  // Have to populate the handle manually, as it's not Cast-able.
6232  i::Handle<i::JSObject> o =
6233      v8::Utils::OpenHandle<Object, i::JSObject>(result);
6234  i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6235  info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6236}
6237
6238
6239static void SloppyIndexedPropertyGetter(
6240    uint32_t index,
6241    const v8::PropertyCallbackInfo<v8::Value>& info) {
6242  ApiTestFuzzer::Fuzz();
6243  if (index < 4) {
6244    info.GetReturnValue().Set(v8_num(index));
6245  }
6246}
6247
6248
6249// Make sure that the the interceptor code in the runtime properly handles
6250// merging property name lists for non-string arguments arrays.
6251THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6252  v8::Isolate* isolate = CcTest::isolate();
6253  v8::HandleScope scope(isolate);
6254  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6255  templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6256                                   0,
6257                                   0,
6258                                   0,
6259                                   SloppyArgsIndexedPropertyEnumerator);
6260  LocalContext context;
6261  context->Global()->Set(v8_str("obj"), templ->NewInstance());
6262  Local<Script> create_args_script = v8_compile(
6263      "var key_count = 0;"
6264      "for (x in obj) {key_count++;} key_count;");
6265  Local<Value> result = create_args_script->Run();
6266  CHECK_EQ(v8_num(4), result);
6267}
6268
6269
6270static void IdentityIndexedPropertyGetter(
6271    uint32_t index,
6272    const v8::PropertyCallbackInfo<v8::Value>& info) {
6273  info.GetReturnValue().Set(index);
6274}
6275
6276
6277THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6278  v8::Isolate* isolate = CcTest::isolate();
6279  v8::HandleScope scope(isolate);
6280  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6281  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6282
6283  LocalContext context;
6284  context->Global()->Set(v8_str("obj"), templ->NewInstance());
6285
6286  // Check fast object case.
6287  const char* fast_case_code =
6288      "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6289  ExpectString(fast_case_code, "0");
6290
6291  // Check slow case.
6292  const char* slow_case_code =
6293      "obj.x = 1; delete obj.x;"
6294      "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6295  ExpectString(slow_case_code, "1");
6296}
6297
6298
6299THREADED_TEST(IndexedInterceptorWithNoSetter) {
6300  v8::Isolate* isolate = CcTest::isolate();
6301  v8::HandleScope scope(isolate);
6302  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6303  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6304
6305  LocalContext context;
6306  context->Global()->Set(v8_str("obj"), templ->NewInstance());
6307
6308  const char* code =
6309      "try {"
6310      "  obj[0] = 239;"
6311      "  for (var i = 0; i < 100; i++) {"
6312      "    var v = obj[0];"
6313      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6314      "  }"
6315      "  'PASSED'"
6316      "} catch(e) {"
6317      "  e"
6318      "}";
6319  ExpectString(code, "PASSED");
6320}
6321
6322
6323THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6324  v8::Isolate* isolate = CcTest::isolate();
6325  v8::HandleScope scope(isolate);
6326  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6327  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6328
6329  LocalContext context;
6330  Local<v8::Object> obj = templ->NewInstance();
6331  obj->TurnOnAccessCheck();
6332  context->Global()->Set(v8_str("obj"), obj);
6333
6334  const char* code =
6335      "var result = 'PASSED';"
6336      "for (var i = 0; i < 100; i++) {"
6337      "  try {"
6338      "    var v = obj[0];"
6339      "    result = 'Wrong value ' + v + ' at iteration ' + i;"
6340      "    break;"
6341      "  } catch (e) {"
6342      "    /* pass */"
6343      "  }"
6344      "}"
6345      "result";
6346  ExpectString(code, "PASSED");
6347}
6348
6349
6350THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6351  i::FLAG_allow_natives_syntax = true;
6352  v8::Isolate* isolate = CcTest::isolate();
6353  v8::HandleScope scope(isolate);
6354  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6355  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6356
6357  LocalContext context;
6358  Local<v8::Object> obj = templ->NewInstance();
6359  context->Global()->Set(v8_str("obj"), obj);
6360
6361  const char* code =
6362      "var result = 'PASSED';"
6363      "for (var i = 0; i < 100; i++) {"
6364      "  var expected = i;"
6365      "  if (i == 5) {"
6366      "    %EnableAccessChecks(obj);"
6367      "  }"
6368      "  try {"
6369      "    var v = obj[i];"
6370      "    if (i == 5) {"
6371      "      result = 'Should not have reached this!';"
6372      "      break;"
6373      "    } else if (v != expected) {"
6374      "      result = 'Wrong value ' + v + ' at iteration ' + i;"
6375      "      break;"
6376      "    }"
6377      "  } catch (e) {"
6378      "    if (i != 5) {"
6379      "      result = e;"
6380      "    }"
6381      "  }"
6382      "  if (i == 5) %DisableAccessChecks(obj);"
6383      "}"
6384      "result";
6385  ExpectString(code, "PASSED");
6386}
6387
6388
6389THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6390  v8::Isolate* isolate = CcTest::isolate();
6391  v8::HandleScope scope(isolate);
6392  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6393  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6394
6395  LocalContext context;
6396  Local<v8::Object> obj = templ->NewInstance();
6397  context->Global()->Set(v8_str("obj"), obj);
6398
6399  const char* code =
6400      "try {"
6401      "  for (var i = 0; i < 100; i++) {"
6402      "    var v = obj[i];"
6403      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6404      "  }"
6405      "  'PASSED'"
6406      "} catch(e) {"
6407      "  e"
6408      "}";
6409  ExpectString(code, "PASSED");
6410}
6411
6412
6413THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6414  v8::Isolate* isolate = CcTest::isolate();
6415  v8::HandleScope scope(isolate);
6416  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6417  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6418
6419  LocalContext context;
6420  Local<v8::Object> obj = templ->NewInstance();
6421  context->Global()->Set(v8_str("obj"), obj);
6422
6423  const char* code =
6424      "try {"
6425      "  for (var i = 0; i < 100; i++) {"
6426      "    var expected = i;"
6427      "    var key = i;"
6428      "    if (i == 25) {"
6429      "       key = -1;"
6430      "       expected = undefined;"
6431      "    }"
6432      "    if (i == 50) {"
6433      "       /* probe minimal Smi number on 32-bit platforms */"
6434      "       key = -(1 << 30);"
6435      "       expected = undefined;"
6436      "    }"
6437      "    if (i == 75) {"
6438      "       /* probe minimal Smi number on 64-bit platforms */"
6439      "       key = 1 << 31;"
6440      "       expected = undefined;"
6441      "    }"
6442      "    var v = obj[key];"
6443      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6444      "  }"
6445      "  'PASSED'"
6446      "} catch(e) {"
6447      "  e"
6448      "}";
6449  ExpectString(code, "PASSED");
6450}
6451
6452
6453THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6454  v8::Isolate* isolate = CcTest::isolate();
6455  v8::HandleScope scope(isolate);
6456  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6457  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6458
6459  LocalContext context;
6460  Local<v8::Object> obj = templ->NewInstance();
6461  context->Global()->Set(v8_str("obj"), obj);
6462
6463  const char* code =
6464      "try {"
6465      "  for (var i = 0; i < 100; i++) {"
6466      "    var expected = i;"
6467      "    var key = i;"
6468      "    if (i == 50) {"
6469      "       key = 'foobar';"
6470      "       expected = undefined;"
6471      "    }"
6472      "    var v = obj[key];"
6473      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6474      "  }"
6475      "  'PASSED'"
6476      "} catch(e) {"
6477      "  e"
6478      "}";
6479  ExpectString(code, "PASSED");
6480}
6481
6482
6483THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6484  v8::Isolate* isolate = CcTest::isolate();
6485  v8::HandleScope scope(isolate);
6486  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6487  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6488
6489  LocalContext context;
6490  Local<v8::Object> obj = templ->NewInstance();
6491  context->Global()->Set(v8_str("obj"), obj);
6492
6493  const char* code =
6494      "var original = obj;"
6495      "try {"
6496      "  for (var i = 0; i < 100; i++) {"
6497      "    var expected = i;"
6498      "    if (i == 50) {"
6499      "       obj = {50: 'foobar'};"
6500      "       expected = 'foobar';"
6501      "    }"
6502      "    var v = obj[i];"
6503      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6504      "    if (i == 50) obj = original;"
6505      "  }"
6506      "  'PASSED'"
6507      "} catch(e) {"
6508      "  e"
6509      "}";
6510  ExpectString(code, "PASSED");
6511}
6512
6513
6514THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6515  v8::Isolate* isolate = CcTest::isolate();
6516  v8::HandleScope scope(isolate);
6517  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6518  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6519
6520  LocalContext context;
6521  Local<v8::Object> obj = templ->NewInstance();
6522  context->Global()->Set(v8_str("obj"), obj);
6523
6524  const char* code =
6525      "var original = obj;"
6526      "try {"
6527      "  for (var i = 0; i < 100; i++) {"
6528      "    var expected = i;"
6529      "    if (i == 5) {"
6530      "       obj = 239;"
6531      "       expected = undefined;"
6532      "    }"
6533      "    var v = obj[i];"
6534      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6535      "    if (i == 5) obj = original;"
6536      "  }"
6537      "  'PASSED'"
6538      "} catch(e) {"
6539      "  e"
6540      "}";
6541  ExpectString(code, "PASSED");
6542}
6543
6544
6545THREADED_TEST(IndexedInterceptorOnProto) {
6546  v8::Isolate* isolate = CcTest::isolate();
6547  v8::HandleScope scope(isolate);
6548  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6549  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6550
6551  LocalContext context;
6552  Local<v8::Object> obj = templ->NewInstance();
6553  context->Global()->Set(v8_str("obj"), obj);
6554
6555  const char* code =
6556      "var o = {__proto__: obj};"
6557      "try {"
6558      "  for (var i = 0; i < 100; i++) {"
6559      "    var v = o[i];"
6560      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6561      "  }"
6562      "  'PASSED'"
6563      "} catch(e) {"
6564      "  e"
6565      "}";
6566  ExpectString(code, "PASSED");
6567}
6568
6569
6570THREADED_TEST(MultiContexts) {
6571  v8::Isolate* isolate = CcTest::isolate();
6572  v8::HandleScope scope(isolate);
6573  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6574  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6575                                                        DummyCallHandler));
6576
6577  Local<String> password = v8_str("Password");
6578
6579  // Create an environment
6580  LocalContext context0(0, templ);
6581  context0->SetSecurityToken(password);
6582  v8::Handle<v8::Object> global0 = context0->Global();
6583  global0->Set(v8_str("custom"), v8_num(1234));
6584  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6585
6586  // Create an independent environment
6587  LocalContext context1(0, templ);
6588  context1->SetSecurityToken(password);
6589  v8::Handle<v8::Object> global1 = context1->Global();
6590  global1->Set(v8_str("custom"), v8_num(1234));
6591  CHECK_NE(global0, global1);
6592  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6593  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6594
6595  // Now create a new context with the old global
6596  LocalContext context2(0, templ, global1);
6597  context2->SetSecurityToken(password);
6598  v8::Handle<v8::Object> global2 = context2->Global();
6599  CHECK_EQ(global1, global2);
6600  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6601  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6602}
6603
6604
6605THREADED_TEST(FunctionPrototypeAcrossContexts) {
6606  // Make sure that functions created by cloning boilerplates cannot
6607  // communicate through their __proto__ field.
6608
6609  v8::HandleScope scope(CcTest::isolate());
6610
6611  LocalContext env0;
6612  v8::Handle<v8::Object> global0 =
6613      env0->Global();
6614  v8::Handle<v8::Object> object0 =
6615      global0->Get(v8_str("Object")).As<v8::Object>();
6616  v8::Handle<v8::Object> tostring0 =
6617      object0->Get(v8_str("toString")).As<v8::Object>();
6618  v8::Handle<v8::Object> proto0 =
6619      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6620  proto0->Set(v8_str("custom"), v8_num(1234));
6621
6622  LocalContext env1;
6623  v8::Handle<v8::Object> global1 =
6624      env1->Global();
6625  v8::Handle<v8::Object> object1 =
6626      global1->Get(v8_str("Object")).As<v8::Object>();
6627  v8::Handle<v8::Object> tostring1 =
6628      object1->Get(v8_str("toString")).As<v8::Object>();
6629  v8::Handle<v8::Object> proto1 =
6630      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6631  CHECK(!proto1->Has(v8_str("custom")));
6632}
6633
6634
6635THREADED_TEST(Regress892105) {
6636  // Make sure that object and array literals created by cloning
6637  // boilerplates cannot communicate through their __proto__
6638  // field. This is rather difficult to check, but we try to add stuff
6639  // to Object.prototype and Array.prototype and create a new
6640  // environment. This should succeed.
6641
6642  v8::HandleScope scope(CcTest::isolate());
6643
6644  Local<String> source = v8_str("Object.prototype.obj = 1234;"
6645                                "Array.prototype.arr = 4567;"
6646                                "8901");
6647
6648  LocalContext env0;
6649  Local<Script> script0 = v8_compile(source);
6650  CHECK_EQ(8901.0, script0->Run()->NumberValue());
6651
6652  LocalContext env1;
6653  Local<Script> script1 = v8_compile(source);
6654  CHECK_EQ(8901.0, script1->Run()->NumberValue());
6655}
6656
6657
6658THREADED_TEST(UndetectableObject) {
6659  LocalContext env;
6660  v8::HandleScope scope(env->GetIsolate());
6661
6662  Local<v8::FunctionTemplate> desc =
6663      v8::FunctionTemplate::New(env->GetIsolate());
6664  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6665
6666  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6667  env->Global()->Set(v8_str("undetectable"), obj);
6668
6669  ExpectString("undetectable.toString()", "[object Object]");
6670  ExpectString("typeof undetectable", "undefined");
6671  ExpectString("typeof(undetectable)", "undefined");
6672  ExpectBoolean("typeof undetectable == 'undefined'", true);
6673  ExpectBoolean("typeof undetectable == 'object'", false);
6674  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6675  ExpectBoolean("!undetectable", true);
6676
6677  ExpectObject("true&&undetectable", obj);
6678  ExpectBoolean("false&&undetectable", false);
6679  ExpectBoolean("true||undetectable", true);
6680  ExpectObject("false||undetectable", obj);
6681
6682  ExpectObject("undetectable&&true", obj);
6683  ExpectObject("undetectable&&false", obj);
6684  ExpectBoolean("undetectable||true", true);
6685  ExpectBoolean("undetectable||false", false);
6686
6687  ExpectBoolean("undetectable==null", true);
6688  ExpectBoolean("null==undetectable", true);
6689  ExpectBoolean("undetectable==undefined", true);
6690  ExpectBoolean("undefined==undetectable", true);
6691  ExpectBoolean("undetectable==undetectable", true);
6692
6693
6694  ExpectBoolean("undetectable===null", false);
6695  ExpectBoolean("null===undetectable", false);
6696  ExpectBoolean("undetectable===undefined", false);
6697  ExpectBoolean("undefined===undetectable", false);
6698  ExpectBoolean("undetectable===undetectable", true);
6699}
6700
6701
6702THREADED_TEST(VoidLiteral) {
6703  LocalContext env;
6704  v8::Isolate* isolate = env->GetIsolate();
6705  v8::HandleScope scope(isolate);
6706
6707  Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6708  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6709
6710  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6711  env->Global()->Set(v8_str("undetectable"), obj);
6712
6713  ExpectBoolean("undefined == void 0", true);
6714  ExpectBoolean("undetectable == void 0", true);
6715  ExpectBoolean("null == void 0", true);
6716  ExpectBoolean("undefined === void 0", true);
6717  ExpectBoolean("undetectable === void 0", false);
6718  ExpectBoolean("null === void 0", false);
6719
6720  ExpectBoolean("void 0 == undefined", true);
6721  ExpectBoolean("void 0 == undetectable", true);
6722  ExpectBoolean("void 0 == null", true);
6723  ExpectBoolean("void 0 === undefined", true);
6724  ExpectBoolean("void 0 === undetectable", false);
6725  ExpectBoolean("void 0 === null", false);
6726
6727  ExpectString("(function() {"
6728               "  try {"
6729               "    return x === void 0;"
6730               "  } catch(e) {"
6731               "    return e.toString();"
6732               "  }"
6733               "})()",
6734               "ReferenceError: x is not defined");
6735  ExpectString("(function() {"
6736               "  try {"
6737               "    return void 0 === x;"
6738               "  } catch(e) {"
6739               "    return e.toString();"
6740               "  }"
6741               "})()",
6742               "ReferenceError: x is not defined");
6743}
6744
6745
6746THREADED_TEST(ExtensibleOnUndetectable) {
6747  LocalContext env;
6748  v8::Isolate* isolate = env->GetIsolate();
6749  v8::HandleScope scope(isolate);
6750
6751  Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6752  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6753
6754  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6755  env->Global()->Set(v8_str("undetectable"), obj);
6756
6757  Local<String> source = v8_str("undetectable.x = 42;"
6758                                "undetectable.x");
6759
6760  Local<Script> script = v8_compile(source);
6761
6762  CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6763
6764  ExpectBoolean("Object.isExtensible(undetectable)", true);
6765
6766  source = v8_str("Object.preventExtensions(undetectable);");
6767  script = v8_compile(source);
6768  script->Run();
6769  ExpectBoolean("Object.isExtensible(undetectable)", false);
6770
6771  source = v8_str("undetectable.y = 2000;");
6772  script = v8_compile(source);
6773  script->Run();
6774  ExpectBoolean("undetectable.y == undefined", true);
6775}
6776
6777
6778
6779THREADED_TEST(UndetectableString) {
6780  LocalContext env;
6781  v8::HandleScope scope(env->GetIsolate());
6782
6783  Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6784                                          String::kUndetectableString);
6785  env->Global()->Set(v8_str("undetectable"), obj);
6786
6787  ExpectString("undetectable", "foo");
6788  ExpectString("typeof undetectable", "undefined");
6789  ExpectString("typeof(undetectable)", "undefined");
6790  ExpectBoolean("typeof undetectable == 'undefined'", true);
6791  ExpectBoolean("typeof undetectable == 'string'", false);
6792  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6793  ExpectBoolean("!undetectable", true);
6794
6795  ExpectObject("true&&undetectable", obj);
6796  ExpectBoolean("false&&undetectable", false);
6797  ExpectBoolean("true||undetectable", true);
6798  ExpectObject("false||undetectable", obj);
6799
6800  ExpectObject("undetectable&&true", obj);
6801  ExpectObject("undetectable&&false", obj);
6802  ExpectBoolean("undetectable||true", true);
6803  ExpectBoolean("undetectable||false", false);
6804
6805  ExpectBoolean("undetectable==null", true);
6806  ExpectBoolean("null==undetectable", true);
6807  ExpectBoolean("undetectable==undefined", true);
6808  ExpectBoolean("undefined==undetectable", true);
6809  ExpectBoolean("undetectable==undetectable", true);
6810
6811
6812  ExpectBoolean("undetectable===null", false);
6813  ExpectBoolean("null===undetectable", false);
6814  ExpectBoolean("undetectable===undefined", false);
6815  ExpectBoolean("undefined===undetectable", false);
6816  ExpectBoolean("undetectable===undetectable", true);
6817}
6818
6819
6820TEST(UndetectableOptimized) {
6821  i::FLAG_allow_natives_syntax = true;
6822  LocalContext env;
6823  v8::HandleScope scope(env->GetIsolate());
6824
6825  Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6826                                          String::kUndetectableString);
6827  env->Global()->Set(v8_str("undetectable"), obj);
6828  env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6829
6830  ExpectString(
6831      "function testBranch() {"
6832      "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
6833      "  if (%_IsUndetectableObject(detectable)) throw 2;"
6834      "}\n"
6835      "function testBool() {"
6836      "  var b1 = !%_IsUndetectableObject(undetectable);"
6837      "  var b2 = %_IsUndetectableObject(detectable);"
6838      "  if (b1) throw 3;"
6839      "  if (b2) throw 4;"
6840      "  return b1 == b2;"
6841      "}\n"
6842      "%OptimizeFunctionOnNextCall(testBranch);"
6843      "%OptimizeFunctionOnNextCall(testBool);"
6844      "for (var i = 0; i < 10; i++) {"
6845      "  testBranch();"
6846      "  testBool();"
6847      "}\n"
6848      "\"PASS\"",
6849      "PASS");
6850}
6851
6852
6853// The point of this test is type checking. We run it only so compilers
6854// don't complain about an unused function.
6855TEST(PersistentHandles) {
6856  LocalContext env;
6857  v8::Isolate* isolate = CcTest::isolate();
6858  v8::HandleScope scope(isolate);
6859  Local<String> str = v8_str("foo");
6860  v8::Persistent<String> p_str(isolate, str);
6861  p_str.Reset();
6862  Local<Script> scr = v8_compile("");
6863  v8::Persistent<Script> p_scr(isolate, scr);
6864  p_scr.Reset();
6865  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6866  v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6867  p_templ.Reset();
6868}
6869
6870
6871static void HandleLogDelegator(
6872    const v8::FunctionCallbackInfo<v8::Value>& args) {
6873  ApiTestFuzzer::Fuzz();
6874}
6875
6876
6877THREADED_TEST(GlobalObjectTemplate) {
6878  v8::Isolate* isolate = CcTest::isolate();
6879  v8::HandleScope handle_scope(isolate);
6880  Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6881  global_template->Set(v8_str("JSNI_Log"),
6882                       v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6883  v8::Local<Context> context = Context::New(isolate, 0, global_template);
6884  Context::Scope context_scope(context);
6885  CompileRun("JSNI_Log('LOG')");
6886}
6887
6888
6889static const char* kSimpleExtensionSource =
6890  "function Foo() {"
6891  "  return 4;"
6892  "}";
6893
6894
6895TEST(SimpleExtensions) {
6896  v8::HandleScope handle_scope(CcTest::isolate());
6897  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6898  const char* extension_names[] = { "simpletest" };
6899  v8::ExtensionConfiguration extensions(1, extension_names);
6900  v8::Handle<Context> context =
6901      Context::New(CcTest::isolate(), &extensions);
6902  Context::Scope lock(context);
6903  v8::Handle<Value> result = CompileRun("Foo()");
6904  CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6905}
6906
6907
6908static const char* kStackTraceFromExtensionSource =
6909  "function foo() {"
6910  "  throw new Error();"
6911  "}"
6912  "function bar() {"
6913  "  foo();"
6914  "}";
6915
6916
6917TEST(StackTraceInExtension) {
6918  v8::HandleScope handle_scope(CcTest::isolate());
6919  v8::RegisterExtension(new Extension("stacktracetest",
6920                        kStackTraceFromExtensionSource));
6921  const char* extension_names[] = { "stacktracetest" };
6922  v8::ExtensionConfiguration extensions(1, extension_names);
6923  v8::Handle<Context> context =
6924      Context::New(CcTest::isolate(), &extensions);
6925  Context::Scope lock(context);
6926  CompileRun("function user() { bar(); }"
6927             "var error;"
6928             "try{ user(); } catch (e) { error = e; }");
6929  CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
6930  CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
6931  CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
6932}
6933
6934
6935TEST(NullExtensions) {
6936  v8::HandleScope handle_scope(CcTest::isolate());
6937  v8::RegisterExtension(new Extension("nulltest", NULL));
6938  const char* extension_names[] = { "nulltest" };
6939  v8::ExtensionConfiguration extensions(1, extension_names);
6940  v8::Handle<Context> context =
6941      Context::New(CcTest::isolate(), &extensions);
6942  Context::Scope lock(context);
6943  v8::Handle<Value> result = CompileRun("1+3");
6944  CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6945}
6946
6947
6948static const char* kEmbeddedExtensionSource =
6949    "function Ret54321(){return 54321;}~~@@$"
6950    "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6951static const int kEmbeddedExtensionSourceValidLen = 34;
6952
6953
6954TEST(ExtensionMissingSourceLength) {
6955  v8::HandleScope handle_scope(CcTest::isolate());
6956  v8::RegisterExtension(new Extension("srclentest_fail",
6957                                      kEmbeddedExtensionSource));
6958  const char* extension_names[] = { "srclentest_fail" };
6959  v8::ExtensionConfiguration extensions(1, extension_names);
6960  v8::Handle<Context> context =
6961      Context::New(CcTest::isolate(), &extensions);
6962  CHECK_EQ(0, *context);
6963}
6964
6965
6966TEST(ExtensionWithSourceLength) {
6967  for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6968       source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6969    v8::HandleScope handle_scope(CcTest::isolate());
6970    i::ScopedVector<char> extension_name(32);
6971    i::SNPrintF(extension_name, "ext #%d", source_len);
6972    v8::RegisterExtension(new Extension(extension_name.start(),
6973                                        kEmbeddedExtensionSource, 0, 0,
6974                                        source_len));
6975    const char* extension_names[1] = { extension_name.start() };
6976    v8::ExtensionConfiguration extensions(1, extension_names);
6977    v8::Handle<Context> context =
6978      Context::New(CcTest::isolate(), &extensions);
6979    if (source_len == kEmbeddedExtensionSourceValidLen) {
6980      Context::Scope lock(context);
6981      v8::Handle<Value> result = CompileRun("Ret54321()");
6982      CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6983    } else {
6984      // Anything but exactly the right length should fail to compile.
6985      CHECK_EQ(0, *context);
6986    }
6987  }
6988}
6989
6990
6991static const char* kEvalExtensionSource1 =
6992  "function UseEval1() {"
6993  "  var x = 42;"
6994  "  return eval('x');"
6995  "}";
6996
6997
6998static const char* kEvalExtensionSource2 =
6999  "(function() {"
7000  "  var x = 42;"
7001  "  function e() {"
7002  "    return eval('x');"
7003  "  }"
7004  "  this.UseEval2 = e;"
7005  "})()";
7006
7007
7008TEST(UseEvalFromExtension) {
7009  v8::HandleScope handle_scope(CcTest::isolate());
7010  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7011  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7012  const char* extension_names[] = { "evaltest1", "evaltest2" };
7013  v8::ExtensionConfiguration extensions(2, extension_names);
7014  v8::Handle<Context> context =
7015      Context::New(CcTest::isolate(), &extensions);
7016  Context::Scope lock(context);
7017  v8::Handle<Value> result = CompileRun("UseEval1()");
7018  CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7019  result = CompileRun("UseEval2()");
7020  CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7021}
7022
7023
7024static const char* kWithExtensionSource1 =
7025  "function UseWith1() {"
7026  "  var x = 42;"
7027  "  with({x:87}) { return x; }"
7028  "}";
7029
7030
7031
7032static const char* kWithExtensionSource2 =
7033  "(function() {"
7034  "  var x = 42;"
7035  "  function e() {"
7036  "    with ({x:87}) { return x; }"
7037  "  }"
7038  "  this.UseWith2 = e;"
7039  "})()";
7040
7041
7042TEST(UseWithFromExtension) {
7043  v8::HandleScope handle_scope(CcTest::isolate());
7044  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7045  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7046  const char* extension_names[] = { "withtest1", "withtest2" };
7047  v8::ExtensionConfiguration extensions(2, extension_names);
7048  v8::Handle<Context> context =
7049      Context::New(CcTest::isolate(), &extensions);
7050  Context::Scope lock(context);
7051  v8::Handle<Value> result = CompileRun("UseWith1()");
7052  CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7053  result = CompileRun("UseWith2()");
7054  CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7055}
7056
7057
7058TEST(AutoExtensions) {
7059  v8::HandleScope handle_scope(CcTest::isolate());
7060  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7061  extension->set_auto_enable(true);
7062  v8::RegisterExtension(extension);
7063  v8::Handle<Context> context =
7064      Context::New(CcTest::isolate());
7065  Context::Scope lock(context);
7066  v8::Handle<Value> result = CompileRun("Foo()");
7067  CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7068}
7069
7070
7071static const char* kSyntaxErrorInExtensionSource =
7072    "[";
7073
7074
7075// Test that a syntax error in an extension does not cause a fatal
7076// error but results in an empty context.
7077TEST(SyntaxErrorExtensions) {
7078  v8::HandleScope handle_scope(CcTest::isolate());
7079  v8::RegisterExtension(new Extension("syntaxerror",
7080                                      kSyntaxErrorInExtensionSource));
7081  const char* extension_names[] = { "syntaxerror" };
7082  v8::ExtensionConfiguration extensions(1, extension_names);
7083  v8::Handle<Context> context =
7084      Context::New(CcTest::isolate(), &extensions);
7085  CHECK(context.IsEmpty());
7086}
7087
7088
7089static const char* kExceptionInExtensionSource =
7090    "throw 42";
7091
7092
7093// Test that an exception when installing an extension does not cause
7094// a fatal error but results in an empty context.
7095TEST(ExceptionExtensions) {
7096  v8::HandleScope handle_scope(CcTest::isolate());
7097  v8::RegisterExtension(new Extension("exception",
7098                                      kExceptionInExtensionSource));
7099  const char* extension_names[] = { "exception" };
7100  v8::ExtensionConfiguration extensions(1, extension_names);
7101  v8::Handle<Context> context =
7102      Context::New(CcTest::isolate(), &extensions);
7103  CHECK(context.IsEmpty());
7104}
7105
7106
7107static const char* kNativeCallInExtensionSource =
7108    "function call_runtime_last_index_of(x) {"
7109    "  return %StringLastIndexOf(x, 'bob', 10);"
7110    "}";
7111
7112
7113static const char* kNativeCallTest =
7114    "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7115
7116// Test that a native runtime calls are supported in extensions.
7117TEST(NativeCallInExtensions) {
7118  v8::HandleScope handle_scope(CcTest::isolate());
7119  v8::RegisterExtension(new Extension("nativecall",
7120                                      kNativeCallInExtensionSource));
7121  const char* extension_names[] = { "nativecall" };
7122  v8::ExtensionConfiguration extensions(1, extension_names);
7123  v8::Handle<Context> context =
7124      Context::New(CcTest::isolate(), &extensions);
7125  Context::Scope lock(context);
7126  v8::Handle<Value> result = CompileRun(kNativeCallTest);
7127  CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
7128}
7129
7130
7131class NativeFunctionExtension : public Extension {
7132 public:
7133  NativeFunctionExtension(const char* name,
7134                          const char* source,
7135                          v8::FunctionCallback fun = &Echo)
7136      : Extension(name, source),
7137        function_(fun) { }
7138
7139  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7140      v8::Isolate* isolate,
7141      v8::Handle<v8::String> name) {
7142    return v8::FunctionTemplate::New(isolate, function_);
7143  }
7144
7145  static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7146    if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7147  }
7148 private:
7149  v8::FunctionCallback function_;
7150};
7151
7152
7153TEST(NativeFunctionDeclaration) {
7154  v8::HandleScope handle_scope(CcTest::isolate());
7155  const char* name = "nativedecl";
7156  v8::RegisterExtension(new NativeFunctionExtension(name,
7157                                                    "native function foo();"));
7158  const char* extension_names[] = { name };
7159  v8::ExtensionConfiguration extensions(1, extension_names);
7160  v8::Handle<Context> context =
7161      Context::New(CcTest::isolate(), &extensions);
7162  Context::Scope lock(context);
7163  v8::Handle<Value> result = CompileRun("foo(42);");
7164  CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7165}
7166
7167
7168TEST(NativeFunctionDeclarationError) {
7169  v8::HandleScope handle_scope(CcTest::isolate());
7170  const char* name = "nativedeclerr";
7171  // Syntax error in extension code.
7172  v8::RegisterExtension(new NativeFunctionExtension(name,
7173                                                    "native\nfunction foo();"));
7174  const char* extension_names[] = { name };
7175  v8::ExtensionConfiguration extensions(1, extension_names);
7176  v8::Handle<Context> context =
7177      Context::New(CcTest::isolate(), &extensions);
7178  CHECK(context.IsEmpty());
7179}
7180
7181
7182TEST(NativeFunctionDeclarationErrorEscape) {
7183  v8::HandleScope handle_scope(CcTest::isolate());
7184  const char* name = "nativedeclerresc";
7185  // Syntax error in extension code - escape code in "native" means that
7186  // it's not treated as a keyword.
7187  v8::RegisterExtension(new NativeFunctionExtension(
7188      name,
7189      "nativ\\u0065 function foo();"));
7190  const char* extension_names[] = { name };
7191  v8::ExtensionConfiguration extensions(1, extension_names);
7192  v8::Handle<Context> context =
7193      Context::New(CcTest::isolate(), &extensions);
7194  CHECK(context.IsEmpty());
7195}
7196
7197
7198static void CheckDependencies(const char* name, const char* expected) {
7199  v8::HandleScope handle_scope(CcTest::isolate());
7200  v8::ExtensionConfiguration config(1, &name);
7201  LocalContext context(&config);
7202  CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7203           context->Global()->Get(v8_str("loaded")));
7204}
7205
7206
7207/*
7208 * Configuration:
7209 *
7210 *     /-- B <--\
7211 * A <-          -- D <-- E
7212 *     \-- C <--/
7213 */
7214THREADED_TEST(ExtensionDependency) {
7215  static const char* kEDeps[] = { "D" };
7216  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7217  static const char* kDDeps[] = { "B", "C" };
7218  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7219  static const char* kBCDeps[] = { "A" };
7220  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7221  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7222  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7223  CheckDependencies("A", "undefinedA");
7224  CheckDependencies("B", "undefinedAB");
7225  CheckDependencies("C", "undefinedAC");
7226  CheckDependencies("D", "undefinedABCD");
7227  CheckDependencies("E", "undefinedABCDE");
7228  v8::HandleScope handle_scope(CcTest::isolate());
7229  static const char* exts[2] = { "C", "E" };
7230  v8::ExtensionConfiguration config(2, exts);
7231  LocalContext context(&config);
7232  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7233}
7234
7235
7236static const char* kExtensionTestScript =
7237  "native function A();"
7238  "native function B();"
7239  "native function C();"
7240  "function Foo(i) {"
7241  "  if (i == 0) return A();"
7242  "  if (i == 1) return B();"
7243  "  if (i == 2) return C();"
7244  "}";
7245
7246
7247static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7248  ApiTestFuzzer::Fuzz();
7249  if (args.IsConstructCall()) {
7250    args.This()->Set(v8_str("data"), args.Data());
7251    args.GetReturnValue().SetNull();
7252    return;
7253  }
7254  args.GetReturnValue().Set(args.Data());
7255}
7256
7257
7258class FunctionExtension : public Extension {
7259 public:
7260  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7261  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7262      v8::Isolate* isolate,
7263      v8::Handle<String> name);
7264};
7265
7266
7267static int lookup_count = 0;
7268v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7269    v8::Isolate* isolate, v8::Handle<String> name) {
7270  lookup_count++;
7271  if (name->Equals(v8_str("A"))) {
7272    return v8::FunctionTemplate::New(
7273        isolate, CallFun, v8::Integer::New(isolate, 8));
7274  } else if (name->Equals(v8_str("B"))) {
7275    return v8::FunctionTemplate::New(
7276        isolate, CallFun, v8::Integer::New(isolate, 7));
7277  } else if (name->Equals(v8_str("C"))) {
7278    return v8::FunctionTemplate::New(
7279        isolate, CallFun, v8::Integer::New(isolate, 6));
7280  } else {
7281    return v8::Handle<v8::FunctionTemplate>();
7282  }
7283}
7284
7285
7286THREADED_TEST(FunctionLookup) {
7287  v8::RegisterExtension(new FunctionExtension());
7288  v8::HandleScope handle_scope(CcTest::isolate());
7289  static const char* exts[1] = { "functiontest" };
7290  v8::ExtensionConfiguration config(1, exts);
7291  LocalContext context(&config);
7292  CHECK_EQ(3, lookup_count);
7293  CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7294           CompileRun("Foo(0)"));
7295  CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7296           CompileRun("Foo(1)"));
7297  CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7298           CompileRun("Foo(2)"));
7299}
7300
7301
7302THREADED_TEST(NativeFunctionConstructCall) {
7303  v8::RegisterExtension(new FunctionExtension());
7304  v8::HandleScope handle_scope(CcTest::isolate());
7305  static const char* exts[1] = { "functiontest" };
7306  v8::ExtensionConfiguration config(1, exts);
7307  LocalContext context(&config);
7308  for (int i = 0; i < 10; i++) {
7309    // Run a few times to ensure that allocation of objects doesn't
7310    // change behavior of a constructor function.
7311    CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7312             CompileRun("(new A()).data"));
7313    CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7314             CompileRun("(new B()).data"));
7315    CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7316             CompileRun("(new C()).data"));
7317  }
7318}
7319
7320
7321static const char* last_location;
7322static const char* last_message;
7323void StoringErrorCallback(const char* location, const char* message) {
7324  if (last_location == NULL) {
7325    last_location = location;
7326    last_message = message;
7327  }
7328}
7329
7330
7331// ErrorReporting creates a circular extensions configuration and
7332// tests that the fatal error handler gets called.  This renders V8
7333// unusable and therefore this test cannot be run in parallel.
7334TEST(ErrorReporting) {
7335  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7336  static const char* aDeps[] = { "B" };
7337  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7338  static const char* bDeps[] = { "A" };
7339  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7340  last_location = NULL;
7341  v8::ExtensionConfiguration config(1, bDeps);
7342  v8::Handle<Context> context =
7343      Context::New(CcTest::isolate(), &config);
7344  CHECK(context.IsEmpty());
7345  CHECK_NE(last_location, NULL);
7346}
7347
7348
7349static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7350                                             v8::Handle<Value> data) {
7351  CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7352  CHECK_EQ(v8::Undefined(CcTest::isolate()),
7353      message->GetScriptOrigin().ResourceName());
7354  message->GetLineNumber();
7355  message->GetSourceLine();
7356}
7357
7358
7359THREADED_TEST(ErrorWithMissingScriptInfo) {
7360  LocalContext context;
7361  v8::HandleScope scope(context->GetIsolate());
7362  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7363  CompileRun("throw Error()");
7364  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7365}
7366
7367
7368struct FlagAndPersistent {
7369  bool flag;
7370  v8::Persistent<v8::Object> handle;
7371};
7372
7373
7374static void DisposeAndSetFlag(
7375    const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7376  data.GetParameter()->handle.Reset();
7377  data.GetParameter()->flag = true;
7378}
7379
7380
7381THREADED_TEST(IndependentWeakHandle) {
7382  v8::Isolate* iso = CcTest::isolate();
7383  v8::HandleScope scope(iso);
7384  v8::Handle<Context> context = Context::New(iso);
7385  Context::Scope context_scope(context);
7386
7387  FlagAndPersistent object_a, object_b;
7388
7389  {
7390    v8::HandleScope handle_scope(iso);
7391    object_a.handle.Reset(iso, v8::Object::New(iso));
7392    object_b.handle.Reset(iso, v8::Object::New(iso));
7393  }
7394
7395  object_a.flag = false;
7396  object_b.flag = false;
7397  object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7398  object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7399  CHECK(!object_b.handle.IsIndependent());
7400  object_a.handle.MarkIndependent();
7401  object_b.handle.MarkIndependent();
7402  CHECK(object_b.handle.IsIndependent());
7403  CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7404  CHECK(object_a.flag);
7405  CHECK(object_b.flag);
7406}
7407
7408
7409static void InvokeScavenge() {
7410  CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7411}
7412
7413
7414static void InvokeMarkSweep() {
7415  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7416}
7417
7418
7419static void ForceScavenge(
7420    const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7421  data.GetParameter()->handle.Reset();
7422  data.GetParameter()->flag = true;
7423  InvokeScavenge();
7424}
7425
7426
7427static void ForceMarkSweep(
7428    const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7429  data.GetParameter()->handle.Reset();
7430  data.GetParameter()->flag = true;
7431  InvokeMarkSweep();
7432}
7433
7434
7435THREADED_TEST(GCFromWeakCallbacks) {
7436  v8::Isolate* isolate = CcTest::isolate();
7437  v8::HandleScope scope(isolate);
7438  v8::Handle<Context> context = Context::New(isolate);
7439  Context::Scope context_scope(context);
7440
7441  static const int kNumberOfGCTypes = 2;
7442  typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7443      Callback;
7444  Callback gc_forcing_callback[kNumberOfGCTypes] =
7445      {&ForceScavenge, &ForceMarkSweep};
7446
7447  typedef void (*GCInvoker)();
7448  GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7449
7450  for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7451    for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7452      FlagAndPersistent object;
7453      {
7454        v8::HandleScope handle_scope(isolate);
7455        object.handle.Reset(isolate, v8::Object::New(isolate));
7456      }
7457      object.flag = false;
7458      object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7459      object.handle.MarkIndependent();
7460      invoke_gc[outer_gc]();
7461      CHECK(object.flag);
7462    }
7463  }
7464}
7465
7466
7467static void RevivingCallback(
7468    const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7469  data.GetParameter()->handle.ClearWeak();
7470  data.GetParameter()->flag = true;
7471}
7472
7473
7474THREADED_TEST(IndependentHandleRevival) {
7475  v8::Isolate* isolate = CcTest::isolate();
7476  v8::HandleScope scope(isolate);
7477  v8::Handle<Context> context = Context::New(isolate);
7478  Context::Scope context_scope(context);
7479
7480  FlagAndPersistent object;
7481  {
7482    v8::HandleScope handle_scope(isolate);
7483    v8::Local<v8::Object> o = v8::Object::New(isolate);
7484    object.handle.Reset(isolate, o);
7485    o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7486    v8::Local<String> y_str = v8_str("y");
7487    o->Set(y_str, y_str);
7488  }
7489  object.flag = false;
7490  object.handle.SetWeak(&object, &RevivingCallback);
7491  object.handle.MarkIndependent();
7492  CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7493  CHECK(object.flag);
7494  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7495  {
7496    v8::HandleScope handle_scope(isolate);
7497    v8::Local<v8::Object> o =
7498        v8::Local<v8::Object>::New(isolate, object.handle);
7499    v8::Local<String> y_str = v8_str("y");
7500    CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7501    CHECK(o->Get(y_str)->Equals(y_str));
7502  }
7503}
7504
7505
7506v8::Handle<Function> args_fun;
7507
7508
7509static void ArgumentsTestCallback(
7510    const v8::FunctionCallbackInfo<v8::Value>& args) {
7511  ApiTestFuzzer::Fuzz();
7512  v8::Isolate* isolate = args.GetIsolate();
7513  CHECK_EQ(args_fun, args.Callee());
7514  CHECK_EQ(3, args.Length());
7515  CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7516  CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7517  CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7518  CHECK_EQ(v8::Undefined(isolate), args[3]);
7519  v8::HandleScope scope(args.GetIsolate());
7520  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7521}
7522
7523
7524THREADED_TEST(Arguments) {
7525  v8::Isolate* isolate = CcTest::isolate();
7526  v8::HandleScope scope(isolate);
7527  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7528  global->Set(v8_str("f"),
7529              v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7530  LocalContext context(NULL, global);
7531  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7532  v8_compile("f(1, 2, 3)")->Run();
7533}
7534
7535
7536static void NoBlockGetterX(Local<String> name,
7537                           const v8::PropertyCallbackInfo<v8::Value>&) {
7538}
7539
7540
7541static void NoBlockGetterI(uint32_t index,
7542                           const v8::PropertyCallbackInfo<v8::Value>&) {
7543}
7544
7545
7546static void PDeleter(Local<String> name,
7547                     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7548  if (!name->Equals(v8_str("foo"))) {
7549    return;  // not intercepted
7550  }
7551
7552  info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7553}
7554
7555
7556static void IDeleter(uint32_t index,
7557                     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7558  if (index != 2) {
7559    return;  // not intercepted
7560  }
7561
7562  info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7563}
7564
7565
7566THREADED_TEST(Deleter) {
7567  v8::Isolate* isolate = CcTest::isolate();
7568  v8::HandleScope scope(isolate);
7569  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7570  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7571  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7572  LocalContext context;
7573  context->Global()->Set(v8_str("k"), obj->NewInstance());
7574  CompileRun(
7575    "k.foo = 'foo';"
7576    "k.bar = 'bar';"
7577    "k[2] = 2;"
7578    "k[4] = 4;");
7579  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7580  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7581
7582  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7583  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7584
7585  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7586  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7587
7588  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7589  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7590}
7591
7592
7593static void GetK(Local<String> name,
7594                 const v8::PropertyCallbackInfo<v8::Value>& info) {
7595  ApiTestFuzzer::Fuzz();
7596  if (name->Equals(v8_str("foo")) ||
7597      name->Equals(v8_str("bar")) ||
7598      name->Equals(v8_str("baz"))) {
7599    info.GetReturnValue().SetUndefined();
7600  }
7601}
7602
7603
7604static void IndexedGetK(uint32_t index,
7605                        const v8::PropertyCallbackInfo<v8::Value>& info) {
7606  ApiTestFuzzer::Fuzz();
7607  if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7608}
7609
7610
7611static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7612  ApiTestFuzzer::Fuzz();
7613  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7614  result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7615  result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7616  result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7617  info.GetReturnValue().Set(result);
7618}
7619
7620
7621static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7622  ApiTestFuzzer::Fuzz();
7623  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7624  result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7625  result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7626  info.GetReturnValue().Set(result);
7627}
7628
7629
7630THREADED_TEST(Enumerators) {
7631  v8::Isolate* isolate = CcTest::isolate();
7632  v8::HandleScope scope(isolate);
7633  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7634  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7635  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7636  LocalContext context;
7637  context->Global()->Set(v8_str("k"), obj->NewInstance());
7638  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7639    "k[10] = 0;"
7640    "k.a = 0;"
7641    "k[5] = 0;"
7642    "k.b = 0;"
7643    "k[4294967295] = 0;"
7644    "k.c = 0;"
7645    "k[4294967296] = 0;"
7646    "k.d = 0;"
7647    "k[140000] = 0;"
7648    "k.e = 0;"
7649    "k[30000000000] = 0;"
7650    "k.f = 0;"
7651    "var result = [];"
7652    "for (var prop in k) {"
7653    "  result.push(prop);"
7654    "}"
7655    "result"));
7656  // Check that we get all the property names returned including the
7657  // ones from the enumerators in the right order: indexed properties
7658  // in numerical order, indexed interceptor properties, named
7659  // properties in insertion order, named interceptor properties.
7660  // This order is not mandated by the spec, so this test is just
7661  // documenting our behavior.
7662  CHECK_EQ(17, result->Length());
7663  // Indexed properties in numerical order.
7664  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7665  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7666  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7667  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7668  // Indexed interceptor properties in the order they are returned
7669  // from the enumerator interceptor.
7670  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7671  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7672  // Named properties in insertion order.
7673  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7674  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7675  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7676  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7677  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7678  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7679  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7680  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7681  // Named interceptor properties.
7682  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7683  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7684  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7685}
7686
7687
7688int p_getter_count;
7689int p_getter_count2;
7690
7691
7692static void PGetter(Local<String> name,
7693                    const v8::PropertyCallbackInfo<v8::Value>& info) {
7694  ApiTestFuzzer::Fuzz();
7695  p_getter_count++;
7696  v8::Handle<v8::Object> global =
7697      info.GetIsolate()->GetCurrentContext()->Global();
7698  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7699  if (name->Equals(v8_str("p1"))) {
7700    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7701  } else if (name->Equals(v8_str("p2"))) {
7702    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7703  } else if (name->Equals(v8_str("p3"))) {
7704    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7705  } else if (name->Equals(v8_str("p4"))) {
7706    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7707  }
7708}
7709
7710
7711static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7712  ApiTestFuzzer::Fuzz();
7713  LocalContext context;
7714  context->Global()->Set(v8_str("o1"), obj->NewInstance());
7715  CompileRun(
7716    "o1.__proto__ = { };"
7717    "var o2 = { __proto__: o1 };"
7718    "var o3 = { __proto__: o2 };"
7719    "var o4 = { __proto__: o3 };"
7720    "for (var i = 0; i < 10; i++) o4.p4;"
7721    "for (var i = 0; i < 10; i++) o3.p3;"
7722    "for (var i = 0; i < 10; i++) o2.p2;"
7723    "for (var i = 0; i < 10; i++) o1.p1;");
7724}
7725
7726
7727static void PGetter2(Local<String> name,
7728                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7729  ApiTestFuzzer::Fuzz();
7730  p_getter_count2++;
7731  v8::Handle<v8::Object> global =
7732      info.GetIsolate()->GetCurrentContext()->Global();
7733  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7734  if (name->Equals(v8_str("p1"))) {
7735    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7736  } else if (name->Equals(v8_str("p2"))) {
7737    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7738  } else if (name->Equals(v8_str("p3"))) {
7739    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7740  } else if (name->Equals(v8_str("p4"))) {
7741    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7742  }
7743}
7744
7745
7746THREADED_TEST(GetterHolders) {
7747  v8::Isolate* isolate = CcTest::isolate();
7748  v8::HandleScope scope(isolate);
7749  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7750  obj->SetAccessor(v8_str("p1"), PGetter);
7751  obj->SetAccessor(v8_str("p2"), PGetter);
7752  obj->SetAccessor(v8_str("p3"), PGetter);
7753  obj->SetAccessor(v8_str("p4"), PGetter);
7754  p_getter_count = 0;
7755  RunHolderTest(obj);
7756  CHECK_EQ(40, p_getter_count);
7757}
7758
7759
7760THREADED_TEST(PreInterceptorHolders) {
7761  v8::Isolate* isolate = CcTest::isolate();
7762  v8::HandleScope scope(isolate);
7763  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7764  obj->SetNamedPropertyHandler(PGetter2);
7765  p_getter_count2 = 0;
7766  RunHolderTest(obj);
7767  CHECK_EQ(40, p_getter_count2);
7768}
7769
7770
7771THREADED_TEST(ObjectInstantiation) {
7772  v8::Isolate* isolate = CcTest::isolate();
7773  v8::HandleScope scope(isolate);
7774  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7775  templ->SetAccessor(v8_str("t"), PGetter2);
7776  LocalContext context;
7777  context->Global()->Set(v8_str("o"), templ->NewInstance());
7778  for (int i = 0; i < 100; i++) {
7779    v8::HandleScope inner_scope(CcTest::isolate());
7780    v8::Handle<v8::Object> obj = templ->NewInstance();
7781    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7782    context->Global()->Set(v8_str("o2"), obj);
7783    v8::Handle<Value> value =
7784        CompileRun("o.__proto__ === o2.__proto__");
7785    CHECK_EQ(v8::True(isolate), value);
7786    context->Global()->Set(v8_str("o"), obj);
7787  }
7788}
7789
7790
7791static int StrCmp16(uint16_t* a, uint16_t* b) {
7792  while (true) {
7793    if (*a == 0 && *b == 0) return 0;
7794    if (*a != *b) return 0 + *a - *b;
7795    a++;
7796    b++;
7797  }
7798}
7799
7800
7801static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7802  while (true) {
7803    if (n-- == 0) return 0;
7804    if (*a == 0 && *b == 0) return 0;
7805    if (*a != *b) return 0 + *a - *b;
7806    a++;
7807    b++;
7808  }
7809}
7810
7811
7812int GetUtf8Length(Handle<String> str) {
7813  int len = str->Utf8Length();
7814  if (len < 0) {
7815    i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7816    i::String::Flatten(istr);
7817    len = str->Utf8Length();
7818  }
7819  return len;
7820}
7821
7822
7823THREADED_TEST(StringWrite) {
7824  LocalContext context;
7825  v8::HandleScope scope(context->GetIsolate());
7826  v8::Handle<String> str = v8_str("abcde");
7827  // abc<Icelandic eth><Unicode snowman>.
7828  v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7829  v8::Handle<String> str3 = v8::String::NewFromUtf8(
7830      context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7831  // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7832  uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7833  v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7834      context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7835  // single lead surrogate
7836  uint16_t lead[1] = { 0xd800 };
7837  v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7838      context->GetIsolate(), lead, v8::String::kNormalString, 1);
7839  // single trail surrogate
7840  uint16_t trail[1] = { 0xdc00 };
7841  v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7842      context->GetIsolate(), trail, v8::String::kNormalString, 1);
7843  // surrogate pair
7844  uint16_t pair[2] = { 0xd800,  0xdc00 };
7845  v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7846      context->GetIsolate(), pair, v8::String::kNormalString, 2);
7847  const int kStride = 4;  // Must match stride in for loops in JS below.
7848  CompileRun(
7849      "var left = '';"
7850      "for (var i = 0; i < 0xd800; i += 4) {"
7851      "  left = left + String.fromCharCode(i);"
7852      "}");
7853  CompileRun(
7854      "var right = '';"
7855      "for (var i = 0; i < 0xd800; i += 4) {"
7856      "  right = String.fromCharCode(i) + right;"
7857      "}");
7858  v8::Handle<v8::Object> global = context->Global();
7859  Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7860  Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7861
7862  CHECK_EQ(5, str2->Length());
7863  CHECK_EQ(0xd800 / kStride, left_tree->Length());
7864  CHECK_EQ(0xd800 / kStride, right_tree->Length());
7865
7866  char buf[100];
7867  char utf8buf[0xd800 * 3];
7868  uint16_t wbuf[100];
7869  int len;
7870  int charlen;
7871
7872  memset(utf8buf, 0x1, 1000);
7873  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7874  CHECK_EQ(9, len);
7875  CHECK_EQ(5, charlen);
7876  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7877
7878  memset(utf8buf, 0x1, 1000);
7879  len = str2->WriteUtf8(utf8buf, 8, &charlen);
7880  CHECK_EQ(8, len);
7881  CHECK_EQ(5, charlen);
7882  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7883
7884  memset(utf8buf, 0x1, 1000);
7885  len = str2->WriteUtf8(utf8buf, 7, &charlen);
7886  CHECK_EQ(5, len);
7887  CHECK_EQ(4, charlen);
7888  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7889
7890  memset(utf8buf, 0x1, 1000);
7891  len = str2->WriteUtf8(utf8buf, 6, &charlen);
7892  CHECK_EQ(5, len);
7893  CHECK_EQ(4, charlen);
7894  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7895
7896  memset(utf8buf, 0x1, 1000);
7897  len = str2->WriteUtf8(utf8buf, 5, &charlen);
7898  CHECK_EQ(5, len);
7899  CHECK_EQ(4, charlen);
7900  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7901
7902  memset(utf8buf, 0x1, 1000);
7903  len = str2->WriteUtf8(utf8buf, 4, &charlen);
7904  CHECK_EQ(3, len);
7905  CHECK_EQ(3, charlen);
7906  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7907
7908  memset(utf8buf, 0x1, 1000);
7909  len = str2->WriteUtf8(utf8buf, 3, &charlen);
7910  CHECK_EQ(3, len);
7911  CHECK_EQ(3, charlen);
7912  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7913
7914  memset(utf8buf, 0x1, 1000);
7915  len = str2->WriteUtf8(utf8buf, 2, &charlen);
7916  CHECK_EQ(2, len);
7917  CHECK_EQ(2, charlen);
7918  CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7919
7920  // allow orphan surrogates by default
7921  memset(utf8buf, 0x1, 1000);
7922  len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7923  CHECK_EQ(13, len);
7924  CHECK_EQ(8, charlen);
7925  CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7926
7927  // replace orphan surrogates with unicode replacement character
7928  memset(utf8buf, 0x1, 1000);
7929  len = orphans_str->WriteUtf8(utf8buf,
7930                               sizeof(utf8buf),
7931                               &charlen,
7932                               String::REPLACE_INVALID_UTF8);
7933  CHECK_EQ(13, len);
7934  CHECK_EQ(8, charlen);
7935  CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7936
7937  // replace single lead surrogate with unicode replacement character
7938  memset(utf8buf, 0x1, 1000);
7939  len = lead_str->WriteUtf8(utf8buf,
7940                            sizeof(utf8buf),
7941                            &charlen,
7942                            String::REPLACE_INVALID_UTF8);
7943  CHECK_EQ(4, len);
7944  CHECK_EQ(1, charlen);
7945  CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7946
7947  // replace single trail surrogate with unicode replacement character
7948  memset(utf8buf, 0x1, 1000);
7949  len = trail_str->WriteUtf8(utf8buf,
7950                             sizeof(utf8buf),
7951                             &charlen,
7952                             String::REPLACE_INVALID_UTF8);
7953  CHECK_EQ(4, len);
7954  CHECK_EQ(1, charlen);
7955  CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7956
7957  // do not replace / write anything if surrogate pair does not fit the buffer
7958  // space
7959  memset(utf8buf, 0x1, 1000);
7960  len = pair_str->WriteUtf8(utf8buf,
7961                             3,
7962                             &charlen,
7963                             String::REPLACE_INVALID_UTF8);
7964  CHECK_EQ(0, len);
7965  CHECK_EQ(0, charlen);
7966
7967  memset(utf8buf, 0x1, sizeof(utf8buf));
7968  len = GetUtf8Length(left_tree);
7969  int utf8_expected =
7970      (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7971  CHECK_EQ(utf8_expected, len);
7972  len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7973  CHECK_EQ(utf8_expected, len);
7974  CHECK_EQ(0xd800 / kStride, charlen);
7975  CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7976  CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7977  CHECK_EQ(0xc0 - kStride,
7978           static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7979  CHECK_EQ(1, utf8buf[utf8_expected]);
7980
7981  memset(utf8buf, 0x1, sizeof(utf8buf));
7982  len = GetUtf8Length(right_tree);
7983  CHECK_EQ(utf8_expected, len);
7984  len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7985  CHECK_EQ(utf8_expected, len);
7986  CHECK_EQ(0xd800 / kStride, charlen);
7987  CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7988  CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7989  CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7990  CHECK_EQ(1, utf8buf[utf8_expected]);
7991
7992  memset(buf, 0x1, sizeof(buf));
7993  memset(wbuf, 0x1, sizeof(wbuf));
7994  len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7995  CHECK_EQ(5, len);
7996  len = str->Write(wbuf);
7997  CHECK_EQ(5, len);
7998  CHECK_EQ(0, strcmp("abcde", buf));
7999  uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8000  CHECK_EQ(0, StrCmp16(answer1, wbuf));
8001
8002  memset(buf, 0x1, sizeof(buf));
8003  memset(wbuf, 0x1, sizeof(wbuf));
8004  len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
8005  CHECK_EQ(4, len);
8006  len = str->Write(wbuf, 0, 4);
8007  CHECK_EQ(4, len);
8008  CHECK_EQ(0, strncmp("abcd\1", buf, 5));
8009  uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8010  CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8011
8012  memset(buf, 0x1, sizeof(buf));
8013  memset(wbuf, 0x1, sizeof(wbuf));
8014  len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
8015  CHECK_EQ(5, len);
8016  len = str->Write(wbuf, 0, 5);
8017  CHECK_EQ(5, len);
8018  CHECK_EQ(0, strncmp("abcde\1", buf, 6));
8019  uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8020  CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8021
8022  memset(buf, 0x1, sizeof(buf));
8023  memset(wbuf, 0x1, sizeof(wbuf));
8024  len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
8025  CHECK_EQ(5, len);
8026  len = str->Write(wbuf, 0, 6);
8027  CHECK_EQ(5, len);
8028  CHECK_EQ(0, strcmp("abcde", buf));
8029  uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8030  CHECK_EQ(0, StrCmp16(answer4, wbuf));
8031
8032  memset(buf, 0x1, sizeof(buf));
8033  memset(wbuf, 0x1, sizeof(wbuf));
8034  len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
8035  CHECK_EQ(1, len);
8036  len = str->Write(wbuf, 4, -1);
8037  CHECK_EQ(1, len);
8038  CHECK_EQ(0, strcmp("e", buf));
8039  uint16_t answer5[] = {'e', '\0'};
8040  CHECK_EQ(0, StrCmp16(answer5, wbuf));
8041
8042  memset(buf, 0x1, sizeof(buf));
8043  memset(wbuf, 0x1, sizeof(wbuf));
8044  len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
8045  CHECK_EQ(1, len);
8046  len = str->Write(wbuf, 4, 6);
8047  CHECK_EQ(1, len);
8048  CHECK_EQ(0, strcmp("e", buf));
8049  CHECK_EQ(0, StrCmp16(answer5, wbuf));
8050
8051  memset(buf, 0x1, sizeof(buf));
8052  memset(wbuf, 0x1, sizeof(wbuf));
8053  len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
8054  CHECK_EQ(1, len);
8055  len = str->Write(wbuf, 4, 1);
8056  CHECK_EQ(1, len);
8057  CHECK_EQ(0, strncmp("e\1", buf, 2));
8058  uint16_t answer6[] = {'e', 0x101};
8059  CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8060
8061  memset(buf, 0x1, sizeof(buf));
8062  memset(wbuf, 0x1, sizeof(wbuf));
8063  len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
8064  CHECK_EQ(1, len);
8065  len = str->Write(wbuf, 3, 1);
8066  CHECK_EQ(1, len);
8067  CHECK_EQ(0, strncmp("d\1", buf, 2));
8068  uint16_t answer7[] = {'d', 0x101};
8069  CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8070
8071  memset(wbuf, 0x1, sizeof(wbuf));
8072  wbuf[5] = 'X';
8073  len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
8074  CHECK_EQ(5, len);
8075  CHECK_EQ('X', wbuf[5]);
8076  uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8077  uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8078  CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8079  CHECK_NE(0, StrCmp16(answer8b, wbuf));
8080  wbuf[5] = '\0';
8081  CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8082
8083  memset(buf, 0x1, sizeof(buf));
8084  buf[5] = 'X';
8085  len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8086                          0,
8087                          6,
8088                          String::NO_NULL_TERMINATION);
8089  CHECK_EQ(5, len);
8090  CHECK_EQ('X', buf[5]);
8091  CHECK_EQ(0, strncmp("abcde", buf, 5));
8092  CHECK_NE(0, strcmp("abcde", buf));
8093  buf[5] = '\0';
8094  CHECK_EQ(0, strcmp("abcde", buf));
8095
8096  memset(utf8buf, 0x1, sizeof(utf8buf));
8097  utf8buf[8] = 'X';
8098  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8099                        String::NO_NULL_TERMINATION);
8100  CHECK_EQ(8, len);
8101  CHECK_EQ('X', utf8buf[8]);
8102  CHECK_EQ(5, charlen);
8103  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
8104  CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8105  utf8buf[8] = '\0';
8106  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8107
8108  memset(utf8buf, 0x1, sizeof(utf8buf));
8109  utf8buf[5] = 'X';
8110  len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8111                        String::NO_NULL_TERMINATION);
8112  CHECK_EQ(5, len);
8113  CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
8114  CHECK_EQ(5, charlen);
8115  utf8buf[5] = '\0';
8116  CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8117
8118  memset(buf, 0x1, sizeof(buf));
8119  len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8120  CHECK_EQ(7, len);
8121  CHECK_EQ(0, strcmp("abc", buf));
8122  CHECK_EQ(0, buf[3]);
8123  CHECK_EQ(0, strcmp("def", buf + 4));
8124
8125  CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
8126  CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
8127  CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
8128}
8129
8130
8131static void Utf16Helper(
8132    LocalContext& context,  // NOLINT
8133    const char* name,
8134    const char* lengths_name,
8135    int len) {
8136  Local<v8::Array> a =
8137      Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8138  Local<v8::Array> alens =
8139      Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8140  for (int i = 0; i < len; i++) {
8141    Local<v8::String> string =
8142      Local<v8::String>::Cast(a->Get(i));
8143    Local<v8::Number> expected_len =
8144      Local<v8::Number>::Cast(alens->Get(i));
8145    int length = GetUtf8Length(string);
8146    CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8147  }
8148}
8149
8150
8151static uint16_t StringGet(Handle<String> str, int index) {
8152  i::Handle<i::String> istring =
8153      v8::Utils::OpenHandle(String::Cast(*str));
8154  return istring->Get(index);
8155}
8156
8157
8158static void WriteUtf8Helper(
8159    LocalContext& context,  // NOLINT
8160    const char* name,
8161    const char* lengths_name,
8162    int len) {
8163  Local<v8::Array> b =
8164      Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8165  Local<v8::Array> alens =
8166      Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8167  char buffer[1000];
8168  char buffer2[1000];
8169  for (int i = 0; i < len; i++) {
8170    Local<v8::String> string =
8171      Local<v8::String>::Cast(b->Get(i));
8172    Local<v8::Number> expected_len =
8173      Local<v8::Number>::Cast(alens->Get(i));
8174    int utf8_length = static_cast<int>(expected_len->Value());
8175    for (int j = utf8_length + 1; j >= 0; j--) {
8176      memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
8177      memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
8178      int nchars;
8179      int utf8_written =
8180          string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
8181      int utf8_written2 =
8182          string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
8183      CHECK_GE(utf8_length + 1, utf8_written);
8184      CHECK_GE(utf8_length, utf8_written2);
8185      for (int k = 0; k < utf8_written2; k++) {
8186        CHECK_EQ(buffer[k], buffer2[k]);
8187      }
8188      CHECK(nchars * 3 >= utf8_written - 1);
8189      CHECK(nchars <= utf8_written);
8190      if (j == utf8_length + 1) {
8191        CHECK_EQ(utf8_written2, utf8_length);
8192        CHECK_EQ(utf8_written2 + 1, utf8_written);
8193      }
8194      CHECK_EQ(buffer[utf8_written], 42);
8195      if (j > utf8_length) {
8196        if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
8197        if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8198        Handle<String> roundtrip = v8_str(buffer);
8199        CHECK(roundtrip->Equals(string));
8200      } else {
8201        if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8202      }
8203      if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8204      if (nchars >= 2) {
8205        uint16_t trail = StringGet(string, nchars - 1);
8206        uint16_t lead = StringGet(string, nchars - 2);
8207        if (((lead & 0xfc00) == 0xd800) &&
8208            ((trail & 0xfc00) == 0xdc00)) {
8209          unsigned char u1 = buffer2[utf8_written2 - 4];
8210          unsigned char u2 = buffer2[utf8_written2 - 3];
8211          unsigned char u3 = buffer2[utf8_written2 - 2];
8212          unsigned char u4 = buffer2[utf8_written2 - 1];
8213          CHECK_EQ((u1 & 0xf8), 0xf0);
8214          CHECK_EQ((u2 & 0xc0), 0x80);
8215          CHECK_EQ((u3 & 0xc0), 0x80);
8216          CHECK_EQ((u4 & 0xc0), 0x80);
8217          uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8218          CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8219          CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8220          CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8221          CHECK_EQ((u1 & 0x3), c >> 18);
8222        }
8223      }
8224    }
8225  }
8226}
8227
8228
8229THREADED_TEST(Utf16) {
8230  LocalContext context;
8231  v8::HandleScope scope(context->GetIsolate());
8232  CompileRun(
8233      "var pad = '01234567890123456789';"
8234      "var p = [];"
8235      "var plens = [20, 3, 3];"
8236      "p.push('01234567890123456789');"
8237      "var lead = 0xd800;"
8238      "var trail = 0xdc00;"
8239      "p.push(String.fromCharCode(0xd800));"
8240      "p.push(String.fromCharCode(0xdc00));"
8241      "var a = [];"
8242      "var b = [];"
8243      "var c = [];"
8244      "var alens = [];"
8245      "for (var i = 0; i < 3; i++) {"
8246      "  p[1] = String.fromCharCode(lead++);"
8247      "  for (var j = 0; j < 3; j++) {"
8248      "    p[2] = String.fromCharCode(trail++);"
8249      "    a.push(p[i] + p[j]);"
8250      "    b.push(p[i] + p[j]);"
8251      "    c.push(p[i] + p[j]);"
8252      "    alens.push(plens[i] + plens[j]);"
8253      "  }"
8254      "}"
8255      "alens[5] -= 2;"  // Here the surrogate pairs match up.
8256      "var a2 = [];"
8257      "var b2 = [];"
8258      "var c2 = [];"
8259      "var a2lens = [];"
8260      "for (var m = 0; m < 9; m++) {"
8261      "  for (var n = 0; n < 9; n++) {"
8262      "    a2.push(a[m] + a[n]);"
8263      "    b2.push(b[m] + b[n]);"
8264      "    var newc = 'x' + c[m] + c[n] + 'y';"
8265      "    c2.push(newc.substring(1, newc.length - 1));"
8266      "    var utf = alens[m] + alens[n];"  // And here.
8267           // The 'n's that start with 0xdc.. are 6-8
8268           // The 'm's that end with 0xd8.. are 1, 4 and 7
8269      "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
8270      "    a2lens.push(utf);"
8271      "  }"
8272      "}");
8273  Utf16Helper(context, "a", "alens", 9);
8274  Utf16Helper(context, "a2", "a2lens", 81);
8275  WriteUtf8Helper(context, "b", "alens", 9);
8276  WriteUtf8Helper(context, "b2", "a2lens", 81);
8277  WriteUtf8Helper(context, "c2", "a2lens", 81);
8278}
8279
8280
8281static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8282  i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8283  i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8284  return *is1 == *is2;
8285}
8286
8287static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8288                             const char* b) {
8289  Handle<String> symbol1 =
8290      v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8291  Handle<String> symbol2 =
8292      v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8293  CHECK(SameSymbol(symbol1, symbol2));
8294}
8295
8296
8297THREADED_TEST(Utf16Symbol) {
8298  LocalContext context;
8299  v8::HandleScope scope(context->GetIsolate());
8300
8301  Handle<String> symbol1 = v8::String::NewFromUtf8(
8302      context->GetIsolate(), "abc", v8::String::kInternalizedString);
8303  Handle<String> symbol2 = v8::String::NewFromUtf8(
8304      context->GetIsolate(), "abc", v8::String::kInternalizedString);
8305  CHECK(SameSymbol(symbol1, symbol2));
8306
8307  SameSymbolHelper(context->GetIsolate(),
8308                   "\360\220\220\205",  // 4 byte encoding.
8309                   "\355\240\201\355\260\205");  // 2 3-byte surrogates.
8310  SameSymbolHelper(context->GetIsolate(),
8311                   "\355\240\201\355\260\206",  // 2 3-byte surrogates.
8312                   "\360\220\220\206");  // 4 byte encoding.
8313  SameSymbolHelper(context->GetIsolate(),
8314                   "x\360\220\220\205",  // 4 byte encoding.
8315                   "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
8316  SameSymbolHelper(context->GetIsolate(),
8317                   "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
8318                   "x\360\220\220\206");  // 4 byte encoding.
8319  CompileRun(
8320      "var sym0 = 'benedictus';"
8321      "var sym0b = 'S\303\270ren';"
8322      "var sym1 = '\355\240\201\355\260\207';"
8323      "var sym2 = '\360\220\220\210';"
8324      "var sym3 = 'x\355\240\201\355\260\207';"
8325      "var sym4 = 'x\360\220\220\210';"
8326      "if (sym1.length != 2) throw sym1;"
8327      "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8328      "if (sym2.length != 2) throw sym2;"
8329      "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8330      "if (sym3.length != 3) throw sym3;"
8331      "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8332      "if (sym4.length != 3) throw sym4;"
8333      "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8334  Handle<String> sym0 = v8::String::NewFromUtf8(
8335      context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8336  Handle<String> sym0b = v8::String::NewFromUtf8(
8337      context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8338  Handle<String> sym1 =
8339      v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8340                              v8::String::kInternalizedString);
8341  Handle<String> sym2 =
8342      v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8343                              v8::String::kInternalizedString);
8344  Handle<String> sym3 = v8::String::NewFromUtf8(
8345      context->GetIsolate(), "x\355\240\201\355\260\207",
8346      v8::String::kInternalizedString);
8347  Handle<String> sym4 =
8348      v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8349                              v8::String::kInternalizedString);
8350  v8::Local<v8::Object> global = context->Global();
8351  Local<Value> s0 = global->Get(v8_str("sym0"));
8352  Local<Value> s0b = global->Get(v8_str("sym0b"));
8353  Local<Value> s1 = global->Get(v8_str("sym1"));
8354  Local<Value> s2 = global->Get(v8_str("sym2"));
8355  Local<Value> s3 = global->Get(v8_str("sym3"));
8356  Local<Value> s4 = global->Get(v8_str("sym4"));
8357  CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8358  CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8359  CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8360  CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8361  CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8362  CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8363}
8364
8365
8366THREADED_TEST(ToArrayIndex) {
8367  LocalContext context;
8368  v8::Isolate* isolate = context->GetIsolate();
8369  v8::HandleScope scope(isolate);
8370
8371  v8::Handle<String> str = v8_str("42");
8372  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8373  CHECK(!index.IsEmpty());
8374  CHECK_EQ(42.0, index->Uint32Value());
8375  str = v8_str("42asdf");
8376  index = str->ToArrayIndex();
8377  CHECK(index.IsEmpty());
8378  str = v8_str("-42");
8379  index = str->ToArrayIndex();
8380  CHECK(index.IsEmpty());
8381  str = v8_str("4294967295");
8382  index = str->ToArrayIndex();
8383  CHECK(!index.IsEmpty());
8384  CHECK_EQ(4294967295.0, index->Uint32Value());
8385  v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8386  index = num->ToArrayIndex();
8387  CHECK(!index.IsEmpty());
8388  CHECK_EQ(1.0, index->Uint32Value());
8389  num = v8::Number::New(isolate, -1);
8390  index = num->ToArrayIndex();
8391  CHECK(index.IsEmpty());
8392  v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8393  index = obj->ToArrayIndex();
8394  CHECK(index.IsEmpty());
8395}
8396
8397
8398THREADED_TEST(ErrorConstruction) {
8399  LocalContext context;
8400  v8::HandleScope scope(context->GetIsolate());
8401
8402  v8::Handle<String> foo = v8_str("foo");
8403  v8::Handle<String> message = v8_str("message");
8404  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8405  CHECK(range_error->IsObject());
8406  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8407  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8408  CHECK(reference_error->IsObject());
8409  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8410  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8411  CHECK(syntax_error->IsObject());
8412  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8413  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8414  CHECK(type_error->IsObject());
8415  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8416  v8::Handle<Value> error = v8::Exception::Error(foo);
8417  CHECK(error->IsObject());
8418  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8419}
8420
8421
8422static void YGetter(Local<String> name,
8423                    const v8::PropertyCallbackInfo<v8::Value>& info) {
8424  ApiTestFuzzer::Fuzz();
8425  info.GetReturnValue().Set(v8_num(10));
8426}
8427
8428
8429static void YSetter(Local<String> name,
8430                    Local<Value> value,
8431                    const v8::PropertyCallbackInfo<void>& info) {
8432  Local<Object> this_obj = Local<Object>::Cast(info.This());
8433  if (this_obj->Has(name)) this_obj->Delete(name);
8434  this_obj->Set(name, value);
8435}
8436
8437
8438THREADED_TEST(DeleteAccessor) {
8439  v8::Isolate* isolate = CcTest::isolate();
8440  v8::HandleScope scope(isolate);
8441  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8442  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8443  LocalContext context;
8444  v8::Handle<v8::Object> holder = obj->NewInstance();
8445  context->Global()->Set(v8_str("holder"), holder);
8446  v8::Handle<Value> result = CompileRun(
8447      "holder.y = 11; holder.y = 12; holder.y");
8448  CHECK_EQ(12, result->Uint32Value());
8449}
8450
8451
8452THREADED_TEST(TypeSwitch) {
8453  v8::Isolate* isolate = CcTest::isolate();
8454  v8::HandleScope scope(isolate);
8455  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8456  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8457  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8458  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8459  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8460  LocalContext context;
8461  v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8462  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8463  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8464  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8465  for (int i = 0; i < 10; i++) {
8466    CHECK_EQ(0, type_switch->match(obj0));
8467    CHECK_EQ(1, type_switch->match(obj1));
8468    CHECK_EQ(2, type_switch->match(obj2));
8469    CHECK_EQ(3, type_switch->match(obj3));
8470    CHECK_EQ(3, type_switch->match(obj3));
8471    CHECK_EQ(2, type_switch->match(obj2));
8472    CHECK_EQ(1, type_switch->match(obj1));
8473    CHECK_EQ(0, type_switch->match(obj0));
8474  }
8475}
8476
8477
8478static int trouble_nesting = 0;
8479static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8480  ApiTestFuzzer::Fuzz();
8481  trouble_nesting++;
8482
8483  // Call a JS function that throws an uncaught exception.
8484  Local<v8::Object> arg_this =
8485      args.GetIsolate()->GetCurrentContext()->Global();
8486  Local<Value> trouble_callee = (trouble_nesting == 3) ?
8487    arg_this->Get(v8_str("trouble_callee")) :
8488    arg_this->Get(v8_str("trouble_caller"));
8489  CHECK(trouble_callee->IsFunction());
8490  args.GetReturnValue().Set(
8491      Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8492}
8493
8494
8495static int report_count = 0;
8496static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8497                                             v8::Handle<Value>) {
8498  report_count++;
8499}
8500
8501
8502// Counts uncaught exceptions, but other tests running in parallel
8503// also have uncaught exceptions.
8504TEST(ApiUncaughtException) {
8505  report_count = 0;
8506  LocalContext env;
8507  v8::Isolate* isolate = env->GetIsolate();
8508  v8::HandleScope scope(isolate);
8509  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8510
8511  Local<v8::FunctionTemplate> fun =
8512      v8::FunctionTemplate::New(isolate, TroubleCallback);
8513  v8::Local<v8::Object> global = env->Global();
8514  global->Set(v8_str("trouble"), fun->GetFunction());
8515
8516  CompileRun(
8517      "function trouble_callee() {"
8518      "  var x = null;"
8519      "  return x.foo;"
8520      "};"
8521      "function trouble_caller() {"
8522      "  trouble();"
8523      "};");
8524  Local<Value> trouble = global->Get(v8_str("trouble"));
8525  CHECK(trouble->IsFunction());
8526  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8527  CHECK(trouble_callee->IsFunction());
8528  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8529  CHECK(trouble_caller->IsFunction());
8530  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8531  CHECK_EQ(1, report_count);
8532  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8533}
8534
8535static const char* script_resource_name = "ExceptionInNativeScript.js";
8536static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8537                                                v8::Handle<Value>) {
8538  v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
8539  CHECK(!name_val.IsEmpty() && name_val->IsString());
8540  v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
8541  CHECK_EQ(script_resource_name, *name);
8542  CHECK_EQ(3, message->GetLineNumber());
8543  v8::String::Utf8Value source_line(message->GetSourceLine());
8544  CHECK_EQ("  new o.foo();", *source_line);
8545}
8546
8547
8548TEST(ExceptionInNativeScript) {
8549  LocalContext env;
8550  v8::Isolate* isolate = env->GetIsolate();
8551  v8::HandleScope scope(isolate);
8552  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8553
8554  Local<v8::FunctionTemplate> fun =
8555      v8::FunctionTemplate::New(isolate, TroubleCallback);
8556  v8::Local<v8::Object> global = env->Global();
8557  global->Set(v8_str("trouble"), fun->GetFunction());
8558
8559  CompileRunWithOrigin(
8560      "function trouble() {\n"
8561      "  var o = {};\n"
8562      "  new o.foo();\n"
8563      "};",
8564      script_resource_name);
8565  Local<Value> trouble = global->Get(v8_str("trouble"));
8566  CHECK(trouble->IsFunction());
8567  Function::Cast(*trouble)->Call(global, 0, NULL);
8568  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8569}
8570
8571
8572TEST(CompilationErrorUsingTryCatchHandler) {
8573  LocalContext env;
8574  v8::HandleScope scope(env->GetIsolate());
8575  v8::TryCatch try_catch;
8576  v8_compile("This doesn't &*&@#$&*^ compile.");
8577  CHECK_NE(NULL, *try_catch.Exception());
8578  CHECK(try_catch.HasCaught());
8579}
8580
8581
8582TEST(TryCatchFinallyUsingTryCatchHandler) {
8583  LocalContext env;
8584  v8::HandleScope scope(env->GetIsolate());
8585  v8::TryCatch try_catch;
8586  CompileRun("try { throw ''; } catch (e) {}");
8587  CHECK(!try_catch.HasCaught());
8588  CompileRun("try { throw ''; } finally {}");
8589  CHECK(try_catch.HasCaught());
8590  try_catch.Reset();
8591  CompileRun(
8592      "(function() {"
8593      "try { throw ''; } finally { return; }"
8594      "})()");
8595  CHECK(!try_catch.HasCaught());
8596  CompileRun(
8597      "(function()"
8598      "  { try { throw ''; } finally { throw 0; }"
8599      "})()");
8600  CHECK(try_catch.HasCaught());
8601}
8602
8603
8604void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
8605  v8::HandleScope scope(args.GetIsolate());
8606  CompileRun(args[0]->ToString());
8607}
8608
8609
8610TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
8611  v8::Isolate* isolate = CcTest::isolate();
8612  v8::HandleScope scope(isolate);
8613  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
8614  templ->Set(v8_str("CEvaluate"),
8615             v8::FunctionTemplate::New(isolate, CEvaluate));
8616  LocalContext context(0, templ);
8617  v8::TryCatch try_catch;
8618  CompileRun("try {"
8619             "  CEvaluate('throw 1;');"
8620             "} finally {"
8621             "}");
8622  CHECK(try_catch.HasCaught());
8623  CHECK(!try_catch.Message().IsEmpty());
8624  String::Utf8Value exception_value(try_catch.Exception());
8625  CHECK_EQ(*exception_value, "1");
8626  try_catch.Reset();
8627  CompileRun("try {"
8628             "  CEvaluate('throw 1;');"
8629             "} finally {"
8630             "  throw 2;"
8631             "}");
8632  CHECK(try_catch.HasCaught());
8633  CHECK(!try_catch.Message().IsEmpty());
8634  String::Utf8Value finally_exception_value(try_catch.Exception());
8635  CHECK_EQ(*finally_exception_value, "2");
8636}
8637
8638
8639// For use within the TestSecurityHandler() test.
8640static bool g_security_callback_result = false;
8641static bool NamedSecurityTestCallback(Local<v8::Object> global,
8642                                      Local<Value> name,
8643                                      v8::AccessType type,
8644                                      Local<Value> data) {
8645  printf("a\n");
8646  // Always allow read access.
8647  if (type == v8::ACCESS_GET)
8648    return true;
8649
8650  // Sometimes allow other access.
8651  return g_security_callback_result;
8652}
8653
8654
8655static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8656                                        uint32_t key,
8657                                        v8::AccessType type,
8658                                        Local<Value> data) {
8659  printf("b\n");
8660  // Always allow read access.
8661  if (type == v8::ACCESS_GET)
8662    return true;
8663
8664  // Sometimes allow other access.
8665  return g_security_callback_result;
8666}
8667
8668
8669// SecurityHandler can't be run twice
8670TEST(SecurityHandler) {
8671  v8::Isolate* isolate = CcTest::isolate();
8672  v8::HandleScope scope0(isolate);
8673  v8::Handle<v8::ObjectTemplate> global_template =
8674      v8::ObjectTemplate::New(isolate);
8675  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8676                                           IndexedSecurityTestCallback);
8677  // Create an environment
8678  v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8679  context0->Enter();
8680
8681  v8::Handle<v8::Object> global0 = context0->Global();
8682  v8::Handle<Script> script0 = v8_compile("foo = 111");
8683  script0->Run();
8684  global0->Set(v8_str("0"), v8_num(999));
8685  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8686  CHECK_EQ(111, foo0->Int32Value());
8687  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8688  CHECK_EQ(999, z0->Int32Value());
8689
8690  // Create another environment, should fail security checks.
8691  v8::HandleScope scope1(isolate);
8692
8693  v8::Handle<Context> context1 =
8694    Context::New(isolate, NULL, global_template);
8695  context1->Enter();
8696
8697  v8::Handle<v8::Object> global1 = context1->Global();
8698  global1->Set(v8_str("othercontext"), global0);
8699  // This set will fail the security check.
8700  v8::Handle<Script> script1 =
8701    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8702  script1->Run();
8703  // This read will pass the security check.
8704  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8705  CHECK_EQ(111, foo1->Int32Value());
8706  // This read will pass the security check.
8707  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8708  CHECK_EQ(999, z1->Int32Value());
8709
8710  // Create another environment, should pass security checks.
8711  { g_security_callback_result = true;  // allow security handler to pass.
8712    v8::HandleScope scope2(isolate);
8713    LocalContext context2;
8714    v8::Handle<v8::Object> global2 = context2->Global();
8715    global2->Set(v8_str("othercontext"), global0);
8716    v8::Handle<Script> script2 =
8717        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8718    script2->Run();
8719    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8720    CHECK_EQ(333, foo2->Int32Value());
8721    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8722    CHECK_EQ(888, z2->Int32Value());
8723  }
8724
8725  context1->Exit();
8726  context0->Exit();
8727}
8728
8729
8730THREADED_TEST(SecurityChecks) {
8731  LocalContext env1;
8732  v8::HandleScope handle_scope(env1->GetIsolate());
8733  v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8734
8735  Local<Value> foo = v8_str("foo");
8736  Local<Value> bar = v8_str("bar");
8737
8738  // Set to the same domain.
8739  env1->SetSecurityToken(foo);
8740
8741  // Create a function in env1.
8742  CompileRun("spy=function(){return spy;}");
8743  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8744  CHECK(spy->IsFunction());
8745
8746  // Create another function accessing global objects.
8747  CompileRun("spy2=function(){return new this.Array();}");
8748  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8749  CHECK(spy2->IsFunction());
8750
8751  // Switch to env2 in the same domain and invoke spy on env2.
8752  {
8753    env2->SetSecurityToken(foo);
8754    // Enter env2
8755    Context::Scope scope_env2(env2);
8756    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8757    CHECK(result->IsFunction());
8758  }
8759
8760  {
8761    env2->SetSecurityToken(bar);
8762    Context::Scope scope_env2(env2);
8763
8764    // Call cross_domain_call, it should throw an exception
8765    v8::TryCatch try_catch;
8766    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8767    CHECK(try_catch.HasCaught());
8768  }
8769}
8770
8771
8772// Regression test case for issue 1183439.
8773THREADED_TEST(SecurityChecksForPrototypeChain) {
8774  LocalContext current;
8775  v8::HandleScope scope(current->GetIsolate());
8776  v8::Handle<Context> other = Context::New(current->GetIsolate());
8777
8778  // Change context to be able to get to the Object function in the
8779  // other context without hitting the security checks.
8780  v8::Local<Value> other_object;
8781  { Context::Scope scope(other);
8782    other_object = other->Global()->Get(v8_str("Object"));
8783    other->Global()->Set(v8_num(42), v8_num(87));
8784  }
8785
8786  current->Global()->Set(v8_str("other"), other->Global());
8787  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8788
8789  // Make sure the security check fails here and we get an undefined
8790  // result instead of getting the Object function. Repeat in a loop
8791  // to make sure to exercise the IC code.
8792  v8::Local<Script> access_other0 = v8_compile("other.Object");
8793  v8::Local<Script> access_other1 = v8_compile("other[42]");
8794  for (int i = 0; i < 5; i++) {
8795    CHECK(access_other0->Run().IsEmpty());
8796    CHECK(access_other1->Run().IsEmpty());
8797  }
8798
8799  // Create an object that has 'other' in its prototype chain and make
8800  // sure we cannot access the Object function indirectly through
8801  // that. Repeat in a loop to make sure to exercise the IC code.
8802  v8_compile("function F() { };"
8803             "F.prototype = other;"
8804             "var f = new F();")->Run();
8805  v8::Local<Script> access_f0 = v8_compile("f.Object");
8806  v8::Local<Script> access_f1 = v8_compile("f[42]");
8807  for (int j = 0; j < 5; j++) {
8808    CHECK(access_f0->Run().IsEmpty());
8809    CHECK(access_f1->Run().IsEmpty());
8810  }
8811
8812  // Now it gets hairy: Set the prototype for the other global object
8813  // to be the current global object. The prototype chain for 'f' now
8814  // goes through 'other' but ends up in the current global object.
8815  { Context::Scope scope(other);
8816    other->Global()->Set(v8_str("__proto__"), current->Global());
8817  }
8818  // Set a named and an index property on the current global
8819  // object. To force the lookup to go through the other global object,
8820  // the properties must not exist in the other global object.
8821  current->Global()->Set(v8_str("foo"), v8_num(100));
8822  current->Global()->Set(v8_num(99), v8_num(101));
8823  // Try to read the properties from f and make sure that the access
8824  // gets stopped by the security checks on the other global object.
8825  Local<Script> access_f2 = v8_compile("f.foo");
8826  Local<Script> access_f3 = v8_compile("f[99]");
8827  for (int k = 0; k < 5; k++) {
8828    CHECK(access_f2->Run().IsEmpty());
8829    CHECK(access_f3->Run().IsEmpty());
8830  }
8831}
8832
8833
8834static bool named_security_check_with_gc_called;
8835
8836static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8837                                        Local<Value> name,
8838                                        v8::AccessType type,
8839                                        Local<Value> data) {
8840  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8841  named_security_check_with_gc_called = true;
8842  return true;
8843}
8844
8845
8846static bool indexed_security_check_with_gc_called;
8847
8848static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8849                                              uint32_t key,
8850                                              v8::AccessType type,
8851                                              Local<Value> data) {
8852  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8853  indexed_security_check_with_gc_called = true;
8854  return true;
8855}
8856
8857
8858TEST(SecurityTestGCAllowed) {
8859  v8::Isolate* isolate = CcTest::isolate();
8860  v8::HandleScope handle_scope(isolate);
8861  v8::Handle<v8::ObjectTemplate> object_template =
8862      v8::ObjectTemplate::New(isolate);
8863  object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8864                                           IndexedSecurityTestCallbackWithGC);
8865
8866  v8::Handle<Context> context = Context::New(isolate);
8867  v8::Context::Scope context_scope(context);
8868
8869  context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8870
8871  named_security_check_with_gc_called = false;
8872  CompileRun("obj.foo = new String(1001);");
8873  CHECK(named_security_check_with_gc_called);
8874
8875  indexed_security_check_with_gc_called = false;
8876  CompileRun("obj[0] = new String(1002);");
8877  CHECK(indexed_security_check_with_gc_called);
8878
8879  named_security_check_with_gc_called = false;
8880  CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8881  CHECK(named_security_check_with_gc_called);
8882
8883  indexed_security_check_with_gc_called = false;
8884  CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8885  CHECK(indexed_security_check_with_gc_called);
8886}
8887
8888
8889THREADED_TEST(CrossDomainDelete) {
8890  LocalContext env1;
8891  v8::HandleScope handle_scope(env1->GetIsolate());
8892  v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8893
8894  Local<Value> foo = v8_str("foo");
8895  Local<Value> bar = v8_str("bar");
8896
8897  // Set to the same domain.
8898  env1->SetSecurityToken(foo);
8899  env2->SetSecurityToken(foo);
8900
8901  env1->Global()->Set(v8_str("prop"), v8_num(3));
8902  env2->Global()->Set(v8_str("env1"), env1->Global());
8903
8904  // Change env2 to a different domain and delete env1.prop.
8905  env2->SetSecurityToken(bar);
8906  {
8907    Context::Scope scope_env2(env2);
8908    Local<Value> result =
8909        CompileRun("delete env1.prop");
8910    CHECK(result.IsEmpty());
8911  }
8912
8913  // Check that env1.prop still exists.
8914  Local<Value> v = env1->Global()->Get(v8_str("prop"));
8915  CHECK(v->IsNumber());
8916  CHECK_EQ(3, v->Int32Value());
8917}
8918
8919
8920THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8921  LocalContext env1;
8922  v8::HandleScope handle_scope(env1->GetIsolate());
8923  v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8924
8925  Local<Value> foo = v8_str("foo");
8926  Local<Value> bar = v8_str("bar");
8927
8928  // Set to the same domain.
8929  env1->SetSecurityToken(foo);
8930  env2->SetSecurityToken(foo);
8931
8932  env1->Global()->Set(v8_str("prop"), v8_num(3));
8933  env2->Global()->Set(v8_str("env1"), env1->Global());
8934
8935  // env1.prop is enumerable in env2.
8936  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8937  {
8938    Context::Scope scope_env2(env2);
8939    Local<Value> result = CompileRun(test);
8940    CHECK(result->IsTrue());
8941  }
8942
8943  // Change env2 to a different domain and test again.
8944  env2->SetSecurityToken(bar);
8945  {
8946    Context::Scope scope_env2(env2);
8947    Local<Value> result = CompileRun(test);
8948    CHECK(result.IsEmpty());
8949  }
8950}
8951
8952
8953THREADED_TEST(CrossDomainForIn) {
8954  LocalContext env1;
8955  v8::HandleScope handle_scope(env1->GetIsolate());
8956  v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8957
8958  Local<Value> foo = v8_str("foo");
8959  Local<Value> bar = v8_str("bar");
8960
8961  // Set to the same domain.
8962  env1->SetSecurityToken(foo);
8963  env2->SetSecurityToken(foo);
8964
8965  env1->Global()->Set(v8_str("prop"), v8_num(3));
8966  env2->Global()->Set(v8_str("env1"), env1->Global());
8967
8968  // Change env2 to a different domain and set env1's global object
8969  // as the __proto__ of an object in env2 and enumerate properties
8970  // in for-in. It shouldn't enumerate properties on env1's global
8971  // object.
8972  env2->SetSecurityToken(bar);
8973  {
8974    Context::Scope scope_env2(env2);
8975    Local<Value> result = CompileRun(
8976        "(function() {"
8977        "  var obj = { '__proto__': env1 };"
8978        "  try {"
8979        "    for (var p in obj) {"
8980        "      if (p == 'prop') return false;"
8981        "    }"
8982        "    return false;"
8983        "  } catch (e) {"
8984        "    return true;"
8985        "  }"
8986        "})()");
8987    CHECK(result->IsTrue());
8988  }
8989}
8990
8991
8992TEST(ContextDetachGlobal) {
8993  LocalContext env1;
8994  v8::HandleScope handle_scope(env1->GetIsolate());
8995  v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8996
8997  Local<v8::Object> global1 = env1->Global();
8998
8999  Local<Value> foo = v8_str("foo");
9000
9001  // Set to the same domain.
9002  env1->SetSecurityToken(foo);
9003  env2->SetSecurityToken(foo);
9004
9005  // Enter env2
9006  env2->Enter();
9007
9008  // Create a function in env2 and add a reference to it in env1.
9009  Local<v8::Object> global2 = env2->Global();
9010  global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
9011  CompileRun("function getProp() {return prop;}");
9012
9013  env1->Global()->Set(v8_str("getProp"),
9014                      global2->Get(v8_str("getProp")));
9015
9016  // Detach env2's global, and reuse the global object of env2
9017  env2->Exit();
9018  env2->DetachGlobal();
9019
9020  v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9021                                          0,
9022                                          v8::Handle<v8::ObjectTemplate>(),
9023                                          global2);
9024  env3->SetSecurityToken(v8_str("bar"));
9025  env3->Enter();
9026
9027  Local<v8::Object> global3 = env3->Global();
9028  CHECK_EQ(global2, global3);
9029  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
9030  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
9031  global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
9032  global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
9033  env3->Exit();
9034
9035  // Call getProp in env1, and it should return the value 1
9036  {
9037    Local<Value> get_prop = global1->Get(v8_str("getProp"));
9038    CHECK(get_prop->IsFunction());
9039    v8::TryCatch try_catch;
9040    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
9041    CHECK(!try_catch.HasCaught());
9042    CHECK_EQ(1, r->Int32Value());
9043  }
9044
9045  // Check that env3 is not accessible from env1
9046  {
9047    Local<Value> r = global3->Get(v8_str("prop2"));
9048    CHECK(r.IsEmpty());
9049  }
9050}
9051
9052
9053TEST(DetachGlobal) {
9054  LocalContext env1;
9055  v8::HandleScope scope(env1->GetIsolate());
9056
9057  // Create second environment.
9058  v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9059
9060  Local<Value> foo = v8_str("foo");
9061
9062  // Set same security token for env1 and env2.
9063  env1->SetSecurityToken(foo);
9064  env2->SetSecurityToken(foo);
9065
9066  // Create a property on the global object in env2.
9067  {
9068    v8::Context::Scope scope(env2);
9069    env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
9070  }
9071
9072  // Create a reference to env2 global from env1 global.
9073  env1->Global()->Set(v8_str("other"), env2->Global());
9074
9075  // Check that we have access to other.p in env2 from env1.
9076  Local<Value> result = CompileRun("other.p");
9077  CHECK(result->IsInt32());
9078  CHECK_EQ(42, result->Int32Value());
9079
9080  // Hold on to global from env2 and detach global from env2.
9081  Local<v8::Object> global2 = env2->Global();
9082  env2->DetachGlobal();
9083
9084  // Check that the global has been detached. No other.p property can
9085  // be found.
9086  result = CompileRun("other.p");
9087  CHECK(result.IsEmpty());
9088
9089  // Reuse global2 for env3.
9090  v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9091                                          0,
9092                                          v8::Handle<v8::ObjectTemplate>(),
9093                                          global2);
9094  CHECK_EQ(global2, env3->Global());
9095
9096  // Start by using the same security token for env3 as for env1 and env2.
9097  env3->SetSecurityToken(foo);
9098
9099  // Create a property on the global object in env3.
9100  {
9101    v8::Context::Scope scope(env3);
9102    env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
9103  }
9104
9105  // Check that other.p is now the property in env3 and that we have access.
9106  result = CompileRun("other.p");
9107  CHECK(result->IsInt32());
9108  CHECK_EQ(24, result->Int32Value());
9109
9110  // Change security token for env3 to something different from env1 and env2.
9111  env3->SetSecurityToken(v8_str("bar"));
9112
9113  // Check that we do not have access to other.p in env1. |other| is now
9114  // the global object for env3 which has a different security token,
9115  // so access should be blocked.
9116  result = CompileRun("other.p");
9117  CHECK(result.IsEmpty());
9118}
9119
9120
9121void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9122  info.GetReturnValue().Set(
9123      info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
9124}
9125
9126
9127TEST(DetachedAccesses) {
9128  LocalContext env1;
9129  v8::HandleScope scope(env1->GetIsolate());
9130
9131  // Create second environment.
9132  Local<ObjectTemplate> inner_global_template =
9133      FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9134  inner_global_template ->SetAccessorProperty(
9135      v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9136  v8::Local<Context> env2 =
9137      Context::New(env1->GetIsolate(), NULL, inner_global_template);
9138
9139  Local<Value> foo = v8_str("foo");
9140
9141  // Set same security token for env1 and env2.
9142  env1->SetSecurityToken(foo);
9143  env2->SetSecurityToken(foo);
9144
9145  env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
9146
9147  {
9148    v8::Context::Scope scope(env2);
9149    env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
9150    CompileRun(
9151        "function bound_x() { return x; }"
9152        "function get_x()   { return this.x; }"
9153        "function get_x_w() { return (function() {return this.x;})(); }");
9154    env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
9155    env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
9156    env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
9157    env1->Global()->Set(
9158        v8_str("this_x"),
9159        CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
9160  }
9161
9162  Local<Object> env2_global = env2->Global();
9163  env2_global->TurnOnAccessCheck();
9164  env2->DetachGlobal();
9165
9166  Local<Value> result;
9167  result = CompileRun("bound_x()");
9168  CHECK_EQ(v8_str("env2_x"), result);
9169  result = CompileRun("get_x()");
9170  CHECK(result.IsEmpty());
9171  result = CompileRun("get_x_w()");
9172  CHECK(result.IsEmpty());
9173  result = CompileRun("this_x()");
9174  CHECK_EQ(v8_str("env2_x"), result);
9175
9176  // Reattach env2's proxy
9177  env2 = Context::New(env1->GetIsolate(),
9178                      0,
9179                      v8::Handle<v8::ObjectTemplate>(),
9180                      env2_global);
9181  env2->SetSecurityToken(foo);
9182  {
9183    v8::Context::Scope scope(env2);
9184    env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
9185    env2->Global()->Set(v8_str("env1"), env1->Global());
9186    result = CompileRun(
9187        "results = [];"
9188        "for (var i = 0; i < 4; i++ ) {"
9189        "  results.push(env1.bound_x());"
9190        "  results.push(env1.get_x());"
9191        "  results.push(env1.get_x_w());"
9192        "  results.push(env1.this_x());"
9193        "}"
9194        "results");
9195    Local<v8::Array> results = Local<v8::Array>::Cast(result);
9196    CHECK_EQ(16, results->Length());
9197    for (int i = 0; i < 16; i += 4) {
9198      CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9199      CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9200      CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9201      CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9202    }
9203  }
9204
9205  result = CompileRun(
9206      "results = [];"
9207      "for (var i = 0; i < 4; i++ ) {"
9208      "  results.push(bound_x());"
9209      "  results.push(get_x());"
9210      "  results.push(get_x_w());"
9211      "  results.push(this_x());"
9212      "}"
9213      "results");
9214  Local<v8::Array> results = Local<v8::Array>::Cast(result);
9215  CHECK_EQ(16, results->Length());
9216  for (int i = 0; i < 16; i += 4) {
9217    CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9218    CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
9219    CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9220    CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9221  }
9222
9223  result = CompileRun(
9224      "results = [];"
9225      "for (var i = 0; i < 4; i++ ) {"
9226      "  results.push(this.bound_x());"
9227      "  results.push(this.get_x());"
9228      "  results.push(this.get_x_w());"
9229      "  results.push(this.this_x());"
9230      "}"
9231      "results");
9232  results = Local<v8::Array>::Cast(result);
9233  CHECK_EQ(16, results->Length());
9234  for (int i = 0; i < 16; i += 4) {
9235    CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9236    CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9237    CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9238    CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9239  }
9240}
9241
9242
9243static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9244static bool NamedAccessBlocker(Local<v8::Object> global,
9245                               Local<Value> name,
9246                               v8::AccessType type,
9247                               Local<Value> data) {
9248  return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9249      allowed_access_type[type];
9250}
9251
9252
9253static bool IndexedAccessBlocker(Local<v8::Object> global,
9254                                 uint32_t key,
9255                                 v8::AccessType type,
9256                                 Local<Value> data) {
9257  return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9258      allowed_access_type[type];
9259}
9260
9261
9262static int g_echo_value = -1;
9263
9264
9265static void EchoGetter(
9266    Local<String> name,
9267    const v8::PropertyCallbackInfo<v8::Value>& info) {
9268  info.GetReturnValue().Set(v8_num(g_echo_value));
9269}
9270
9271
9272static void EchoSetter(Local<String> name,
9273                       Local<Value> value,
9274                       const v8::PropertyCallbackInfo<void>&) {
9275  if (value->IsNumber())
9276    g_echo_value = value->Int32Value();
9277}
9278
9279
9280static void UnreachableGetter(
9281    Local<String> name,
9282    const v8::PropertyCallbackInfo<v8::Value>& info) {
9283  CHECK(false);  // This function should not be called..
9284}
9285
9286
9287static void UnreachableSetter(Local<String>,
9288                              Local<Value>,
9289                              const v8::PropertyCallbackInfo<void>&) {
9290  CHECK(false);  // This function should nto be called.
9291}
9292
9293
9294static void UnreachableFunction(
9295    const v8::FunctionCallbackInfo<v8::Value>& info) {
9296  CHECK(false);  // This function should not be called..
9297}
9298
9299
9300TEST(AccessControl) {
9301  v8::Isolate* isolate = CcTest::isolate();
9302  v8::HandleScope handle_scope(isolate);
9303  v8::Handle<v8::ObjectTemplate> global_template =
9304      v8::ObjectTemplate::New(isolate);
9305
9306  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9307                                           IndexedAccessBlocker);
9308
9309  // Add an accessor accessible by cross-domain JS code.
9310  global_template->SetAccessor(
9311      v8_str("accessible_prop"),
9312      EchoGetter, EchoSetter,
9313      v8::Handle<Value>(),
9314      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9315
9316
9317  // Add an accessor that is not accessible by cross-domain JS code.
9318  global_template->SetAccessor(v8_str("blocked_prop"),
9319                               UnreachableGetter, UnreachableSetter,
9320                               v8::Handle<Value>(),
9321                               v8::DEFAULT);
9322
9323  global_template->SetAccessorProperty(
9324      v8_str("blocked_js_prop"),
9325      v8::FunctionTemplate::New(isolate, UnreachableFunction),
9326      v8::FunctionTemplate::New(isolate, UnreachableFunction),
9327      v8::None,
9328      v8::DEFAULT);
9329
9330  // Create an environment
9331  v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9332  context0->Enter();
9333
9334  v8::Handle<v8::Object> global0 = context0->Global();
9335
9336  // Define a property with JS getter and setter.
9337  CompileRun(
9338      "function getter() { return 'getter'; };\n"
9339      "function setter() { return 'setter'; }\n"
9340      "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9341
9342  Local<Value> getter = global0->Get(v8_str("getter"));
9343  Local<Value> setter = global0->Get(v8_str("setter"));
9344
9345  // And define normal element.
9346  global0->Set(239, v8_str("239"));
9347
9348  // Define an element with JS getter and setter.
9349  CompileRun(
9350      "function el_getter() { return 'el_getter'; };\n"
9351      "function el_setter() { return 'el_setter'; };\n"
9352      "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9353
9354  Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9355  Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9356
9357  v8::HandleScope scope1(isolate);
9358
9359  v8::Local<Context> context1 = Context::New(isolate);
9360  context1->Enter();
9361
9362  v8::Handle<v8::Object> global1 = context1->Global();
9363  global1->Set(v8_str("other"), global0);
9364
9365  // Access blocked property.
9366  CompileRun("other.blocked_prop = 1");
9367
9368  CHECK(CompileRun("other.blocked_prop").IsEmpty());
9369  CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9370            .IsEmpty());
9371  CHECK(
9372      CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
9373
9374  // Access blocked element.
9375  CHECK(CompileRun("other[239] = 1").IsEmpty());
9376
9377  CHECK(CompileRun("other[239]").IsEmpty());
9378  CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
9379  CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
9380
9381  // Enable ACCESS_HAS
9382  allowed_access_type[v8::ACCESS_HAS] = true;
9383  CHECK(CompileRun("other[239]").IsEmpty());
9384  // ... and now we can get the descriptor...
9385  CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
9386            .IsEmpty());
9387  // ... and enumerate the property.
9388  ExpectTrue("propertyIsEnumerable.call(other, '239')");
9389  allowed_access_type[v8::ACCESS_HAS] = false;
9390
9391  // Access a property with JS accessor.
9392  CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
9393
9394  CHECK(CompileRun("other.js_accessor_p").IsEmpty());
9395  CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
9396            .IsEmpty());
9397
9398  // Enable both ACCESS_HAS and ACCESS_GET.
9399  allowed_access_type[v8::ACCESS_HAS] = true;
9400  allowed_access_type[v8::ACCESS_GET] = true;
9401
9402  ExpectString("other.js_accessor_p", "getter");
9403  ExpectObject(
9404      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9405  ExpectObject(
9406      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9407  ExpectUndefined(
9408      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9409
9410  allowed_access_type[v8::ACCESS_HAS] = false;
9411  allowed_access_type[v8::ACCESS_GET] = false;
9412
9413  // Access an element with JS accessor.
9414  CHECK(CompileRun("other[42] = 2").IsEmpty());
9415
9416  CHECK(CompileRun("other[42]").IsEmpty());
9417  CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
9418
9419  // Enable both ACCESS_HAS and ACCESS_GET.
9420  allowed_access_type[v8::ACCESS_HAS] = true;
9421  allowed_access_type[v8::ACCESS_GET] = true;
9422
9423  ExpectString("other[42]", "el_getter");
9424  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9425  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9426  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9427
9428  allowed_access_type[v8::ACCESS_HAS] = false;
9429  allowed_access_type[v8::ACCESS_GET] = false;
9430
9431  v8::Handle<Value> value;
9432
9433  // Access accessible property
9434  value = CompileRun("other.accessible_prop = 3");
9435  CHECK(value->IsNumber());
9436  CHECK_EQ(3, value->Int32Value());
9437  CHECK_EQ(3, g_echo_value);
9438
9439  value = CompileRun("other.accessible_prop");
9440  CHECK(value->IsNumber());
9441  CHECK_EQ(3, value->Int32Value());
9442
9443  value = CompileRun(
9444      "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9445  CHECK(value->IsNumber());
9446  CHECK_EQ(3, value->Int32Value());
9447
9448  value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9449  CHECK(value->IsTrue());
9450
9451  // Enumeration doesn't enumerate accessors from inaccessible objects in
9452  // the prototype chain even if the accessors are in themselves accessible.
9453  value = CompileRun(
9454      "(function() {"
9455      "  var obj = { '__proto__': other };"
9456      "  try {"
9457      "    for (var p in obj) {"
9458      "      if (p == 'accessible_prop' ||"
9459      "          p == 'blocked_js_prop' ||"
9460      "          p == 'blocked_js_prop') {"
9461      "        return false;"
9462      "      }"
9463      "    }"
9464      "    return false;"
9465      "  } catch (e) {"
9466      "    return true;"
9467      "  }"
9468      "})()");
9469  CHECK(value->IsTrue());
9470
9471  context1->Exit();
9472  context0->Exit();
9473}
9474
9475
9476TEST(AccessControlES5) {
9477  v8::Isolate* isolate = CcTest::isolate();
9478  v8::HandleScope handle_scope(isolate);
9479  v8::Handle<v8::ObjectTemplate> global_template =
9480      v8::ObjectTemplate::New(isolate);
9481
9482  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9483                                           IndexedAccessBlocker);
9484
9485  // Add accessible accessor.
9486  global_template->SetAccessor(
9487      v8_str("accessible_prop"),
9488      EchoGetter, EchoSetter,
9489      v8::Handle<Value>(),
9490      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9491
9492
9493  // Add an accessor that is not accessible by cross-domain JS code.
9494  global_template->SetAccessor(v8_str("blocked_prop"),
9495                               UnreachableGetter, UnreachableSetter,
9496                               v8::Handle<Value>(),
9497                               v8::DEFAULT);
9498
9499  // Create an environment
9500  v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9501  context0->Enter();
9502
9503  v8::Handle<v8::Object> global0 = context0->Global();
9504
9505  v8::Local<Context> context1 = Context::New(isolate);
9506  context1->Enter();
9507  v8::Handle<v8::Object> global1 = context1->Global();
9508  global1->Set(v8_str("other"), global0);
9509
9510  // Regression test for issue 1154.
9511  CHECK(CompileRun("Object.keys(other)").IsEmpty());
9512  CHECK(CompileRun("other.blocked_prop").IsEmpty());
9513
9514  // Regression test for issue 1027.
9515  CompileRun("Object.defineProperty(\n"
9516             "  other, 'blocked_prop', {configurable: false})");
9517  CHECK(CompileRun("other.blocked_prop").IsEmpty());
9518  CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9519            .IsEmpty());
9520
9521  // Regression test for issue 1171.
9522  ExpectTrue("Object.isExtensible(other)");
9523  CompileRun("Object.preventExtensions(other)");
9524  ExpectTrue("Object.isExtensible(other)");
9525
9526  // Object.seal and Object.freeze.
9527  CompileRun("Object.freeze(other)");
9528  ExpectTrue("Object.isExtensible(other)");
9529
9530  CompileRun("Object.seal(other)");
9531  ExpectTrue("Object.isExtensible(other)");
9532
9533  // Regression test for issue 1250.
9534  // Make sure that we can set the accessible accessors value using normal
9535  // assignment.
9536  CompileRun("other.accessible_prop = 42");
9537  CHECK_EQ(42, g_echo_value);
9538
9539  v8::Handle<Value> value;
9540  CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9541  value = CompileRun("other.accessible_prop == 42");
9542  CHECK(value->IsTrue());
9543}
9544
9545
9546static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
9547                                 v8::AccessType type, Local<Value> data) {
9548  return false;
9549}
9550
9551
9552static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
9553                                   v8::AccessType type, Local<Value> data) {
9554  return false;
9555}
9556
9557
9558THREADED_TEST(AccessControlGetOwnPropertyNames) {
9559  v8::Isolate* isolate = CcTest::isolate();
9560  v8::HandleScope handle_scope(isolate);
9561  v8::Handle<v8::ObjectTemplate> obj_template =
9562      v8::ObjectTemplate::New(isolate);
9563
9564  obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9565  obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9566                                        BlockEverythingIndexed);
9567
9568  // Create an environment
9569  v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9570  context0->Enter();
9571
9572  v8::Handle<v8::Object> global0 = context0->Global();
9573
9574  v8::HandleScope scope1(CcTest::isolate());
9575
9576  v8::Local<Context> context1 = Context::New(isolate);
9577  context1->Enter();
9578
9579  v8::Handle<v8::Object> global1 = context1->Global();
9580  global1->Set(v8_str("other"), global0);
9581  global1->Set(v8_str("object"), obj_template->NewInstance());
9582
9583  v8::Handle<Value> value;
9584
9585  // Attempt to get the property names of the other global object and
9586  // of an object that requires access checks.  Accessing the other
9587  // global object should be blocked by access checks on the global
9588  // proxy object.  Accessing the object that requires access checks
9589  // is blocked by the access checks on the object itself.
9590  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9591  CHECK(value.IsEmpty());
9592
9593  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9594  CHECK(value.IsEmpty());
9595
9596  context1->Exit();
9597  context0->Exit();
9598}
9599
9600
9601TEST(SuperAccessControl) {
9602  i::FLAG_harmony_classes = true;
9603  v8::Isolate* isolate = CcTest::isolate();
9604  v8::HandleScope handle_scope(isolate);
9605  v8::Handle<v8::ObjectTemplate> obj_template =
9606      v8::ObjectTemplate::New(isolate);
9607  obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9608                                        BlockEverythingIndexed);
9609  LocalContext env;
9610  env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
9611
9612  v8::TryCatch try_catch;
9613  CompileRun(
9614      "function f() { return super.hasOwnProperty; };"
9615      "var m = f.toMethod(prohibited);"
9616      "m();");
9617  CHECK(try_catch.HasCaught());
9618}
9619
9620
9621static void IndexedPropertyEnumerator(
9622    const v8::PropertyCallbackInfo<v8::Array>& info) {
9623  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9624  result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9625  result->Set(1, v8::Object::New(info.GetIsolate()));
9626  info.GetReturnValue().Set(result);
9627}
9628
9629
9630static void NamedPropertyEnumerator(
9631    const v8::PropertyCallbackInfo<v8::Array>& info) {
9632  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9633  result->Set(0, v8_str("x"));
9634  result->Set(1, v8::Object::New(info.GetIsolate()));
9635  info.GetReturnValue().Set(result);
9636}
9637
9638
9639THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9640  v8::Isolate* isolate = CcTest::isolate();
9641  v8::HandleScope handle_scope(isolate);
9642  v8::Handle<v8::ObjectTemplate> obj_template =
9643      v8::ObjectTemplate::New(isolate);
9644
9645  obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9646  obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9647  obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9648                                          IndexedPropertyEnumerator);
9649  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9650                                        NamedPropertyEnumerator);
9651
9652  LocalContext context;
9653  v8::Handle<v8::Object> global = context->Global();
9654  global->Set(v8_str("object"), obj_template->NewInstance());
9655
9656  v8::Handle<v8::Value> result =
9657      CompileRun("Object.getOwnPropertyNames(object)");
9658  CHECK(result->IsArray());
9659  v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9660  CHECK_EQ(3, result_array->Length());
9661  CHECK(result_array->Get(0)->IsString());
9662  CHECK(result_array->Get(1)->IsString());
9663  CHECK(result_array->Get(2)->IsString());
9664  CHECK_EQ(v8_str("7"), result_array->Get(0));
9665  CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9666  CHECK_EQ(v8_str("x"), result_array->Get(2));
9667}
9668
9669
9670static void ConstTenGetter(Local<String> name,
9671                           const v8::PropertyCallbackInfo<v8::Value>& info) {
9672  info.GetReturnValue().Set(v8_num(10));
9673}
9674
9675
9676THREADED_TEST(CrossDomainAccessors) {
9677  v8::Isolate* isolate = CcTest::isolate();
9678  v8::HandleScope handle_scope(isolate);
9679
9680  v8::Handle<v8::FunctionTemplate> func_template =
9681      v8::FunctionTemplate::New(isolate);
9682
9683  v8::Handle<v8::ObjectTemplate> global_template =
9684      func_template->InstanceTemplate();
9685
9686  v8::Handle<v8::ObjectTemplate> proto_template =
9687      func_template->PrototypeTemplate();
9688
9689  // Add an accessor to proto that's accessible by cross-domain JS code.
9690  proto_template->SetAccessor(v8_str("accessible"),
9691                              ConstTenGetter, 0,
9692                              v8::Handle<Value>(),
9693                              v8::ALL_CAN_READ);
9694
9695  // Add an accessor that is not accessible by cross-domain JS code.
9696  global_template->SetAccessor(v8_str("unreachable"),
9697                               UnreachableGetter, 0,
9698                               v8::Handle<Value>(),
9699                               v8::DEFAULT);
9700
9701  v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9702  context0->Enter();
9703
9704  Local<v8::Object> global = context0->Global();
9705  // Add a normal property that shadows 'accessible'
9706  global->Set(v8_str("accessible"), v8_num(11));
9707
9708  // Enter a new context.
9709  v8::HandleScope scope1(CcTest::isolate());
9710  v8::Local<Context> context1 = Context::New(isolate);
9711  context1->Enter();
9712
9713  v8::Handle<v8::Object> global1 = context1->Global();
9714  global1->Set(v8_str("other"), global);
9715
9716  // Should return 10, instead of 11
9717  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9718  CHECK(value->IsNumber());
9719  CHECK_EQ(10, value->Int32Value());
9720
9721  value = v8_compile("other.unreachable")->Run();
9722  CHECK(value.IsEmpty());
9723
9724  context1->Exit();
9725  context0->Exit();
9726}
9727
9728
9729static int named_access_count = 0;
9730static int indexed_access_count = 0;
9731
9732static bool NamedAccessCounter(Local<v8::Object> global,
9733                               Local<Value> name,
9734                               v8::AccessType type,
9735                               Local<Value> data) {
9736  named_access_count++;
9737  return true;
9738}
9739
9740
9741static bool IndexedAccessCounter(Local<v8::Object> global,
9742                                 uint32_t key,
9743                                 v8::AccessType type,
9744                                 Local<Value> data) {
9745  indexed_access_count++;
9746  return true;
9747}
9748
9749
9750// This one is too easily disturbed by other tests.
9751TEST(AccessControlIC) {
9752  named_access_count = 0;
9753  indexed_access_count = 0;
9754
9755  v8::Isolate* isolate = CcTest::isolate();
9756  v8::HandleScope handle_scope(isolate);
9757
9758  // Create an environment.
9759  v8::Local<Context> context0 = Context::New(isolate);
9760  context0->Enter();
9761
9762  // Create an object that requires access-check functions to be
9763  // called for cross-domain access.
9764  v8::Handle<v8::ObjectTemplate> object_template =
9765      v8::ObjectTemplate::New(isolate);
9766  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9767                                           IndexedAccessCounter);
9768  Local<v8::Object> object = object_template->NewInstance();
9769
9770  v8::HandleScope scope1(isolate);
9771
9772  // Create another environment.
9773  v8::Local<Context> context1 = Context::New(isolate);
9774  context1->Enter();
9775
9776  // Make easy access to the object from the other environment.
9777  v8::Handle<v8::Object> global1 = context1->Global();
9778  global1->Set(v8_str("obj"), object);
9779
9780  v8::Handle<Value> value;
9781
9782  // Check that the named access-control function is called every time.
9783  CompileRun("function testProp(obj) {"
9784             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
9785             "  for (var j = 0; j < 10; j++) obj.prop;"
9786             "  return obj.prop"
9787             "}");
9788  value = CompileRun("testProp(obj)");
9789  CHECK(value->IsNumber());
9790  CHECK_EQ(1, value->Int32Value());
9791  CHECK_EQ(21, named_access_count);
9792
9793  // Check that the named access-control function is called every time.
9794  CompileRun("var p = 'prop';"
9795             "function testKeyed(obj) {"
9796             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
9797             "  for (var j = 0; j < 10; j++) obj[p];"
9798             "  return obj[p];"
9799             "}");
9800  // Use obj which requires access checks.  No inline caching is used
9801  // in that case.
9802  value = CompileRun("testKeyed(obj)");
9803  CHECK(value->IsNumber());
9804  CHECK_EQ(1, value->Int32Value());
9805  CHECK_EQ(42, named_access_count);
9806  // Force the inline caches into generic state and try again.
9807  CompileRun("testKeyed({ a: 0 })");
9808  CompileRun("testKeyed({ b: 0 })");
9809  value = CompileRun("testKeyed(obj)");
9810  CHECK(value->IsNumber());
9811  CHECK_EQ(1, value->Int32Value());
9812  CHECK_EQ(63, named_access_count);
9813
9814  // Check that the indexed access-control function is called every time.
9815  CompileRun("function testIndexed(obj) {"
9816             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
9817             "  for (var j = 0; j < 10; j++) obj[0];"
9818             "  return obj[0]"
9819             "}");
9820  value = CompileRun("testIndexed(obj)");
9821  CHECK(value->IsNumber());
9822  CHECK_EQ(1, value->Int32Value());
9823  CHECK_EQ(21, indexed_access_count);
9824  // Force the inline caches into generic state.
9825  CompileRun("testIndexed(new Array(1))");
9826  // Test that the indexed access check is called.
9827  value = CompileRun("testIndexed(obj)");
9828  CHECK(value->IsNumber());
9829  CHECK_EQ(1, value->Int32Value());
9830  CHECK_EQ(42, indexed_access_count);
9831
9832  // Check that the named access check is called when invoking
9833  // functions on an object that requires access checks.
9834  CompileRun("obj.f = function() {}");
9835  CompileRun("function testCallNormal(obj) {"
9836             "  for (var i = 0; i < 10; i++) obj.f();"
9837             "}");
9838  CompileRun("testCallNormal(obj)");
9839  CHECK_EQ(74, named_access_count);
9840
9841  // Force obj into slow case.
9842  value = CompileRun("delete obj.prop");
9843  CHECK(value->BooleanValue());
9844  // Force inline caches into dictionary probing mode.
9845  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9846  // Test that the named access check is called.
9847  value = CompileRun("testProp(obj);");
9848  CHECK(value->IsNumber());
9849  CHECK_EQ(1, value->Int32Value());
9850  CHECK_EQ(96, named_access_count);
9851
9852  // Force the call inline cache into dictionary probing mode.
9853  CompileRun("o.f = function() {}; testCallNormal(o)");
9854  // Test that the named access check is still called for each
9855  // invocation of the function.
9856  value = CompileRun("testCallNormal(obj)");
9857  CHECK_EQ(106, named_access_count);
9858
9859  context1->Exit();
9860  context0->Exit();
9861}
9862
9863
9864static bool NamedAccessFlatten(Local<v8::Object> global,
9865                               Local<Value> name,
9866                               v8::AccessType type,
9867                               Local<Value> data) {
9868  char buf[100];
9869  int len;
9870
9871  CHECK(name->IsString());
9872
9873  memset(buf, 0x1, sizeof(buf));
9874  len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9875  CHECK_EQ(4, len);
9876
9877  uint16_t buf2[100];
9878
9879  memset(buf, 0x1, sizeof(buf));
9880  len = name.As<String>()->Write(buf2);
9881  CHECK_EQ(4, len);
9882
9883  return true;
9884}
9885
9886
9887static bool IndexedAccessFlatten(Local<v8::Object> global,
9888                                 uint32_t key,
9889                                 v8::AccessType type,
9890                                 Local<Value> data) {
9891  return true;
9892}
9893
9894
9895// Regression test.  In access checks, operations that may cause
9896// garbage collection are not allowed.  It used to be the case that
9897// using the Write operation on a string could cause a garbage
9898// collection due to flattening of the string.  This is no longer the
9899// case.
9900THREADED_TEST(AccessControlFlatten) {
9901  named_access_count = 0;
9902  indexed_access_count = 0;
9903
9904  v8::Isolate* isolate = CcTest::isolate();
9905  v8::HandleScope handle_scope(isolate);
9906
9907  // Create an environment.
9908  v8::Local<Context> context0 = Context::New(isolate);
9909  context0->Enter();
9910
9911  // Create an object that requires access-check functions to be
9912  // called for cross-domain access.
9913  v8::Handle<v8::ObjectTemplate> object_template =
9914      v8::ObjectTemplate::New(isolate);
9915  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9916                                           IndexedAccessFlatten);
9917  Local<v8::Object> object = object_template->NewInstance();
9918
9919  v8::HandleScope scope1(isolate);
9920
9921  // Create another environment.
9922  v8::Local<Context> context1 = Context::New(isolate);
9923  context1->Enter();
9924
9925  // Make easy access to the object from the other environment.
9926  v8::Handle<v8::Object> global1 = context1->Global();
9927  global1->Set(v8_str("obj"), object);
9928
9929  v8::Handle<Value> value;
9930
9931  value = v8_compile("var p = 'as' + 'df';")->Run();
9932  value = v8_compile("obj[p];")->Run();
9933
9934  context1->Exit();
9935  context0->Exit();
9936}
9937
9938
9939static void AccessControlNamedGetter(
9940    Local<String>,
9941    const v8::PropertyCallbackInfo<v8::Value>& info) {
9942  info.GetReturnValue().Set(42);
9943}
9944
9945
9946static void AccessControlNamedSetter(
9947    Local<String>,
9948    Local<Value> value,
9949    const v8::PropertyCallbackInfo<v8::Value>& info) {
9950  info.GetReturnValue().Set(value);
9951}
9952
9953
9954static void AccessControlIndexedGetter(
9955      uint32_t index,
9956      const v8::PropertyCallbackInfo<v8::Value>& info) {
9957  info.GetReturnValue().Set(v8_num(42));
9958}
9959
9960
9961static void AccessControlIndexedSetter(
9962    uint32_t,
9963    Local<Value> value,
9964    const v8::PropertyCallbackInfo<v8::Value>& info) {
9965  info.GetReturnValue().Set(value);
9966}
9967
9968
9969THREADED_TEST(AccessControlInterceptorIC) {
9970  named_access_count = 0;
9971  indexed_access_count = 0;
9972
9973  v8::Isolate* isolate = CcTest::isolate();
9974  v8::HandleScope handle_scope(isolate);
9975
9976  // Create an environment.
9977  v8::Local<Context> context0 = Context::New(isolate);
9978  context0->Enter();
9979
9980  // Create an object that requires access-check functions to be
9981  // called for cross-domain access.  The object also has interceptors
9982  // interceptor.
9983  v8::Handle<v8::ObjectTemplate> object_template =
9984      v8::ObjectTemplate::New(isolate);
9985  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9986                                           IndexedAccessCounter);
9987  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9988                                           AccessControlNamedSetter);
9989  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9990                                             AccessControlIndexedSetter);
9991  Local<v8::Object> object = object_template->NewInstance();
9992
9993  v8::HandleScope scope1(isolate);
9994
9995  // Create another environment.
9996  v8::Local<Context> context1 = Context::New(isolate);
9997  context1->Enter();
9998
9999  // Make easy access to the object from the other environment.
10000  v8::Handle<v8::Object> global1 = context1->Global();
10001  global1->Set(v8_str("obj"), object);
10002
10003  v8::Handle<Value> value;
10004
10005  // Check that the named access-control function is called every time
10006  // eventhough there is an interceptor on the object.
10007  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
10008  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
10009                     "obj.x")->Run();
10010  CHECK(value->IsNumber());
10011  CHECK_EQ(42, value->Int32Value());
10012  CHECK_EQ(21, named_access_count);
10013
10014  value = v8_compile("var p = 'x';")->Run();
10015  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
10016  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
10017                     "obj[p]")->Run();
10018  CHECK(value->IsNumber());
10019  CHECK_EQ(42, value->Int32Value());
10020  CHECK_EQ(42, named_access_count);
10021
10022  // Check that the indexed access-control function is called every
10023  // time eventhough there is an interceptor on the object.
10024  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
10025  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
10026                     "obj[0]")->Run();
10027  CHECK(value->IsNumber());
10028  CHECK_EQ(42, value->Int32Value());
10029  CHECK_EQ(21, indexed_access_count);
10030
10031  context1->Exit();
10032  context0->Exit();
10033}
10034
10035
10036THREADED_TEST(Version) {
10037  v8::V8::GetVersion();
10038}
10039
10040
10041static void InstanceFunctionCallback(
10042    const v8::FunctionCallbackInfo<v8::Value>& args) {
10043  ApiTestFuzzer::Fuzz();
10044  args.GetReturnValue().Set(v8_num(12));
10045}
10046
10047
10048THREADED_TEST(InstanceProperties) {
10049  LocalContext context;
10050  v8::Isolate* isolate = context->GetIsolate();
10051  v8::HandleScope handle_scope(isolate);
10052
10053  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10054  Local<ObjectTemplate> instance = t->InstanceTemplate();
10055
10056  instance->Set(v8_str("x"), v8_num(42));
10057  instance->Set(v8_str("f"),
10058                v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10059
10060  Local<Value> o = t->GetFunction()->NewInstance();
10061
10062  context->Global()->Set(v8_str("i"), o);
10063  Local<Value> value = CompileRun("i.x");
10064  CHECK_EQ(42, value->Int32Value());
10065
10066  value = CompileRun("i.f()");
10067  CHECK_EQ(12, value->Int32Value());
10068}
10069
10070
10071static void GlobalObjectInstancePropertiesGet(
10072    Local<String> key,
10073    const v8::PropertyCallbackInfo<v8::Value>&) {
10074  ApiTestFuzzer::Fuzz();
10075}
10076
10077
10078THREADED_TEST(GlobalObjectInstanceProperties) {
10079  v8::Isolate* isolate = CcTest::isolate();
10080  v8::HandleScope handle_scope(isolate);
10081
10082  Local<Value> global_object;
10083
10084  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10085  t->InstanceTemplate()->SetNamedPropertyHandler(
10086      GlobalObjectInstancePropertiesGet);
10087  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10088  instance_template->Set(v8_str("x"), v8_num(42));
10089  instance_template->Set(v8_str("f"),
10090                         v8::FunctionTemplate::New(isolate,
10091                                                   InstanceFunctionCallback));
10092
10093  // The script to check how Crankshaft compiles missing global function
10094  // invocations.  function g is not defined and should throw on call.
10095  const char* script =
10096      "function wrapper(call) {"
10097      "  var x = 0, y = 1;"
10098      "  for (var i = 0; i < 1000; i++) {"
10099      "    x += i * 100;"
10100      "    y += i * 100;"
10101      "  }"
10102      "  if (call) g();"
10103      "}"
10104      "for (var i = 0; i < 17; i++) wrapper(false);"
10105      "var thrown = 0;"
10106      "try { wrapper(true); } catch (e) { thrown = 1; };"
10107      "thrown";
10108
10109  {
10110    LocalContext env(NULL, instance_template);
10111    // Hold on to the global object so it can be used again in another
10112    // environment initialization.
10113    global_object = env->Global();
10114
10115    Local<Value> value = CompileRun("x");
10116    CHECK_EQ(42, value->Int32Value());
10117    value = CompileRun("f()");
10118    CHECK_EQ(12, value->Int32Value());
10119    value = CompileRun(script);
10120    CHECK_EQ(1, value->Int32Value());
10121  }
10122
10123  {
10124    // Create new environment reusing the global object.
10125    LocalContext env(NULL, instance_template, global_object);
10126    Local<Value> value = CompileRun("x");
10127    CHECK_EQ(42, value->Int32Value());
10128    value = CompileRun("f()");
10129    CHECK_EQ(12, value->Int32Value());
10130    value = CompileRun(script);
10131    CHECK_EQ(1, value->Int32Value());
10132  }
10133}
10134
10135
10136THREADED_TEST(CallKnownGlobalReceiver) {
10137  v8::Isolate* isolate = CcTest::isolate();
10138  v8::HandleScope handle_scope(isolate);
10139
10140  Local<Value> global_object;
10141
10142  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10143  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10144
10145  // The script to check that we leave global object not
10146  // global object proxy on stack when we deoptimize from inside
10147  // arguments evaluation.
10148  // To provoke error we need to both force deoptimization
10149  // from arguments evaluation and to force CallIC to take
10150  // CallIC_Miss code path that can't cope with global proxy.
10151  const char* script =
10152      "function bar(x, y) { try { } finally { } }"
10153      "function baz(x) { try { } finally { } }"
10154      "function bom(x) { try { } finally { } }"
10155      "function foo(x) { bar([x], bom(2)); }"
10156      "for (var i = 0; i < 10000; i++) foo(1);"
10157      "foo";
10158
10159  Local<Value> foo;
10160  {
10161    LocalContext env(NULL, instance_template);
10162    // Hold on to the global object so it can be used again in another
10163    // environment initialization.
10164    global_object = env->Global();
10165    foo = CompileRun(script);
10166  }
10167
10168  {
10169    // Create new environment reusing the global object.
10170    LocalContext env(NULL, instance_template, global_object);
10171    env->Global()->Set(v8_str("foo"), foo);
10172    CompileRun("foo()");
10173  }
10174}
10175
10176
10177static void ShadowFunctionCallback(
10178    const v8::FunctionCallbackInfo<v8::Value>& args) {
10179  ApiTestFuzzer::Fuzz();
10180  args.GetReturnValue().Set(v8_num(42));
10181}
10182
10183
10184static int shadow_y;
10185static int shadow_y_setter_call_count;
10186static int shadow_y_getter_call_count;
10187
10188
10189static void ShadowYSetter(Local<String>,
10190                          Local<Value>,
10191                          const v8::PropertyCallbackInfo<void>&) {
10192  shadow_y_setter_call_count++;
10193  shadow_y = 42;
10194}
10195
10196
10197static void ShadowYGetter(Local<String> name,
10198                          const v8::PropertyCallbackInfo<v8::Value>& info) {
10199  ApiTestFuzzer::Fuzz();
10200  shadow_y_getter_call_count++;
10201  info.GetReturnValue().Set(v8_num(shadow_y));
10202}
10203
10204
10205static void ShadowIndexedGet(uint32_t index,
10206                             const v8::PropertyCallbackInfo<v8::Value>&) {
10207}
10208
10209
10210static void ShadowNamedGet(Local<String> key,
10211                           const v8::PropertyCallbackInfo<v8::Value>&) {
10212}
10213
10214
10215THREADED_TEST(ShadowObject) {
10216  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10217  v8::Isolate* isolate = CcTest::isolate();
10218  v8::HandleScope handle_scope(isolate);
10219
10220  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10221  LocalContext context(NULL, global_template);
10222
10223  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10224  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10225  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10226  Local<ObjectTemplate> proto = t->PrototypeTemplate();
10227  Local<ObjectTemplate> instance = t->InstanceTemplate();
10228
10229  proto->Set(v8_str("f"),
10230             v8::FunctionTemplate::New(isolate,
10231                                       ShadowFunctionCallback,
10232                                       Local<Value>()));
10233  proto->Set(v8_str("x"), v8_num(12));
10234
10235  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10236
10237  Local<Value> o = t->GetFunction()->NewInstance();
10238  context->Global()->Set(v8_str("__proto__"), o);
10239
10240  Local<Value> value =
10241      CompileRun("this.propertyIsEnumerable(0)");
10242  CHECK(value->IsBoolean());
10243  CHECK(!value->BooleanValue());
10244
10245  value = CompileRun("x");
10246  CHECK_EQ(12, value->Int32Value());
10247
10248  value = CompileRun("f()");
10249  CHECK_EQ(42, value->Int32Value());
10250
10251  CompileRun("y = 43");
10252  CHECK_EQ(1, shadow_y_setter_call_count);
10253  value = CompileRun("y");
10254  CHECK_EQ(1, shadow_y_getter_call_count);
10255  CHECK_EQ(42, value->Int32Value());
10256}
10257
10258
10259THREADED_TEST(HiddenPrototype) {
10260  LocalContext context;
10261  v8::Isolate* isolate = context->GetIsolate();
10262  v8::HandleScope handle_scope(isolate);
10263
10264  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10265  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10266  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10267  t1->SetHiddenPrototype(true);
10268  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10269  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10270  t2->SetHiddenPrototype(true);
10271  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10272  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10273  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10274
10275  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10276  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10277  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10278  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10279
10280  // Setting the prototype on an object skips hidden prototypes.
10281  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10282  o0->Set(v8_str("__proto__"), o1);
10283  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10284  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10285  o0->Set(v8_str("__proto__"), o2);
10286  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10287  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10288  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10289  o0->Set(v8_str("__proto__"), o3);
10290  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10291  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10292  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10293  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10294
10295  // Getting the prototype of o0 should get the first visible one
10296  // which is o3.  Therefore, z should not be defined on the prototype
10297  // object.
10298  Local<Value> proto = o0->Get(v8_str("__proto__"));
10299  CHECK(proto->IsObject());
10300  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10301}
10302
10303
10304THREADED_TEST(HiddenPrototypeSet) {
10305  LocalContext context;
10306  v8::Isolate* isolate = context->GetIsolate();
10307  v8::HandleScope handle_scope(isolate);
10308
10309  Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10310  Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10311  ht->SetHiddenPrototype(true);
10312  Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10313  ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10314
10315  Local<v8::Object> o = ot->GetFunction()->NewInstance();
10316  Local<v8::Object> h = ht->GetFunction()->NewInstance();
10317  Local<v8::Object> p = pt->GetFunction()->NewInstance();
10318  o->Set(v8_str("__proto__"), h);
10319  h->Set(v8_str("__proto__"), p);
10320
10321  // Setting a property that exists on the hidden prototype goes there.
10322  o->Set(v8_str("x"), v8_num(7));
10323  CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10324  CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10325  CHECK(p->Get(v8_str("x"))->IsUndefined());
10326
10327  // Setting a new property should not be forwarded to the hidden prototype.
10328  o->Set(v8_str("y"), v8_num(6));
10329  CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10330  CHECK(h->Get(v8_str("y"))->IsUndefined());
10331  CHECK(p->Get(v8_str("y"))->IsUndefined());
10332
10333  // Setting a property that only exists on a prototype of the hidden prototype
10334  // is treated normally again.
10335  p->Set(v8_str("z"), v8_num(8));
10336  CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10337  CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10338  CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10339  o->Set(v8_str("z"), v8_num(9));
10340  CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10341  CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10342  CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10343}
10344
10345
10346// Regression test for issue 2457.
10347THREADED_TEST(HiddenPrototypeIdentityHash) {
10348  LocalContext context;
10349  v8::HandleScope handle_scope(context->GetIsolate());
10350
10351  Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10352  t->SetHiddenPrototype(true);
10353  t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10354  Handle<Object> p = t->GetFunction()->NewInstance();
10355  Handle<Object> o = Object::New(context->GetIsolate());
10356  o->SetPrototype(p);
10357
10358  int hash = o->GetIdentityHash();
10359  USE(hash);
10360  o->Set(v8_str("foo"), v8_num(42));
10361  DCHECK_EQ(hash, o->GetIdentityHash());
10362}
10363
10364
10365THREADED_TEST(SetPrototype) {
10366  LocalContext context;
10367  v8::Isolate* isolate = context->GetIsolate();
10368  v8::HandleScope handle_scope(isolate);
10369
10370  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10371  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10372  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10373  t1->SetHiddenPrototype(true);
10374  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10375  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10376  t2->SetHiddenPrototype(true);
10377  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10378  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10379  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10380
10381  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10382  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10383  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10384  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10385
10386  // Setting the prototype on an object does not skip hidden prototypes.
10387  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10388  CHECK(o0->SetPrototype(o1));
10389  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10390  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10391  CHECK(o1->SetPrototype(o2));
10392  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10393  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10394  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10395  CHECK(o2->SetPrototype(o3));
10396  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10397  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10398  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10399  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10400
10401  // Getting the prototype of o0 should get the first visible one
10402  // which is o3.  Therefore, z should not be defined on the prototype
10403  // object.
10404  Local<Value> proto = o0->Get(v8_str("__proto__"));
10405  CHECK(proto->IsObject());
10406  CHECK_EQ(proto.As<v8::Object>(), o3);
10407
10408  // However, Object::GetPrototype ignores hidden prototype.
10409  Local<Value> proto0 = o0->GetPrototype();
10410  CHECK(proto0->IsObject());
10411  CHECK_EQ(proto0.As<v8::Object>(), o1);
10412
10413  Local<Value> proto1 = o1->GetPrototype();
10414  CHECK(proto1->IsObject());
10415  CHECK_EQ(proto1.As<v8::Object>(), o2);
10416
10417  Local<Value> proto2 = o2->GetPrototype();
10418  CHECK(proto2->IsObject());
10419  CHECK_EQ(proto2.As<v8::Object>(), o3);
10420}
10421
10422
10423// Getting property names of an object with a prototype chain that
10424// triggers dictionary elements in GetOwnPropertyNames() shouldn't
10425// crash the runtime.
10426THREADED_TEST(Regress91517) {
10427  i::FLAG_allow_natives_syntax = true;
10428  LocalContext context;
10429  v8::Isolate* isolate = context->GetIsolate();
10430  v8::HandleScope handle_scope(isolate);
10431
10432  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10433  t1->SetHiddenPrototype(true);
10434  t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10435  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10436  t2->SetHiddenPrototype(true);
10437  t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10438  t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10439  t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10440  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10441  t3->SetHiddenPrototype(true);
10442  t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10443  Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10444  t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10445
10446  // Force dictionary-based properties.
10447  i::ScopedVector<char> name_buf(1024);
10448  for (int i = 1; i <= 1000; i++) {
10449    i::SNPrintF(name_buf, "sdf%d", i);
10450    t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10451  }
10452
10453  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10454  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10455  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10456  Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10457
10458  // Create prototype chain of hidden prototypes.
10459  CHECK(o4->SetPrototype(o3));
10460  CHECK(o3->SetPrototype(o2));
10461  CHECK(o2->SetPrototype(o1));
10462
10463  // Call the runtime version of GetOwnPropertyNames() on the natively
10464  // created object through JavaScript.
10465  context->Global()->Set(v8_str("obj"), o4);
10466  // PROPERTY_ATTRIBUTES_NONE = 0
10467  CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10468
10469  ExpectInt32("names.length", 1006);
10470  ExpectTrue("names.indexOf(\"baz\") >= 0");
10471  ExpectTrue("names.indexOf(\"boo\") >= 0");
10472  ExpectTrue("names.indexOf(\"foo\") >= 0");
10473  ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10474  ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10475  ExpectFalse("names[1005] == undefined");
10476}
10477
10478
10479// Getting property names of an object with a hidden and inherited
10480// prototype should not duplicate the accessor properties inherited.
10481THREADED_TEST(Regress269562) {
10482  i::FLAG_allow_natives_syntax = true;
10483  LocalContext context;
10484  v8::HandleScope handle_scope(context->GetIsolate());
10485
10486  Local<v8::FunctionTemplate> t1 =
10487      v8::FunctionTemplate::New(context->GetIsolate());
10488  t1->SetHiddenPrototype(true);
10489
10490  Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10491  i1->SetAccessor(v8_str("foo"),
10492                  SimpleAccessorGetter, SimpleAccessorSetter);
10493  i1->SetAccessor(v8_str("bar"),
10494                  SimpleAccessorGetter, SimpleAccessorSetter);
10495  i1->SetAccessor(v8_str("baz"),
10496                  SimpleAccessorGetter, SimpleAccessorSetter);
10497  i1->Set(v8_str("n1"), v8_num(1));
10498  i1->Set(v8_str("n2"), v8_num(2));
10499
10500  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10501  Local<v8::FunctionTemplate> t2 =
10502      v8::FunctionTemplate::New(context->GetIsolate());
10503  t2->SetHiddenPrototype(true);
10504
10505  // Inherit from t1 and mark prototype as hidden.
10506  t2->Inherit(t1);
10507  t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10508
10509  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10510  CHECK(o2->SetPrototype(o1));
10511
10512  v8::Local<v8::Symbol> sym =
10513      v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10514  o1->Set(sym, v8_num(3));
10515  o1->SetHiddenValue(
10516      v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10517
10518  // Call the runtime version of GetOwnPropertyNames() on
10519  // the natively created object through JavaScript.
10520  context->Global()->Set(v8_str("obj"), o2);
10521  context->Global()->Set(v8_str("sym"), sym);
10522  // PROPERTY_ATTRIBUTES_NONE = 0
10523  CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10524
10525  ExpectInt32("names.length", 7);
10526  ExpectTrue("names.indexOf(\"foo\") >= 0");
10527  ExpectTrue("names.indexOf(\"bar\") >= 0");
10528  ExpectTrue("names.indexOf(\"baz\") >= 0");
10529  ExpectTrue("names.indexOf(\"n1\") >= 0");
10530  ExpectTrue("names.indexOf(\"n2\") >= 0");
10531  ExpectTrue("names.indexOf(sym) >= 0");
10532  ExpectTrue("names.indexOf(\"mine\") >= 0");
10533}
10534
10535
10536THREADED_TEST(FunctionReadOnlyPrototype) {
10537  LocalContext context;
10538  v8::Isolate* isolate = context->GetIsolate();
10539  v8::HandleScope handle_scope(isolate);
10540
10541  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10542  t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10543  t1->ReadOnlyPrototype();
10544  context->Global()->Set(v8_str("func1"), t1->GetFunction());
10545  // Configured value of ReadOnly flag.
10546  CHECK(CompileRun(
10547      "(function() {"
10548      "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10549      "  return (descriptor['writable'] == false);"
10550      "})()")->BooleanValue());
10551  CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10552  CHECK_EQ(42,
10553           CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10554
10555  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10556  t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10557  context->Global()->Set(v8_str("func2"), t2->GetFunction());
10558  // Default value of ReadOnly flag.
10559  CHECK(CompileRun(
10560      "(function() {"
10561      "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10562      "  return (descriptor['writable'] == true);"
10563      "})()")->BooleanValue());
10564  CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10565}
10566
10567
10568THREADED_TEST(SetPrototypeThrows) {
10569  LocalContext context;
10570  v8::Isolate* isolate = context->GetIsolate();
10571  v8::HandleScope handle_scope(isolate);
10572
10573  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10574
10575  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10576  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10577
10578  CHECK(o0->SetPrototype(o1));
10579  // If setting the prototype leads to the cycle, SetPrototype should
10580  // return false and keep VM in sane state.
10581  v8::TryCatch try_catch;
10582  CHECK(!o1->SetPrototype(o0));
10583  CHECK(!try_catch.HasCaught());
10584  DCHECK(!CcTest::i_isolate()->has_pending_exception());
10585
10586  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10587}
10588
10589
10590THREADED_TEST(FunctionRemovePrototype) {
10591  LocalContext context;
10592  v8::Isolate* isolate = context->GetIsolate();
10593  v8::HandleScope handle_scope(isolate);
10594
10595  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10596  t1->RemovePrototype();
10597  Local<v8::Function> fun = t1->GetFunction();
10598  context->Global()->Set(v8_str("fun"), fun);
10599  CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10600
10601  v8::TryCatch try_catch;
10602  CompileRun("new fun()");
10603  CHECK(try_catch.HasCaught());
10604
10605  try_catch.Reset();
10606  fun->NewInstance();
10607  CHECK(try_catch.HasCaught());
10608}
10609
10610
10611THREADED_TEST(GetterSetterExceptions) {
10612  LocalContext context;
10613  v8::Isolate* isolate = context->GetIsolate();
10614  v8::HandleScope handle_scope(isolate);
10615  CompileRun(
10616    "function Foo() { };"
10617    "function Throw() { throw 5; };"
10618    "var x = { };"
10619    "x.__defineSetter__('set', Throw);"
10620    "x.__defineGetter__('get', Throw);");
10621  Local<v8::Object> x =
10622      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10623  v8::TryCatch try_catch;
10624  x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10625  x->Get(v8_str("get"));
10626  x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10627  x->Get(v8_str("get"));
10628  x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10629  x->Get(v8_str("get"));
10630  x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10631  x->Get(v8_str("get"));
10632}
10633
10634
10635THREADED_TEST(Constructor) {
10636  LocalContext context;
10637  v8::Isolate* isolate = context->GetIsolate();
10638  v8::HandleScope handle_scope(isolate);
10639  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10640  templ->SetClassName(v8_str("Fun"));
10641  Local<Function> cons = templ->GetFunction();
10642  context->Global()->Set(v8_str("Fun"), cons);
10643  Local<v8::Object> inst = cons->NewInstance();
10644  i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10645  CHECK(obj->IsJSObject());
10646  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10647  CHECK(value->BooleanValue());
10648}
10649
10650
10651static void ConstructorCallback(
10652    const v8::FunctionCallbackInfo<v8::Value>& args) {
10653  ApiTestFuzzer::Fuzz();
10654  Local<Object> This;
10655
10656  if (args.IsConstructCall()) {
10657    Local<Object> Holder = args.Holder();
10658    This = Object::New(args.GetIsolate());
10659    Local<Value> proto = Holder->GetPrototype();
10660    if (proto->IsObject()) {
10661      This->SetPrototype(proto);
10662    }
10663  } else {
10664    This = args.This();
10665  }
10666
10667  This->Set(v8_str("a"), args[0]);
10668  args.GetReturnValue().Set(This);
10669}
10670
10671
10672static void FakeConstructorCallback(
10673    const v8::FunctionCallbackInfo<v8::Value>& args) {
10674  ApiTestFuzzer::Fuzz();
10675  args.GetReturnValue().Set(args[0]);
10676}
10677
10678
10679THREADED_TEST(ConstructorForObject) {
10680  LocalContext context;
10681  v8::Isolate* isolate = context->GetIsolate();
10682  v8::HandleScope handle_scope(isolate);
10683
10684  { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10685    instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10686    Local<Object> instance = instance_template->NewInstance();
10687    context->Global()->Set(v8_str("obj"), instance);
10688    v8::TryCatch try_catch;
10689    Local<Value> value;
10690    CHECK(!try_catch.HasCaught());
10691
10692    // Call the Object's constructor with a 32-bit signed integer.
10693    value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10694    CHECK(!try_catch.HasCaught());
10695    CHECK(value->IsInt32());
10696    CHECK_EQ(28, value->Int32Value());
10697
10698    Local<Value> args1[] = { v8_num(28) };
10699    Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10700    CHECK(value_obj1->IsObject());
10701    Local<Object> object1 = Local<Object>::Cast(value_obj1);
10702    value = object1->Get(v8_str("a"));
10703    CHECK(value->IsInt32());
10704    CHECK(!try_catch.HasCaught());
10705    CHECK_EQ(28, value->Int32Value());
10706
10707    // Call the Object's constructor with a String.
10708    value = CompileRun(
10709        "(function() { var o = new obj('tipli'); return o.a; })()");
10710    CHECK(!try_catch.HasCaught());
10711    CHECK(value->IsString());
10712    String::Utf8Value string_value1(value->ToString());
10713    CHECK_EQ("tipli", *string_value1);
10714
10715    Local<Value> args2[] = { v8_str("tipli") };
10716    Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10717    CHECK(value_obj2->IsObject());
10718    Local<Object> object2 = Local<Object>::Cast(value_obj2);
10719    value = object2->Get(v8_str("a"));
10720    CHECK(!try_catch.HasCaught());
10721    CHECK(value->IsString());
10722    String::Utf8Value string_value2(value->ToString());
10723    CHECK_EQ("tipli", *string_value2);
10724
10725    // Call the Object's constructor with a Boolean.
10726    value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10727    CHECK(!try_catch.HasCaught());
10728    CHECK(value->IsBoolean());
10729    CHECK_EQ(true, value->BooleanValue());
10730
10731    Handle<Value> args3[] = { v8::True(isolate) };
10732    Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10733    CHECK(value_obj3->IsObject());
10734    Local<Object> object3 = Local<Object>::Cast(value_obj3);
10735    value = object3->Get(v8_str("a"));
10736    CHECK(!try_catch.HasCaught());
10737    CHECK(value->IsBoolean());
10738    CHECK_EQ(true, value->BooleanValue());
10739
10740    // Call the Object's constructor with undefined.
10741    Handle<Value> args4[] = { v8::Undefined(isolate) };
10742    Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10743    CHECK(value_obj4->IsObject());
10744    Local<Object> object4 = Local<Object>::Cast(value_obj4);
10745    value = object4->Get(v8_str("a"));
10746    CHECK(!try_catch.HasCaught());
10747    CHECK(value->IsUndefined());
10748
10749    // Call the Object's constructor with null.
10750    Handle<Value> args5[] = { v8::Null(isolate) };
10751    Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10752    CHECK(value_obj5->IsObject());
10753    Local<Object> object5 = Local<Object>::Cast(value_obj5);
10754    value = object5->Get(v8_str("a"));
10755    CHECK(!try_catch.HasCaught());
10756    CHECK(value->IsNull());
10757  }
10758
10759  // Check exception handling when there is no constructor set for the Object.
10760  { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10761    Local<Object> instance = instance_template->NewInstance();
10762    context->Global()->Set(v8_str("obj2"), instance);
10763    v8::TryCatch try_catch;
10764    Local<Value> value;
10765    CHECK(!try_catch.HasCaught());
10766
10767    value = CompileRun("new obj2(28)");
10768    CHECK(try_catch.HasCaught());
10769    String::Utf8Value exception_value1(try_catch.Exception());
10770    CHECK_EQ("TypeError: object is not a function", *exception_value1);
10771    try_catch.Reset();
10772
10773    Local<Value> args[] = { v8_num(29) };
10774    value = instance->CallAsConstructor(1, args);
10775    CHECK(try_catch.HasCaught());
10776    String::Utf8Value exception_value2(try_catch.Exception());
10777    CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10778    try_catch.Reset();
10779  }
10780
10781  // Check the case when constructor throws exception.
10782  { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10783    instance_template->SetCallAsFunctionHandler(ThrowValue);
10784    Local<Object> instance = instance_template->NewInstance();
10785    context->Global()->Set(v8_str("obj3"), instance);
10786    v8::TryCatch try_catch;
10787    Local<Value> value;
10788    CHECK(!try_catch.HasCaught());
10789
10790    value = CompileRun("new obj3(22)");
10791    CHECK(try_catch.HasCaught());
10792    String::Utf8Value exception_value1(try_catch.Exception());
10793    CHECK_EQ("22", *exception_value1);
10794    try_catch.Reset();
10795
10796    Local<Value> args[] = { v8_num(23) };
10797    value = instance->CallAsConstructor(1, args);
10798    CHECK(try_catch.HasCaught());
10799    String::Utf8Value exception_value2(try_catch.Exception());
10800    CHECK_EQ("23", *exception_value2);
10801    try_catch.Reset();
10802  }
10803
10804  // Check whether constructor returns with an object or non-object.
10805  { Local<FunctionTemplate> function_template =
10806        FunctionTemplate::New(isolate, FakeConstructorCallback);
10807    Local<Function> function = function_template->GetFunction();
10808    Local<Object> instance1 = function;
10809    context->Global()->Set(v8_str("obj4"), instance1);
10810    v8::TryCatch try_catch;
10811    Local<Value> value;
10812    CHECK(!try_catch.HasCaught());
10813
10814    CHECK(instance1->IsObject());
10815    CHECK(instance1->IsFunction());
10816
10817    value = CompileRun("new obj4(28)");
10818    CHECK(!try_catch.HasCaught());
10819    CHECK(value->IsObject());
10820
10821    Local<Value> args1[] = { v8_num(28) };
10822    value = instance1->CallAsConstructor(1, args1);
10823    CHECK(!try_catch.HasCaught());
10824    CHECK(value->IsObject());
10825
10826    Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10827    instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10828    Local<Object> instance2 = instance_template->NewInstance();
10829    context->Global()->Set(v8_str("obj5"), instance2);
10830    CHECK(!try_catch.HasCaught());
10831
10832    CHECK(instance2->IsObject());
10833    CHECK(!instance2->IsFunction());
10834
10835    value = CompileRun("new obj5(28)");
10836    CHECK(!try_catch.HasCaught());
10837    CHECK(!value->IsObject());
10838
10839    Local<Value> args2[] = { v8_num(28) };
10840    value = instance2->CallAsConstructor(1, args2);
10841    CHECK(!try_catch.HasCaught());
10842    CHECK(!value->IsObject());
10843  }
10844}
10845
10846
10847THREADED_TEST(FunctionDescriptorException) {
10848  LocalContext context;
10849  v8::Isolate* isolate = context->GetIsolate();
10850  v8::HandleScope handle_scope(isolate);
10851  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10852  templ->SetClassName(v8_str("Fun"));
10853  Local<Function> cons = templ->GetFunction();
10854  context->Global()->Set(v8_str("Fun"), cons);
10855  Local<Value> value = CompileRun(
10856    "function test() {"
10857    "  try {"
10858    "    (new Fun()).blah()"
10859    "  } catch (e) {"
10860    "    var str = String(e);"
10861    // "    if (str.indexOf('TypeError') == -1) return 1;"
10862    // "    if (str.indexOf('[object Fun]') != -1) return 2;"
10863    // "    if (str.indexOf('#<Fun>') == -1) return 3;"
10864    "    return 0;"
10865    "  }"
10866    "  return 4;"
10867    "}"
10868    "test();");
10869  CHECK_EQ(0, value->Int32Value());
10870}
10871
10872
10873THREADED_TEST(EvalAliasedDynamic) {
10874  LocalContext current;
10875  v8::HandleScope scope(current->GetIsolate());
10876
10877  // Tests where aliased eval can only be resolved dynamically.
10878  Local<Script> script = v8_compile(
10879      "function f(x) { "
10880      "  var foo = 2;"
10881      "  with (x) { return eval('foo'); }"
10882      "}"
10883      "foo = 0;"
10884      "result1 = f(new Object());"
10885      "result2 = f(this);"
10886      "var x = new Object();"
10887      "x.eval = function(x) { return 1; };"
10888      "result3 = f(x);");
10889  script->Run();
10890  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10891  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10892  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10893
10894  v8::TryCatch try_catch;
10895  script = v8_compile(
10896      "function f(x) { "
10897      "  var bar = 2;"
10898      "  with (x) { return eval('bar'); }"
10899      "}"
10900      "result4 = f(this)");
10901  script->Run();
10902  CHECK(!try_catch.HasCaught());
10903  CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10904
10905  try_catch.Reset();
10906}
10907
10908
10909THREADED_TEST(CrossEval) {
10910  v8::HandleScope scope(CcTest::isolate());
10911  LocalContext other;
10912  LocalContext current;
10913
10914  Local<String> token = v8_str("<security token>");
10915  other->SetSecurityToken(token);
10916  current->SetSecurityToken(token);
10917
10918  // Set up reference from current to other.
10919  current->Global()->Set(v8_str("other"), other->Global());
10920
10921  // Check that new variables are introduced in other context.
10922  Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10923  script->Run();
10924  Local<Value> foo = other->Global()->Get(v8_str("foo"));
10925  CHECK_EQ(1234, foo->Int32Value());
10926  CHECK(!current->Global()->Has(v8_str("foo")));
10927
10928  // Check that writing to non-existing properties introduces them in
10929  // the other context.
10930  script = v8_compile("other.eval('na = 1234')");
10931  script->Run();
10932  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10933  CHECK(!current->Global()->Has(v8_str("na")));
10934
10935  // Check that global variables in current context are not visible in other
10936  // context.
10937  v8::TryCatch try_catch;
10938  script = v8_compile("var bar = 42; other.eval('bar');");
10939  Local<Value> result = script->Run();
10940  CHECK(try_catch.HasCaught());
10941  try_catch.Reset();
10942
10943  // Check that local variables in current context are not visible in other
10944  // context.
10945  script = v8_compile(
10946      "(function() { "
10947      "  var baz = 87;"
10948      "  return other.eval('baz');"
10949      "})();");
10950  result = script->Run();
10951  CHECK(try_catch.HasCaught());
10952  try_catch.Reset();
10953
10954  // Check that global variables in the other environment are visible
10955  // when evaluting code.
10956  other->Global()->Set(v8_str("bis"), v8_num(1234));
10957  script = v8_compile("other.eval('bis')");
10958  CHECK_EQ(1234, script->Run()->Int32Value());
10959  CHECK(!try_catch.HasCaught());
10960
10961  // Check that the 'this' pointer points to the global object evaluating
10962  // code.
10963  other->Global()->Set(v8_str("t"), other->Global());
10964  script = v8_compile("other.eval('this == t')");
10965  result = script->Run();
10966  CHECK(result->IsTrue());
10967  CHECK(!try_catch.HasCaught());
10968
10969  // Check that variables introduced in with-statement are not visible in
10970  // other context.
10971  script = v8_compile("with({x:2}){other.eval('x')}");
10972  result = script->Run();
10973  CHECK(try_catch.HasCaught());
10974  try_catch.Reset();
10975
10976  // Check that you cannot use 'eval.call' with another object than the
10977  // current global object.
10978  script = v8_compile("other.y = 1; eval.call(other, 'y')");
10979  result = script->Run();
10980  CHECK(try_catch.HasCaught());
10981}
10982
10983
10984// Test that calling eval in a context which has been detached from
10985// its global throws an exception.  This behavior is consistent with
10986// other JavaScript implementations.
10987THREADED_TEST(EvalInDetachedGlobal) {
10988  v8::Isolate* isolate = CcTest::isolate();
10989  v8::HandleScope scope(isolate);
10990
10991  v8::Local<Context> context0 = Context::New(isolate);
10992  v8::Local<Context> context1 = Context::New(isolate);
10993
10994  // Set up function in context0 that uses eval from context0.
10995  context0->Enter();
10996  v8::Handle<v8::Value> fun =
10997      CompileRun("var x = 42;"
10998                 "(function() {"
10999                 "  var e = eval;"
11000                 "  return function(s) { return e(s); }"
11001                 "})()");
11002  context0->Exit();
11003
11004  // Put the function into context1 and call it before and after
11005  // detaching the global.  Before detaching, the call succeeds and
11006  // after detaching and exception is thrown.
11007  context1->Enter();
11008  context1->Global()->Set(v8_str("fun"), fun);
11009  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
11010  CHECK_EQ(42, x_value->Int32Value());
11011  context0->DetachGlobal();
11012  v8::TryCatch catcher;
11013  x_value = CompileRun("fun('x')");
11014  CHECK(x_value.IsEmpty());
11015  CHECK(catcher.HasCaught());
11016  context1->Exit();
11017}
11018
11019
11020THREADED_TEST(CrossLazyLoad) {
11021  v8::HandleScope scope(CcTest::isolate());
11022  LocalContext other;
11023  LocalContext current;
11024
11025  Local<String> token = v8_str("<security token>");
11026  other->SetSecurityToken(token);
11027  current->SetSecurityToken(token);
11028
11029  // Set up reference from current to other.
11030  current->Global()->Set(v8_str("other"), other->Global());
11031
11032  // Trigger lazy loading in other context.
11033  Local<Script> script = v8_compile("other.eval('new Date(42)')");
11034  Local<Value> value = script->Run();
11035  CHECK_EQ(42.0, value->NumberValue());
11036}
11037
11038
11039static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11040  ApiTestFuzzer::Fuzz();
11041  if (args.IsConstructCall()) {
11042    if (args[0]->IsInt32()) {
11043      args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
11044      return;
11045    }
11046  }
11047
11048  args.GetReturnValue().Set(args[0]);
11049}
11050
11051
11052static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
11053  args.GetReturnValue().Set(args.This());
11054}
11055
11056
11057// Test that a call handler can be set for objects which will allow
11058// non-function objects created through the API to be called as
11059// functions.
11060THREADED_TEST(CallAsFunction) {
11061  LocalContext context;
11062  v8::Isolate* isolate = context->GetIsolate();
11063  v8::HandleScope scope(isolate);
11064
11065  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11066    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11067    instance_template->SetCallAsFunctionHandler(call_as_function);
11068    Local<v8::Object> instance = t->GetFunction()->NewInstance();
11069    context->Global()->Set(v8_str("obj"), instance);
11070    v8::TryCatch try_catch;
11071    Local<Value> value;
11072    CHECK(!try_catch.HasCaught());
11073
11074    value = CompileRun("obj(42)");
11075    CHECK(!try_catch.HasCaught());
11076    CHECK_EQ(42, value->Int32Value());
11077
11078    value = CompileRun("(function(o){return o(49)})(obj)");
11079    CHECK(!try_catch.HasCaught());
11080    CHECK_EQ(49, value->Int32Value());
11081
11082    // test special case of call as function
11083    value = CompileRun("[obj]['0'](45)");
11084    CHECK(!try_catch.HasCaught());
11085    CHECK_EQ(45, value->Int32Value());
11086
11087    value = CompileRun("obj.call = Function.prototype.call;"
11088                       "obj.call(null, 87)");
11089    CHECK(!try_catch.HasCaught());
11090    CHECK_EQ(87, value->Int32Value());
11091
11092    // Regression tests for bug #1116356: Calling call through call/apply
11093    // must work for non-function receivers.
11094    const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11095    value = CompileRun(apply_99);
11096    CHECK(!try_catch.HasCaught());
11097    CHECK_EQ(99, value->Int32Value());
11098
11099    const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11100    value = CompileRun(call_17);
11101    CHECK(!try_catch.HasCaught());
11102    CHECK_EQ(17, value->Int32Value());
11103
11104    // Check that the call-as-function handler can be called through
11105    // new.
11106    value = CompileRun("new obj(43)");
11107    CHECK(!try_catch.HasCaught());
11108    CHECK_EQ(-43, value->Int32Value());
11109
11110    // Check that the call-as-function handler can be called through
11111    // the API.
11112    v8::Handle<Value> args[] = { v8_num(28) };
11113    value = instance->CallAsFunction(instance, 1, args);
11114    CHECK(!try_catch.HasCaught());
11115    CHECK_EQ(28, value->Int32Value());
11116  }
11117
11118  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11119    Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11120    USE(instance_template);
11121    Local<v8::Object> instance = t->GetFunction()->NewInstance();
11122    context->Global()->Set(v8_str("obj2"), instance);
11123    v8::TryCatch try_catch;
11124    Local<Value> value;
11125    CHECK(!try_catch.HasCaught());
11126
11127    // Call an object without call-as-function handler through the JS
11128    value = CompileRun("obj2(28)");
11129    CHECK(value.IsEmpty());
11130    CHECK(try_catch.HasCaught());
11131    String::Utf8Value exception_value1(try_catch.Exception());
11132    // TODO(verwaest): Better message
11133    CHECK_EQ("TypeError: object is not a function",
11134             *exception_value1);
11135    try_catch.Reset();
11136
11137    // Call an object without call-as-function handler through the API
11138    value = CompileRun("obj2(28)");
11139    v8::Handle<Value> args[] = { v8_num(28) };
11140    value = instance->CallAsFunction(instance, 1, args);
11141    CHECK(value.IsEmpty());
11142    CHECK(try_catch.HasCaught());
11143    String::Utf8Value exception_value2(try_catch.Exception());
11144    CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11145    try_catch.Reset();
11146  }
11147
11148  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11149    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11150    instance_template->SetCallAsFunctionHandler(ThrowValue);
11151    Local<v8::Object> instance = t->GetFunction()->NewInstance();
11152    context->Global()->Set(v8_str("obj3"), instance);
11153    v8::TryCatch try_catch;
11154    Local<Value> value;
11155    CHECK(!try_catch.HasCaught());
11156
11157    // Catch the exception which is thrown by call-as-function handler
11158    value = CompileRun("obj3(22)");
11159    CHECK(try_catch.HasCaught());
11160    String::Utf8Value exception_value1(try_catch.Exception());
11161    CHECK_EQ("22", *exception_value1);
11162    try_catch.Reset();
11163
11164    v8::Handle<Value> args[] = { v8_num(23) };
11165    value = instance->CallAsFunction(instance, 1, args);
11166    CHECK(try_catch.HasCaught());
11167    String::Utf8Value exception_value2(try_catch.Exception());
11168    CHECK_EQ("23", *exception_value2);
11169    try_catch.Reset();
11170  }
11171
11172  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11173    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11174    instance_template->SetCallAsFunctionHandler(ReturnThis);
11175    Local<v8::Object> instance = t->GetFunction()->NewInstance();
11176
11177    Local<v8::Value> a1 =
11178        instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11179    CHECK(a1->StrictEquals(instance));
11180    Local<v8::Value> a2 =
11181        instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11182    CHECK(a2->StrictEquals(instance));
11183    Local<v8::Value> a3 =
11184        instance->CallAsFunction(v8_num(42), 0, NULL);
11185    CHECK(a3->StrictEquals(instance));
11186    Local<v8::Value> a4 =
11187        instance->CallAsFunction(v8_str("hello"), 0, NULL);
11188    CHECK(a4->StrictEquals(instance));
11189    Local<v8::Value> a5 =
11190        instance->CallAsFunction(v8::True(isolate), 0, NULL);
11191    CHECK(a5->StrictEquals(instance));
11192  }
11193
11194  { CompileRun(
11195      "function ReturnThisSloppy() {"
11196      "  return this;"
11197      "}"
11198      "function ReturnThisStrict() {"
11199      "  'use strict';"
11200      "  return this;"
11201      "}");
11202    Local<Function> ReturnThisSloppy =
11203        Local<Function>::Cast(
11204            context->Global()->Get(v8_str("ReturnThisSloppy")));
11205    Local<Function> ReturnThisStrict =
11206        Local<Function>::Cast(
11207            context->Global()->Get(v8_str("ReturnThisStrict")));
11208
11209    Local<v8::Value> a1 =
11210        ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11211    CHECK(a1->StrictEquals(context->Global()));
11212    Local<v8::Value> a2 =
11213        ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11214    CHECK(a2->StrictEquals(context->Global()));
11215    Local<v8::Value> a3 =
11216        ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11217    CHECK(a3->IsNumberObject());
11218    CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11219    Local<v8::Value> a4 =
11220        ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11221    CHECK(a4->IsStringObject());
11222    CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11223    Local<v8::Value> a5 =
11224        ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11225    CHECK(a5->IsBooleanObject());
11226    CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11227
11228    Local<v8::Value> a6 =
11229        ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11230    CHECK(a6->IsUndefined());
11231    Local<v8::Value> a7 =
11232        ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11233    CHECK(a7->IsNull());
11234    Local<v8::Value> a8 =
11235        ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11236    CHECK(a8->StrictEquals(v8_num(42)));
11237    Local<v8::Value> a9 =
11238        ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11239    CHECK(a9->StrictEquals(v8_str("hello")));
11240    Local<v8::Value> a10 =
11241        ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11242    CHECK(a10->StrictEquals(v8::True(isolate)));
11243  }
11244}
11245
11246
11247// Check whether a non-function object is callable.
11248THREADED_TEST(CallableObject) {
11249  LocalContext context;
11250  v8::Isolate* isolate = context->GetIsolate();
11251  v8::HandleScope scope(isolate);
11252
11253  { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11254    instance_template->SetCallAsFunctionHandler(call_as_function);
11255    Local<Object> instance = instance_template->NewInstance();
11256    v8::TryCatch try_catch;
11257
11258    CHECK(instance->IsCallable());
11259    CHECK(!try_catch.HasCaught());
11260  }
11261
11262  { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11263    Local<Object> instance = instance_template->NewInstance();
11264    v8::TryCatch try_catch;
11265
11266    CHECK(!instance->IsCallable());
11267    CHECK(!try_catch.HasCaught());
11268  }
11269
11270  { Local<FunctionTemplate> function_template =
11271        FunctionTemplate::New(isolate, call_as_function);
11272    Local<Function> function = function_template->GetFunction();
11273    Local<Object> instance = function;
11274    v8::TryCatch try_catch;
11275
11276    CHECK(instance->IsCallable());
11277    CHECK(!try_catch.HasCaught());
11278  }
11279
11280  { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11281    Local<Function> function = function_template->GetFunction();
11282    Local<Object> instance = function;
11283    v8::TryCatch try_catch;
11284
11285    CHECK(instance->IsCallable());
11286    CHECK(!try_catch.HasCaught());
11287  }
11288}
11289
11290
11291static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11292  v8::HandleScope scope(isolate);
11293  if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11294  for (int i = 0; i < iterations; i++) {
11295    Local<v8::Number> n(v8::Integer::New(isolate, 42));
11296  }
11297  return Recurse(isolate, depth - 1, iterations);
11298}
11299
11300
11301THREADED_TEST(HandleIteration) {
11302  static const int kIterations = 500;
11303  static const int kNesting = 200;
11304  LocalContext context;
11305  v8::Isolate* isolate = context->GetIsolate();
11306  v8::HandleScope scope0(isolate);
11307  CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11308  {
11309    v8::HandleScope scope1(isolate);
11310    CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11311    for (int i = 0; i < kIterations; i++) {
11312      Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11313      CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11314    }
11315
11316    CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11317    {
11318      v8::HandleScope scope2(CcTest::isolate());
11319      for (int j = 0; j < kIterations; j++) {
11320        Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11321        CHECK_EQ(j + 1 + kIterations,
11322                 v8::HandleScope::NumberOfHandles(isolate));
11323      }
11324    }
11325    CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11326  }
11327  CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11328  CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11329}
11330
11331
11332static void InterceptorHasOwnPropertyGetter(
11333    Local<String> name,
11334    const v8::PropertyCallbackInfo<v8::Value>& info) {
11335  ApiTestFuzzer::Fuzz();
11336}
11337
11338
11339THREADED_TEST(InterceptorHasOwnProperty) {
11340  LocalContext context;
11341  v8::Isolate* isolate = context->GetIsolate();
11342  v8::HandleScope scope(isolate);
11343  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11344  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11345  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11346  Local<Function> function = fun_templ->GetFunction();
11347  context->Global()->Set(v8_str("constructor"), function);
11348  v8::Handle<Value> value = CompileRun(
11349      "var o = new constructor();"
11350      "o.hasOwnProperty('ostehaps');");
11351  CHECK_EQ(false, value->BooleanValue());
11352  value = CompileRun(
11353      "o.ostehaps = 42;"
11354      "o.hasOwnProperty('ostehaps');");
11355  CHECK_EQ(true, value->BooleanValue());
11356  value = CompileRun(
11357      "var p = new constructor();"
11358      "p.hasOwnProperty('ostehaps');");
11359  CHECK_EQ(false, value->BooleanValue());
11360}
11361
11362
11363static void InterceptorHasOwnPropertyGetterGC(
11364    Local<String> name,
11365    const v8::PropertyCallbackInfo<v8::Value>& info) {
11366  ApiTestFuzzer::Fuzz();
11367  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11368}
11369
11370
11371THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11372  LocalContext context;
11373  v8::Isolate* isolate = context->GetIsolate();
11374  v8::HandleScope scope(isolate);
11375  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11376  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11377  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11378  Local<Function> function = fun_templ->GetFunction();
11379  context->Global()->Set(v8_str("constructor"), function);
11380  // Let's first make some stuff so we can be sure to get a good GC.
11381  CompileRun(
11382      "function makestr(size) {"
11383      "  switch (size) {"
11384      "    case 1: return 'f';"
11385      "    case 2: return 'fo';"
11386      "    case 3: return 'foo';"
11387      "  }"
11388      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
11389      "}"
11390      "var x = makestr(12345);"
11391      "x = makestr(31415);"
11392      "x = makestr(23456);");
11393  v8::Handle<Value> value = CompileRun(
11394      "var o = new constructor();"
11395      "o.__proto__ = new String(x);"
11396      "o.hasOwnProperty('ostehaps');");
11397  CHECK_EQ(false, value->BooleanValue());
11398}
11399
11400
11401typedef void (*NamedPropertyGetter)(
11402    Local<String> property,
11403    const v8::PropertyCallbackInfo<v8::Value>& info);
11404
11405
11406static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11407                                   const char* source,
11408                                   int expected) {
11409  v8::Isolate* isolate = CcTest::isolate();
11410  v8::HandleScope scope(isolate);
11411  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11412  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11413  LocalContext context;
11414  context->Global()->Set(v8_str("o"), templ->NewInstance());
11415  v8::Handle<Value> value = CompileRun(source);
11416  CHECK_EQ(expected, value->Int32Value());
11417}
11418
11419
11420static void InterceptorLoadICGetter(
11421    Local<String> name,
11422    const v8::PropertyCallbackInfo<v8::Value>& info) {
11423  ApiTestFuzzer::Fuzz();
11424  v8::Isolate* isolate = CcTest::isolate();
11425  CHECK_EQ(isolate, info.GetIsolate());
11426  CHECK_EQ(v8_str("data"), info.Data());
11427  CHECK_EQ(v8_str("x"), name);
11428  info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11429}
11430
11431
11432// This test should hit the load IC for the interceptor case.
11433THREADED_TEST(InterceptorLoadIC) {
11434  CheckInterceptorLoadIC(InterceptorLoadICGetter,
11435    "var result = 0;"
11436    "for (var i = 0; i < 1000; i++) {"
11437    "  result = o.x;"
11438    "}",
11439    42);
11440}
11441
11442
11443// Below go several tests which verify that JITing for various
11444// configurations of interceptor and explicit fields works fine
11445// (those cases are special cased to get better performance).
11446
11447static void InterceptorLoadXICGetter(
11448    Local<String> name,
11449    const v8::PropertyCallbackInfo<v8::Value>& info) {
11450  ApiTestFuzzer::Fuzz();
11451  info.GetReturnValue().Set(
11452      v8_str("x")->Equals(name) ?
11453          v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11454          v8::Handle<v8::Value>());
11455}
11456
11457
11458THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11459  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11460    "var result = 0;"
11461    "o.y = 239;"
11462    "for (var i = 0; i < 1000; i++) {"
11463    "  result = o.y;"
11464    "}",
11465    239);
11466}
11467
11468
11469THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11470  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11471    "var result = 0;"
11472    "o.__proto__ = { 'y': 239 };"
11473    "for (var i = 0; i < 1000; i++) {"
11474    "  result = o.y + o.x;"
11475    "}",
11476    239 + 42);
11477}
11478
11479
11480THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11481  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11482    "var result = 0;"
11483    "o.__proto__.y = 239;"
11484    "for (var i = 0; i < 1000; i++) {"
11485    "  result = o.y + o.x;"
11486    "}",
11487    239 + 42);
11488}
11489
11490
11491THREADED_TEST(InterceptorLoadICUndefined) {
11492  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11493    "var result = 0;"
11494    "for (var i = 0; i < 1000; i++) {"
11495    "  result = (o.y == undefined) ? 239 : 42;"
11496    "}",
11497    239);
11498}
11499
11500
11501THREADED_TEST(InterceptorLoadICWithOverride) {
11502  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11503    "fst = new Object();  fst.__proto__ = o;"
11504    "snd = new Object();  snd.__proto__ = fst;"
11505    "var result1 = 0;"
11506    "for (var i = 0; i < 1000;  i++) {"
11507    "  result1 = snd.x;"
11508    "}"
11509    "fst.x = 239;"
11510    "var result = 0;"
11511    "for (var i = 0; i < 1000; i++) {"
11512    "  result = snd.x;"
11513    "}"
11514    "result + result1",
11515    239 + 42);
11516}
11517
11518
11519// Test the case when we stored field into
11520// a stub, but interceptor produced value on its own.
11521THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11522  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11523    "proto = new Object();"
11524    "o.__proto__ = proto;"
11525    "proto.x = 239;"
11526    "for (var i = 0; i < 1000; i++) {"
11527    "  o.x;"
11528    // Now it should be ICed and keep a reference to x defined on proto
11529    "}"
11530    "var result = 0;"
11531    "for (var i = 0; i < 1000; i++) {"
11532    "  result += o.x;"
11533    "}"
11534    "result;",
11535    42 * 1000);
11536}
11537
11538
11539// Test the case when we stored field into
11540// a stub, but it got invalidated later on.
11541THREADED_TEST(InterceptorLoadICInvalidatedField) {
11542  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11543    "proto1 = new Object();"
11544    "proto2 = new Object();"
11545    "o.__proto__ = proto1;"
11546    "proto1.__proto__ = proto2;"
11547    "proto2.y = 239;"
11548    "for (var i = 0; i < 1000; i++) {"
11549    "  o.y;"
11550    // Now it should be ICed and keep a reference to y defined on proto2
11551    "}"
11552    "proto1.y = 42;"
11553    "var result = 0;"
11554    "for (var i = 0; i < 1000; i++) {"
11555    "  result += o.y;"
11556    "}"
11557    "result;",
11558    42 * 1000);
11559}
11560
11561
11562static int interceptor_load_not_handled_calls = 0;
11563static void InterceptorLoadNotHandled(
11564    Local<String> name,
11565    const v8::PropertyCallbackInfo<v8::Value>& info) {
11566  ++interceptor_load_not_handled_calls;
11567}
11568
11569
11570// Test how post-interceptor lookups are done in the non-cacheable
11571// case: the interceptor should not be invoked during this lookup.
11572THREADED_TEST(InterceptorLoadICPostInterceptor) {
11573  interceptor_load_not_handled_calls = 0;
11574  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11575    "receiver = new Object();"
11576    "receiver.__proto__ = o;"
11577    "proto = new Object();"
11578    "/* Make proto a slow-case object. */"
11579    "for (var i = 0; i < 1000; i++) {"
11580    "  proto[\"xxxxxxxx\" + i] = [];"
11581    "}"
11582    "proto.x = 17;"
11583    "o.__proto__ = proto;"
11584    "var result = 0;"
11585    "for (var i = 0; i < 1000; i++) {"
11586    "  result += receiver.x;"
11587    "}"
11588    "result;",
11589    17 * 1000);
11590  CHECK_EQ(1000, interceptor_load_not_handled_calls);
11591}
11592
11593
11594// Test the case when we stored field into
11595// a stub, but it got invalidated later on due to override on
11596// global object which is between interceptor and fields' holders.
11597THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11598  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11599    "o.__proto__ = this;"  // set a global to be a proto of o.
11600    "this.__proto__.y = 239;"
11601    "for (var i = 0; i < 10; i++) {"
11602    "  if (o.y != 239) throw 'oops: ' + o.y;"
11603    // Now it should be ICed and keep a reference to y defined on field_holder.
11604    "}"
11605    "this.y = 42;"  // Assign on a global.
11606    "var result = 0;"
11607    "for (var i = 0; i < 10; i++) {"
11608    "  result += o.y;"
11609    "}"
11610    "result;",
11611    42 * 10);
11612}
11613
11614
11615static void SetOnThis(Local<String> name,
11616                      Local<Value> value,
11617                      const v8::PropertyCallbackInfo<void>& info) {
11618  Local<Object>::Cast(info.This())->ForceSet(name, value);
11619}
11620
11621
11622THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11623  v8::Isolate* isolate = CcTest::isolate();
11624  v8::HandleScope scope(isolate);
11625  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11626  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11627  templ->SetAccessor(v8_str("y"), Return239Callback);
11628  LocalContext context;
11629  context->Global()->Set(v8_str("o"), templ->NewInstance());
11630
11631  // Check the case when receiver and interceptor's holder
11632  // are the same objects.
11633  v8::Handle<Value> value = CompileRun(
11634      "var result = 0;"
11635      "for (var i = 0; i < 7; i++) {"
11636      "  result = o.y;"
11637      "}");
11638  CHECK_EQ(239, value->Int32Value());
11639
11640  // Check the case when interceptor's holder is in proto chain
11641  // of receiver.
11642  value = CompileRun(
11643      "r = { __proto__: o };"
11644      "var result = 0;"
11645      "for (var i = 0; i < 7; i++) {"
11646      "  result = r.y;"
11647      "}");
11648  CHECK_EQ(239, value->Int32Value());
11649}
11650
11651
11652THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11653  v8::Isolate* isolate = CcTest::isolate();
11654  v8::HandleScope scope(isolate);
11655  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11656  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11657  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11658  templ_p->SetAccessor(v8_str("y"), Return239Callback);
11659
11660  LocalContext context;
11661  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11662  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11663
11664  // Check the case when receiver and interceptor's holder
11665  // are the same objects.
11666  v8::Handle<Value> value = CompileRun(
11667      "o.__proto__ = p;"
11668      "var result = 0;"
11669      "for (var i = 0; i < 7; i++) {"
11670      "  result = o.x + o.y;"
11671      "}");
11672  CHECK_EQ(239 + 42, value->Int32Value());
11673
11674  // Check the case when interceptor's holder is in proto chain
11675  // of receiver.
11676  value = CompileRun(
11677      "r = { __proto__: o };"
11678      "var result = 0;"
11679      "for (var i = 0; i < 7; i++) {"
11680      "  result = r.x + r.y;"
11681      "}");
11682  CHECK_EQ(239 + 42, value->Int32Value());
11683}
11684
11685
11686THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11687  v8::Isolate* isolate = CcTest::isolate();
11688  v8::HandleScope scope(isolate);
11689  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11690  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11691  templ->SetAccessor(v8_str("y"), Return239Callback);
11692
11693  LocalContext context;
11694  context->Global()->Set(v8_str("o"), templ->NewInstance());
11695
11696  v8::Handle<Value> value = CompileRun(
11697    "fst = new Object();  fst.__proto__ = o;"
11698    "snd = new Object();  snd.__proto__ = fst;"
11699    "var result1 = 0;"
11700    "for (var i = 0; i < 7;  i++) {"
11701    "  result1 = snd.x;"
11702    "}"
11703    "fst.x = 239;"
11704    "var result = 0;"
11705    "for (var i = 0; i < 7; i++) {"
11706    "  result = snd.x;"
11707    "}"
11708    "result + result1");
11709  CHECK_EQ(239 + 42, value->Int32Value());
11710}
11711
11712
11713// Test the case when we stored callback into
11714// a stub, but interceptor produced value on its own.
11715THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11716  v8::Isolate* isolate = CcTest::isolate();
11717  v8::HandleScope scope(isolate);
11718  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11719  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11720  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11721  templ_p->SetAccessor(v8_str("y"), Return239Callback);
11722
11723  LocalContext context;
11724  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11725  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11726
11727  v8::Handle<Value> value = CompileRun(
11728    "o.__proto__ = p;"
11729    "for (var i = 0; i < 7; i++) {"
11730    "  o.x;"
11731    // Now it should be ICed and keep a reference to x defined on p
11732    "}"
11733    "var result = 0;"
11734    "for (var i = 0; i < 7; i++) {"
11735    "  result += o.x;"
11736    "}"
11737    "result");
11738  CHECK_EQ(42 * 7, value->Int32Value());
11739}
11740
11741
11742// Test the case when we stored callback into
11743// a stub, but it got invalidated later on.
11744THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11745  v8::Isolate* isolate = CcTest::isolate();
11746  v8::HandleScope scope(isolate);
11747  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11748  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11749  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11750  templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11751
11752  LocalContext context;
11753  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11754  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11755
11756  v8::Handle<Value> value = CompileRun(
11757    "inbetween = new Object();"
11758    "o.__proto__ = inbetween;"
11759    "inbetween.__proto__ = p;"
11760    "for (var i = 0; i < 10; i++) {"
11761    "  o.y;"
11762    // Now it should be ICed and keep a reference to y defined on p
11763    "}"
11764    "inbetween.y = 42;"
11765    "var result = 0;"
11766    "for (var i = 0; i < 10; i++) {"
11767    "  result += o.y;"
11768    "}"
11769    "result");
11770  CHECK_EQ(42 * 10, value->Int32Value());
11771}
11772
11773
11774// Test the case when we stored callback into
11775// a stub, but it got invalidated later on due to override on
11776// global object which is between interceptor and callbacks' holders.
11777THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11778  v8::Isolate* isolate = CcTest::isolate();
11779  v8::HandleScope scope(isolate);
11780  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11781  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11782  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11783  templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11784
11785  LocalContext context;
11786  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11787  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11788
11789  v8::Handle<Value> value = CompileRun(
11790    "o.__proto__ = this;"
11791    "this.__proto__ = p;"
11792    "for (var i = 0; i < 10; i++) {"
11793    "  if (o.y != 239) throw 'oops: ' + o.y;"
11794    // Now it should be ICed and keep a reference to y defined on p
11795    "}"
11796    "this.y = 42;"
11797    "var result = 0;"
11798    "for (var i = 0; i < 10; i++) {"
11799    "  result += o.y;"
11800    "}"
11801    "result");
11802  CHECK_EQ(42 * 10, value->Int32Value());
11803}
11804
11805
11806static void InterceptorLoadICGetter0(
11807    Local<String> name,
11808    const v8::PropertyCallbackInfo<v8::Value>& info) {
11809  ApiTestFuzzer::Fuzz();
11810  CHECK(v8_str("x")->Equals(name));
11811  info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11812}
11813
11814
11815THREADED_TEST(InterceptorReturningZero) {
11816  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11817     "o.x == undefined ? 1 : 0",
11818     0);
11819}
11820
11821
11822static void InterceptorStoreICSetter(
11823    Local<String> key,
11824    Local<Value> value,
11825    const v8::PropertyCallbackInfo<v8::Value>& info) {
11826  CHECK(v8_str("x")->Equals(key));
11827  CHECK_EQ(42, value->Int32Value());
11828  info.GetReturnValue().Set(value);
11829}
11830
11831
11832// This test should hit the store IC for the interceptor case.
11833THREADED_TEST(InterceptorStoreIC) {
11834  v8::Isolate* isolate = CcTest::isolate();
11835  v8::HandleScope scope(isolate);
11836  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11837  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11838                                 InterceptorStoreICSetter,
11839                                 0, 0, 0, v8_str("data"));
11840  LocalContext context;
11841  context->Global()->Set(v8_str("o"), templ->NewInstance());
11842  CompileRun(
11843      "for (var i = 0; i < 1000; i++) {"
11844      "  o.x = 42;"
11845      "}");
11846}
11847
11848
11849THREADED_TEST(InterceptorStoreICWithNoSetter) {
11850  v8::Isolate* isolate = CcTest::isolate();
11851  v8::HandleScope scope(isolate);
11852  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11853  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11854  LocalContext context;
11855  context->Global()->Set(v8_str("o"), templ->NewInstance());
11856  v8::Handle<Value> value = CompileRun(
11857    "for (var i = 0; i < 1000; i++) {"
11858    "  o.y = 239;"
11859    "}"
11860    "42 + o.y");
11861  CHECK_EQ(239 + 42, value->Int32Value());
11862}
11863
11864
11865
11866
11867v8::Handle<Value> call_ic_function;
11868v8::Handle<Value> call_ic_function2;
11869v8::Handle<Value> call_ic_function3;
11870
11871static void InterceptorCallICGetter(
11872    Local<String> name,
11873    const v8::PropertyCallbackInfo<v8::Value>& info) {
11874  ApiTestFuzzer::Fuzz();
11875  CHECK(v8_str("x")->Equals(name));
11876  info.GetReturnValue().Set(call_ic_function);
11877}
11878
11879
11880// This test should hit the call IC for the interceptor case.
11881THREADED_TEST(InterceptorCallIC) {
11882  v8::Isolate* isolate = CcTest::isolate();
11883  v8::HandleScope scope(isolate);
11884  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11885  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11886  LocalContext context;
11887  context->Global()->Set(v8_str("o"), templ->NewInstance());
11888  call_ic_function =
11889      v8_compile("function f(x) { return x + 1; }; f")->Run();
11890  v8::Handle<Value> value = CompileRun(
11891    "var result = 0;"
11892    "for (var i = 0; i < 1000; i++) {"
11893    "  result = o.x(41);"
11894    "}");
11895  CHECK_EQ(42, value->Int32Value());
11896}
11897
11898
11899// This test checks that if interceptor doesn't provide
11900// a value, we can fetch regular value.
11901THREADED_TEST(InterceptorCallICSeesOthers) {
11902  v8::Isolate* isolate = CcTest::isolate();
11903  v8::HandleScope scope(isolate);
11904  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11905  templ->SetNamedPropertyHandler(NoBlockGetterX);
11906  LocalContext context;
11907  context->Global()->Set(v8_str("o"), templ->NewInstance());
11908  v8::Handle<Value> value = CompileRun(
11909    "o.x = function f(x) { return x + 1; };"
11910    "var result = 0;"
11911    "for (var i = 0; i < 7; i++) {"
11912    "  result = o.x(41);"
11913    "}");
11914  CHECK_EQ(42, value->Int32Value());
11915}
11916
11917
11918static v8::Handle<Value> call_ic_function4;
11919static void InterceptorCallICGetter4(
11920    Local<String> name,
11921    const v8::PropertyCallbackInfo<v8::Value>& info) {
11922  ApiTestFuzzer::Fuzz();
11923  CHECK(v8_str("x")->Equals(name));
11924  info.GetReturnValue().Set(call_ic_function4);
11925}
11926
11927
11928// This test checks that if interceptor provides a function,
11929// even if we cached shadowed variant, interceptor's function
11930// is invoked
11931THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11932  v8::Isolate* isolate = CcTest::isolate();
11933  v8::HandleScope scope(isolate);
11934  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11935  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11936  LocalContext context;
11937  context->Global()->Set(v8_str("o"), templ->NewInstance());
11938  call_ic_function4 =
11939      v8_compile("function f(x) { return x - 1; }; f")->Run();
11940  v8::Handle<Value> value = CompileRun(
11941    "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11942    "var result = 0;"
11943    "for (var i = 0; i < 1000; i++) {"
11944    "  result = o.x(42);"
11945    "}");
11946  CHECK_EQ(41, value->Int32Value());
11947}
11948
11949
11950// Test the case when we stored cacheable lookup into
11951// a stub, but it got invalidated later on
11952THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11953  v8::Isolate* isolate = CcTest::isolate();
11954  v8::HandleScope scope(isolate);
11955  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11956  templ->SetNamedPropertyHandler(NoBlockGetterX);
11957  LocalContext context;
11958  context->Global()->Set(v8_str("o"), templ->NewInstance());
11959  v8::Handle<Value> value = CompileRun(
11960    "proto1 = new Object();"
11961    "proto2 = new Object();"
11962    "o.__proto__ = proto1;"
11963    "proto1.__proto__ = proto2;"
11964    "proto2.y = function(x) { return x + 1; };"
11965    // Invoke it many times to compile a stub
11966    "for (var i = 0; i < 7; i++) {"
11967    "  o.y(42);"
11968    "}"
11969    "proto1.y = function(x) { return x - 1; };"
11970    "var result = 0;"
11971    "for (var i = 0; i < 7; i++) {"
11972    "  result += o.y(42);"
11973    "}");
11974  CHECK_EQ(41 * 7, value->Int32Value());
11975}
11976
11977
11978// This test checks that if interceptor doesn't provide a function,
11979// cached constant function is used
11980THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11981  v8::Isolate* isolate = CcTest::isolate();
11982  v8::HandleScope scope(isolate);
11983  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11984  templ->SetNamedPropertyHandler(NoBlockGetterX);
11985  LocalContext context;
11986  context->Global()->Set(v8_str("o"), templ->NewInstance());
11987  v8::Handle<Value> value = CompileRun(
11988    "function inc(x) { return x + 1; };"
11989    "inc(1);"
11990    "o.x = inc;"
11991    "var result = 0;"
11992    "for (var i = 0; i < 1000; i++) {"
11993    "  result = o.x(42);"
11994    "}");
11995  CHECK_EQ(43, value->Int32Value());
11996}
11997
11998
11999static v8::Handle<Value> call_ic_function5;
12000static void InterceptorCallICGetter5(
12001    Local<String> name,
12002    const v8::PropertyCallbackInfo<v8::Value>& info) {
12003  ApiTestFuzzer::Fuzz();
12004  if (v8_str("x")->Equals(name))
12005    info.GetReturnValue().Set(call_ic_function5);
12006}
12007
12008
12009// This test checks that if interceptor provides a function,
12010// even if we cached constant function, interceptor's function
12011// is invoked
12012THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
12013  v8::Isolate* isolate = CcTest::isolate();
12014  v8::HandleScope scope(isolate);
12015  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12016  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
12017  LocalContext context;
12018  context->Global()->Set(v8_str("o"), templ->NewInstance());
12019  call_ic_function5 =
12020      v8_compile("function f(x) { return x - 1; }; f")->Run();
12021  v8::Handle<Value> value = CompileRun(
12022    "function inc(x) { return x + 1; };"
12023    "inc(1);"
12024    "o.x = inc;"
12025    "var result = 0;"
12026    "for (var i = 0; i < 1000; i++) {"
12027    "  result = o.x(42);"
12028    "}");
12029  CHECK_EQ(41, value->Int32Value());
12030}
12031
12032
12033static v8::Handle<Value> call_ic_function6;
12034static void InterceptorCallICGetter6(
12035    Local<String> name,
12036    const v8::PropertyCallbackInfo<v8::Value>& info) {
12037  ApiTestFuzzer::Fuzz();
12038  if (v8_str("x")->Equals(name))
12039    info.GetReturnValue().Set(call_ic_function6);
12040}
12041
12042
12043// Same test as above, except the code is wrapped in a function
12044// to test the optimized compiler.
12045THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
12046  i::FLAG_allow_natives_syntax = true;
12047  v8::Isolate* isolate = CcTest::isolate();
12048  v8::HandleScope scope(isolate);
12049  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12050  templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
12051  LocalContext context;
12052  context->Global()->Set(v8_str("o"), templ->NewInstance());
12053  call_ic_function6 =
12054      v8_compile("function f(x) { return x - 1; }; f")->Run();
12055  v8::Handle<Value> value = CompileRun(
12056    "function inc(x) { return x + 1; };"
12057    "inc(1);"
12058    "o.x = inc;"
12059    "function test() {"
12060    "  var result = 0;"
12061    "  for (var i = 0; i < 1000; i++) {"
12062    "    result = o.x(42);"
12063    "  }"
12064    "  return result;"
12065    "};"
12066    "test();"
12067    "test();"
12068    "test();"
12069    "%OptimizeFunctionOnNextCall(test);"
12070    "test()");
12071  CHECK_EQ(41, value->Int32Value());
12072}
12073
12074
12075// Test the case when we stored constant function into
12076// a stub, but it got invalidated later on
12077THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
12078  v8::Isolate* isolate = CcTest::isolate();
12079  v8::HandleScope scope(isolate);
12080  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12081  templ->SetNamedPropertyHandler(NoBlockGetterX);
12082  LocalContext context;
12083  context->Global()->Set(v8_str("o"), templ->NewInstance());
12084  v8::Handle<Value> value = CompileRun(
12085    "function inc(x) { return x + 1; };"
12086    "inc(1);"
12087    "proto1 = new Object();"
12088    "proto2 = new Object();"
12089    "o.__proto__ = proto1;"
12090    "proto1.__proto__ = proto2;"
12091    "proto2.y = inc;"
12092    // Invoke it many times to compile a stub
12093    "for (var i = 0; i < 7; i++) {"
12094    "  o.y(42);"
12095    "}"
12096    "proto1.y = function(x) { return x - 1; };"
12097    "var result = 0;"
12098    "for (var i = 0; i < 7; i++) {"
12099    "  result += o.y(42);"
12100    "}");
12101  CHECK_EQ(41 * 7, value->Int32Value());
12102}
12103
12104
12105// Test the case when we stored constant function into
12106// a stub, but it got invalidated later on due to override on
12107// global object which is between interceptor and constant function' holders.
12108THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
12109  v8::Isolate* isolate = CcTest::isolate();
12110  v8::HandleScope scope(isolate);
12111  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12112  templ->SetNamedPropertyHandler(NoBlockGetterX);
12113  LocalContext context;
12114  context->Global()->Set(v8_str("o"), templ->NewInstance());
12115  v8::Handle<Value> value = CompileRun(
12116    "function inc(x) { return x + 1; };"
12117    "inc(1);"
12118    "o.__proto__ = this;"
12119    "this.__proto__.y = inc;"
12120    // Invoke it many times to compile a stub
12121    "for (var i = 0; i < 7; i++) {"
12122    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
12123    "}"
12124    "this.y = function(x) { return x - 1; };"
12125    "var result = 0;"
12126    "for (var i = 0; i < 7; i++) {"
12127    "  result += o.y(42);"
12128    "}");
12129  CHECK_EQ(41 * 7, value->Int32Value());
12130}
12131
12132
12133// Test the case when actual function to call sits on global object.
12134THREADED_TEST(InterceptorCallICCachedFromGlobal) {
12135  v8::Isolate* isolate = CcTest::isolate();
12136  v8::HandleScope scope(isolate);
12137  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12138  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12139
12140  LocalContext context;
12141  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12142
12143  v8::Handle<Value> value = CompileRun(
12144    "try {"
12145    "  o.__proto__ = this;"
12146    "  for (var i = 0; i < 10; i++) {"
12147    "    var v = o.parseFloat('239');"
12148    "    if (v != 239) throw v;"
12149      // Now it should be ICed and keep a reference to parseFloat.
12150    "  }"
12151    "  var result = 0;"
12152    "  for (var i = 0; i < 10; i++) {"
12153    "    result += o.parseFloat('239');"
12154    "  }"
12155    "  result"
12156    "} catch(e) {"
12157    "  e"
12158    "};");
12159  CHECK_EQ(239 * 10, value->Int32Value());
12160}
12161
12162static void InterceptorCallICFastApi(
12163    Local<String> name,
12164    const v8::PropertyCallbackInfo<v8::Value>& info) {
12165  ApiTestFuzzer::Fuzz();
12166  CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12167  int* call_count =
12168      reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12169  ++(*call_count);
12170  if ((*call_count) % 20 == 0) {
12171    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12172  }
12173}
12174
12175static void FastApiCallback_TrivialSignature(
12176    const v8::FunctionCallbackInfo<v8::Value>& args) {
12177  ApiTestFuzzer::Fuzz();
12178  CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12179  v8::Isolate* isolate = CcTest::isolate();
12180  CHECK_EQ(isolate, args.GetIsolate());
12181  CHECK_EQ(args.This(), args.Holder());
12182  CHECK(args.Data()->Equals(v8_str("method_data")));
12183  args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12184}
12185
12186static void FastApiCallback_SimpleSignature(
12187    const v8::FunctionCallbackInfo<v8::Value>& args) {
12188  ApiTestFuzzer::Fuzz();
12189  CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12190  v8::Isolate* isolate = CcTest::isolate();
12191  CHECK_EQ(isolate, args.GetIsolate());
12192  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12193  CHECK(args.Data()->Equals(v8_str("method_data")));
12194  // Note, we're using HasRealNamedProperty instead of Has to avoid
12195  // invoking the interceptor again.
12196  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12197  args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12198}
12199
12200
12201// Helper to maximize the odds of object moving.
12202static void GenerateSomeGarbage() {
12203  CompileRun(
12204      "var garbage;"
12205      "for (var i = 0; i < 1000; i++) {"
12206      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12207      "}"
12208      "garbage = undefined;");
12209}
12210
12211
12212void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12213  static int count = 0;
12214  if (count++ % 3 == 0) {
12215    CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12216        // This should move the stub
12217    GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
12218  }
12219}
12220
12221
12222THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12223  LocalContext context;
12224  v8::Isolate* isolate = context->GetIsolate();
12225  v8::HandleScope scope(isolate);
12226  v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12227      v8::ObjectTemplate::New(isolate);
12228  nativeobject_templ->Set(isolate, "callback",
12229                          v8::FunctionTemplate::New(isolate,
12230                                                    DirectApiCallback));
12231  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12232  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12233  // call the api function multiple times to ensure direct call stub creation.
12234  CompileRun(
12235        "function f() {"
12236        "  for (var i = 1; i <= 30; i++) {"
12237        "    nativeobject.callback();"
12238        "  }"
12239        "}"
12240        "f();");
12241}
12242
12243
12244void ThrowingDirectApiCallback(
12245    const v8::FunctionCallbackInfo<v8::Value>& args) {
12246  args.GetIsolate()->ThrowException(v8_str("g"));
12247}
12248
12249
12250THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12251  LocalContext context;
12252  v8::Isolate* isolate = context->GetIsolate();
12253  v8::HandleScope scope(isolate);
12254  v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12255      v8::ObjectTemplate::New(isolate);
12256  nativeobject_templ->Set(isolate, "callback",
12257                          v8::FunctionTemplate::New(isolate,
12258                                                    ThrowingDirectApiCallback));
12259  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12260  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12261  // call the api function multiple times to ensure direct call stub creation.
12262  v8::Handle<Value> result = CompileRun(
12263      "var result = '';"
12264      "function f() {"
12265      "  for (var i = 1; i <= 5; i++) {"
12266      "    try { nativeobject.callback(); } catch (e) { result += e; }"
12267      "  }"
12268      "}"
12269      "f(); result;");
12270  CHECK_EQ(v8_str("ggggg"), result);
12271}
12272
12273
12274static Handle<Value> DoDirectGetter() {
12275  if (++p_getter_count % 3 == 0) {
12276    CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12277    GenerateSomeGarbage();
12278  }
12279  return v8_str("Direct Getter Result");
12280}
12281
12282static void DirectGetterCallback(
12283    Local<String> name,
12284    const v8::PropertyCallbackInfo<v8::Value>& info) {
12285  CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12286  info.GetReturnValue().Set(DoDirectGetter());
12287}
12288
12289
12290template<typename Accessor>
12291static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12292  LocalContext context;
12293  v8::Isolate* isolate = context->GetIsolate();
12294  v8::HandleScope scope(isolate);
12295  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12296  obj->SetAccessor(v8_str("p1"), accessor);
12297  context->Global()->Set(v8_str("o1"), obj->NewInstance());
12298  p_getter_count = 0;
12299  v8::Handle<v8::Value> result = CompileRun(
12300      "function f() {"
12301      "  for (var i = 0; i < 30; i++) o1.p1;"
12302      "  return o1.p1"
12303      "}"
12304      "f();");
12305  CHECK_EQ(v8_str("Direct Getter Result"), result);
12306  CHECK_EQ(31, p_getter_count);
12307}
12308
12309
12310THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12311  LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12312}
12313
12314
12315void ThrowingDirectGetterCallback(
12316    Local<String> name,
12317    const v8::PropertyCallbackInfo<v8::Value>& info) {
12318  info.GetIsolate()->ThrowException(v8_str("g"));
12319}
12320
12321
12322THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12323  LocalContext context;
12324  v8::Isolate* isolate = context->GetIsolate();
12325  v8::HandleScope scope(isolate);
12326  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12327  obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12328  context->Global()->Set(v8_str("o1"), obj->NewInstance());
12329  v8::Handle<Value> result = CompileRun(
12330      "var result = '';"
12331      "for (var i = 0; i < 5; i++) {"
12332      "    try { o1.p1; } catch (e) { result += e; }"
12333      "}"
12334      "result;");
12335  CHECK_EQ(v8_str("ggggg"), result);
12336}
12337
12338
12339THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12340  int interceptor_call_count = 0;
12341  v8::Isolate* isolate = CcTest::isolate();
12342  v8::HandleScope scope(isolate);
12343  v8::Handle<v8::FunctionTemplate> fun_templ =
12344      v8::FunctionTemplate::New(isolate);
12345  v8::Handle<v8::FunctionTemplate> method_templ =
12346      v8::FunctionTemplate::New(isolate,
12347                                FastApiCallback_TrivialSignature,
12348                                v8_str("method_data"),
12349                                v8::Handle<v8::Signature>());
12350  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12351  proto_templ->Set(v8_str("method"), method_templ);
12352  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12353  templ->SetNamedPropertyHandler(
12354      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12355      v8::External::New(isolate, &interceptor_call_count));
12356  LocalContext context;
12357  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12358  GenerateSomeGarbage();
12359  context->Global()->Set(v8_str("o"), fun->NewInstance());
12360  CompileRun(
12361      "var result = 0;"
12362      "for (var i = 0; i < 100; i++) {"
12363      "  result = o.method(41);"
12364      "}");
12365  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12366  CHECK_EQ(100, interceptor_call_count);
12367}
12368
12369
12370THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12371  int interceptor_call_count = 0;
12372  v8::Isolate* isolate = CcTest::isolate();
12373  v8::HandleScope scope(isolate);
12374  v8::Handle<v8::FunctionTemplate> fun_templ =
12375      v8::FunctionTemplate::New(isolate);
12376  v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12377      isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12378      v8::Signature::New(isolate, fun_templ));
12379  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12380  proto_templ->Set(v8_str("method"), method_templ);
12381  fun_templ->SetHiddenPrototype(true);
12382  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12383  templ->SetNamedPropertyHandler(
12384      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12385      v8::External::New(isolate, &interceptor_call_count));
12386  LocalContext context;
12387  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12388  GenerateSomeGarbage();
12389  context->Global()->Set(v8_str("o"), fun->NewInstance());
12390  CompileRun(
12391      "o.foo = 17;"
12392      "var receiver = {};"
12393      "receiver.__proto__ = o;"
12394      "var result = 0;"
12395      "for (var i = 0; i < 100; i++) {"
12396      "  result = receiver.method(41);"
12397      "}");
12398  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12399  CHECK_EQ(100, interceptor_call_count);
12400}
12401
12402
12403THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12404  int interceptor_call_count = 0;
12405  v8::Isolate* isolate = CcTest::isolate();
12406  v8::HandleScope scope(isolate);
12407  v8::Handle<v8::FunctionTemplate> fun_templ =
12408      v8::FunctionTemplate::New(isolate);
12409  v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12410      isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12411      v8::Signature::New(isolate, fun_templ));
12412  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12413  proto_templ->Set(v8_str("method"), method_templ);
12414  fun_templ->SetHiddenPrototype(true);
12415  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12416  templ->SetNamedPropertyHandler(
12417      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12418      v8::External::New(isolate, &interceptor_call_count));
12419  LocalContext context;
12420  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12421  GenerateSomeGarbage();
12422  context->Global()->Set(v8_str("o"), fun->NewInstance());
12423  CompileRun(
12424      "o.foo = 17;"
12425      "var receiver = {};"
12426      "receiver.__proto__ = o;"
12427      "var result = 0;"
12428      "var saved_result = 0;"
12429      "for (var i = 0; i < 100; i++) {"
12430      "  result = receiver.method(41);"
12431      "  if (i == 50) {"
12432      "    saved_result = result;"
12433      "    receiver = {method: function(x) { return x - 1 }};"
12434      "  }"
12435      "}");
12436  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12437  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12438  CHECK_GE(interceptor_call_count, 50);
12439}
12440
12441
12442THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12443  int interceptor_call_count = 0;
12444  v8::Isolate* isolate = CcTest::isolate();
12445  v8::HandleScope scope(isolate);
12446  v8::Handle<v8::FunctionTemplate> fun_templ =
12447      v8::FunctionTemplate::New(isolate);
12448  v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12449      isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12450      v8::Signature::New(isolate, fun_templ));
12451  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12452  proto_templ->Set(v8_str("method"), method_templ);
12453  fun_templ->SetHiddenPrototype(true);
12454  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12455  templ->SetNamedPropertyHandler(
12456      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12457      v8::External::New(isolate, &interceptor_call_count));
12458  LocalContext context;
12459  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12460  GenerateSomeGarbage();
12461  context->Global()->Set(v8_str("o"), fun->NewInstance());
12462  CompileRun(
12463      "o.foo = 17;"
12464      "var receiver = {};"
12465      "receiver.__proto__ = o;"
12466      "var result = 0;"
12467      "var saved_result = 0;"
12468      "for (var i = 0; i < 100; i++) {"
12469      "  result = receiver.method(41);"
12470      "  if (i == 50) {"
12471      "    saved_result = result;"
12472      "    o.method = function(x) { return x - 1 };"
12473      "  }"
12474      "}");
12475  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12476  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12477  CHECK_GE(interceptor_call_count, 50);
12478}
12479
12480
12481THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12482  int interceptor_call_count = 0;
12483  v8::Isolate* isolate = CcTest::isolate();
12484  v8::HandleScope scope(isolate);
12485  v8::Handle<v8::FunctionTemplate> fun_templ =
12486      v8::FunctionTemplate::New(isolate);
12487  v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12488      isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12489      v8::Signature::New(isolate, fun_templ));
12490  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12491  proto_templ->Set(v8_str("method"), method_templ);
12492  fun_templ->SetHiddenPrototype(true);
12493  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12494  templ->SetNamedPropertyHandler(
12495      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12496      v8::External::New(isolate, &interceptor_call_count));
12497  LocalContext context;
12498  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12499  GenerateSomeGarbage();
12500  context->Global()->Set(v8_str("o"), fun->NewInstance());
12501  v8::TryCatch try_catch;
12502  CompileRun(
12503      "o.foo = 17;"
12504      "var receiver = {};"
12505      "receiver.__proto__ = o;"
12506      "var result = 0;"
12507      "var saved_result = 0;"
12508      "for (var i = 0; i < 100; i++) {"
12509      "  result = receiver.method(41);"
12510      "  if (i == 50) {"
12511      "    saved_result = result;"
12512      "    receiver = 333;"
12513      "  }"
12514      "}");
12515  CHECK(try_catch.HasCaught());
12516  // TODO(verwaest): Adjust message.
12517  CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12518           try_catch.Exception()->ToString());
12519  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12520  CHECK_GE(interceptor_call_count, 50);
12521}
12522
12523
12524THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12525  int interceptor_call_count = 0;
12526  v8::Isolate* isolate = CcTest::isolate();
12527  v8::HandleScope scope(isolate);
12528  v8::Handle<v8::FunctionTemplate> fun_templ =
12529      v8::FunctionTemplate::New(isolate);
12530  v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12531      isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12532      v8::Signature::New(isolate, fun_templ));
12533  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12534  proto_templ->Set(v8_str("method"), method_templ);
12535  fun_templ->SetHiddenPrototype(true);
12536  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12537  templ->SetNamedPropertyHandler(
12538      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12539      v8::External::New(isolate, &interceptor_call_count));
12540  LocalContext context;
12541  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12542  GenerateSomeGarbage();
12543  context->Global()->Set(v8_str("o"), fun->NewInstance());
12544  v8::TryCatch try_catch;
12545  CompileRun(
12546      "o.foo = 17;"
12547      "var receiver = {};"
12548      "receiver.__proto__ = o;"
12549      "var result = 0;"
12550      "var saved_result = 0;"
12551      "for (var i = 0; i < 100; i++) {"
12552      "  result = receiver.method(41);"
12553      "  if (i == 50) {"
12554      "    saved_result = result;"
12555      "    receiver = {method: receiver.method};"
12556      "  }"
12557      "}");
12558  CHECK(try_catch.HasCaught());
12559  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12560           try_catch.Exception()->ToString());
12561  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12562  CHECK_GE(interceptor_call_count, 50);
12563}
12564
12565
12566THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12567  v8::Isolate* isolate = CcTest::isolate();
12568  v8::HandleScope scope(isolate);
12569  v8::Handle<v8::FunctionTemplate> fun_templ =
12570      v8::FunctionTemplate::New(isolate);
12571  v8::Handle<v8::FunctionTemplate> method_templ =
12572      v8::FunctionTemplate::New(isolate,
12573                                FastApiCallback_TrivialSignature,
12574                                v8_str("method_data"),
12575                                v8::Handle<v8::Signature>());
12576  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12577  proto_templ->Set(v8_str("method"), method_templ);
12578  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12579  USE(templ);
12580  LocalContext context;
12581  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12582  GenerateSomeGarbage();
12583  context->Global()->Set(v8_str("o"), fun->NewInstance());
12584  CompileRun(
12585      "var result = 0;"
12586      "for (var i = 0; i < 100; i++) {"
12587      "  result = o.method(41);"
12588      "}");
12589
12590  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12591}
12592
12593
12594THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12595  v8::Isolate* isolate = CcTest::isolate();
12596  v8::HandleScope scope(isolate);
12597  v8::Handle<v8::FunctionTemplate> fun_templ =
12598      v8::FunctionTemplate::New(isolate);
12599  v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12600      isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12601      v8::Signature::New(isolate, fun_templ));
12602  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12603  proto_templ->Set(v8_str("method"), method_templ);
12604  fun_templ->SetHiddenPrototype(true);
12605  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12606  CHECK(!templ.IsEmpty());
12607  LocalContext context;
12608  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12609  GenerateSomeGarbage();
12610  context->Global()->Set(v8_str("o"), fun->NewInstance());
12611  CompileRun(
12612      "o.foo = 17;"
12613      "var receiver = {};"
12614      "receiver.__proto__ = o;"
12615      "var result = 0;"
12616      "for (var i = 0; i < 100; i++) {"
12617      "  result = receiver.method(41);"
12618      "}");
12619
12620  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12621}
12622
12623
12624THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12625  v8::Isolate* isolate = CcTest::isolate();
12626  v8::HandleScope scope(isolate);
12627  v8::Handle<v8::FunctionTemplate> fun_templ =
12628      v8::FunctionTemplate::New(isolate);
12629  v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12630      isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12631      v8::Signature::New(isolate, fun_templ));
12632  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12633  proto_templ->Set(v8_str("method"), method_templ);
12634  fun_templ->SetHiddenPrototype(true);
12635  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12636  CHECK(!templ.IsEmpty());
12637  LocalContext context;
12638  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12639  GenerateSomeGarbage();
12640  context->Global()->Set(v8_str("o"), fun->NewInstance());
12641  CompileRun(
12642      "o.foo = 17;"
12643      "var receiver = {};"
12644      "receiver.__proto__ = o;"
12645      "var result = 0;"
12646      "var saved_result = 0;"
12647      "for (var i = 0; i < 100; i++) {"
12648      "  result = receiver.method(41);"
12649      "  if (i == 50) {"
12650      "    saved_result = result;"
12651      "    receiver = {method: function(x) { return x - 1 }};"
12652      "  }"
12653      "}");
12654  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12655  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12656}
12657
12658
12659THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12660  v8::Isolate* isolate = CcTest::isolate();
12661  v8::HandleScope scope(isolate);
12662  v8::Handle<v8::FunctionTemplate> fun_templ =
12663      v8::FunctionTemplate::New(isolate);
12664  v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12665      isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12666      v8::Signature::New(isolate, fun_templ));
12667  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12668  proto_templ->Set(v8_str("method"), method_templ);
12669  fun_templ->SetHiddenPrototype(true);
12670  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12671  CHECK(!templ.IsEmpty());
12672  LocalContext context;
12673  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12674  GenerateSomeGarbage();
12675  context->Global()->Set(v8_str("o"), fun->NewInstance());
12676  v8::TryCatch try_catch;
12677  CompileRun(
12678      "o.foo = 17;"
12679      "var receiver = {};"
12680      "receiver.__proto__ = o;"
12681      "var result = 0;"
12682      "var saved_result = 0;"
12683      "for (var i = 0; i < 100; i++) {"
12684      "  result = receiver.method(41);"
12685      "  if (i == 50) {"
12686      "    saved_result = result;"
12687      "    receiver = 333;"
12688      "  }"
12689      "}");
12690  CHECK(try_catch.HasCaught());
12691  // TODO(verwaest): Adjust message.
12692  CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12693           try_catch.Exception()->ToString());
12694  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12695}
12696
12697
12698THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12699  v8::Isolate* isolate = CcTest::isolate();
12700  v8::HandleScope scope(isolate);
12701  v8::Handle<v8::FunctionTemplate> fun_templ =
12702      v8::FunctionTemplate::New(isolate);
12703  v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12704      isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12705      v8::Signature::New(isolate, fun_templ));
12706  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12707  proto_templ->Set(v8_str("method"), method_templ);
12708  fun_templ->SetHiddenPrototype(true);
12709  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12710  CHECK(!templ.IsEmpty());
12711  LocalContext context;
12712  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12713  GenerateSomeGarbage();
12714  context->Global()->Set(v8_str("o"), fun->NewInstance());
12715  v8::TryCatch try_catch;
12716  CompileRun(
12717      "o.foo = 17;"
12718      "var receiver = {};"
12719      "receiver.__proto__ = o;"
12720      "var result = 0;"
12721      "var saved_result = 0;"
12722      "for (var i = 0; i < 100; i++) {"
12723      "  result = receiver.method(41);"
12724      "  if (i == 50) {"
12725      "    saved_result = result;"
12726      "    receiver = Object.create(receiver);"
12727      "  }"
12728      "}");
12729  CHECK(try_catch.HasCaught());
12730  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12731           try_catch.Exception()->ToString());
12732  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12733}
12734
12735
12736v8::Handle<Value> keyed_call_ic_function;
12737
12738static void InterceptorKeyedCallICGetter(
12739    Local<String> name,
12740    const v8::PropertyCallbackInfo<v8::Value>& info) {
12741  ApiTestFuzzer::Fuzz();
12742  if (v8_str("x")->Equals(name)) {
12743    info.GetReturnValue().Set(keyed_call_ic_function);
12744  }
12745}
12746
12747
12748// Test the case when we stored cacheable lookup into
12749// a stub, but the function name changed (to another cacheable function).
12750THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12751  v8::Isolate* isolate = CcTest::isolate();
12752  v8::HandleScope scope(isolate);
12753  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12754  templ->SetNamedPropertyHandler(NoBlockGetterX);
12755  LocalContext context;
12756  context->Global()->Set(v8_str("o"), templ->NewInstance());
12757  CompileRun(
12758    "proto = new Object();"
12759    "proto.y = function(x) { return x + 1; };"
12760    "proto.z = function(x) { return x - 1; };"
12761    "o.__proto__ = proto;"
12762    "var result = 0;"
12763    "var method = 'y';"
12764    "for (var i = 0; i < 10; i++) {"
12765    "  if (i == 5) { method = 'z'; };"
12766    "  result += o[method](41);"
12767    "}");
12768  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12769}
12770
12771
12772// Test the case when we stored cacheable lookup into
12773// a stub, but the function name changed (and the new function is present
12774// both before and after the interceptor in the prototype chain).
12775THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12776  v8::Isolate* isolate = CcTest::isolate();
12777  v8::HandleScope scope(isolate);
12778  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12779  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12780  LocalContext context;
12781  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12782  keyed_call_ic_function =
12783      v8_compile("function f(x) { return x - 1; }; f")->Run();
12784  CompileRun(
12785    "o = new Object();"
12786    "proto2 = new Object();"
12787    "o.y = function(x) { return x + 1; };"
12788    "proto2.y = function(x) { return x + 2; };"
12789    "o.__proto__ = proto1;"
12790    "proto1.__proto__ = proto2;"
12791    "var result = 0;"
12792    "var method = 'x';"
12793    "for (var i = 0; i < 10; i++) {"
12794    "  if (i == 5) { method = 'y'; };"
12795    "  result += o[method](41);"
12796    "}");
12797  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12798}
12799
12800
12801// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12802// on the global object.
12803THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12804  v8::Isolate* isolate = CcTest::isolate();
12805  v8::HandleScope scope(isolate);
12806  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12807  templ->SetNamedPropertyHandler(NoBlockGetterX);
12808  LocalContext context;
12809  context->Global()->Set(v8_str("o"), templ->NewInstance());
12810  CompileRun(
12811    "function inc(x) { return x + 1; };"
12812    "inc(1);"
12813    "function dec(x) { return x - 1; };"
12814    "dec(1);"
12815    "o.__proto__ = this;"
12816    "this.__proto__.x = inc;"
12817    "this.__proto__.y = dec;"
12818    "var result = 0;"
12819    "var method = 'x';"
12820    "for (var i = 0; i < 10; i++) {"
12821    "  if (i == 5) { method = 'y'; };"
12822    "  result += o[method](41);"
12823    "}");
12824  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12825}
12826
12827
12828// Test the case when actual function to call sits on global object.
12829THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12830  v8::Isolate* isolate = CcTest::isolate();
12831  v8::HandleScope scope(isolate);
12832  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12833  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12834  LocalContext context;
12835  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12836
12837  CompileRun(
12838    "function len(x) { return x.length; };"
12839    "o.__proto__ = this;"
12840    "var m = 'parseFloat';"
12841    "var result = 0;"
12842    "for (var i = 0; i < 10; i++) {"
12843    "  if (i == 5) {"
12844    "    m = 'len';"
12845    "    saved_result = result;"
12846    "  };"
12847    "  result = o[m]('239');"
12848    "}");
12849  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12850  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12851}
12852
12853
12854// Test the map transition before the interceptor.
12855THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12856  v8::Isolate* isolate = CcTest::isolate();
12857  v8::HandleScope scope(isolate);
12858  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12859  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12860  LocalContext context;
12861  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12862
12863  CompileRun(
12864    "var o = new Object();"
12865    "o.__proto__ = proto;"
12866    "o.method = function(x) { return x + 1; };"
12867    "var m = 'method';"
12868    "var result = 0;"
12869    "for (var i = 0; i < 10; i++) {"
12870    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
12871    "  result += o[m](41);"
12872    "}");
12873  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12874}
12875
12876
12877// Test the map transition after the interceptor.
12878THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12879  v8::Isolate* isolate = CcTest::isolate();
12880  v8::HandleScope scope(isolate);
12881  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12882  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12883  LocalContext context;
12884  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12885
12886  CompileRun(
12887    "var proto = new Object();"
12888    "o.__proto__ = proto;"
12889    "proto.method = function(x) { return x + 1; };"
12890    "var m = 'method';"
12891    "var result = 0;"
12892    "for (var i = 0; i < 10; i++) {"
12893    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12894    "  result += o[m](41);"
12895    "}");
12896  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12897}
12898
12899
12900static int interceptor_call_count = 0;
12901
12902static void InterceptorICRefErrorGetter(
12903    Local<String> name,
12904    const v8::PropertyCallbackInfo<v8::Value>& info) {
12905  ApiTestFuzzer::Fuzz();
12906  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12907    info.GetReturnValue().Set(call_ic_function2);
12908  }
12909}
12910
12911
12912// This test should hit load and call ICs for the interceptor case.
12913// Once in a while, the interceptor will reply that a property was not
12914// found in which case we should get a reference error.
12915THREADED_TEST(InterceptorICReferenceErrors) {
12916  v8::Isolate* isolate = CcTest::isolate();
12917  v8::HandleScope scope(isolate);
12918  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12919  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12920  LocalContext context(0, templ, v8::Handle<Value>());
12921  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12922  v8::Handle<Value> value = CompileRun(
12923    "function f() {"
12924    "  for (var i = 0; i < 1000; i++) {"
12925    "    try { x; } catch(e) { return true; }"
12926    "  }"
12927    "  return false;"
12928    "};"
12929    "f();");
12930  CHECK_EQ(true, value->BooleanValue());
12931  interceptor_call_count = 0;
12932  value = CompileRun(
12933    "function g() {"
12934    "  for (var i = 0; i < 1000; i++) {"
12935    "    try { x(42); } catch(e) { return true; }"
12936    "  }"
12937    "  return false;"
12938    "};"
12939    "g();");
12940  CHECK_EQ(true, value->BooleanValue());
12941}
12942
12943
12944static int interceptor_ic_exception_get_count = 0;
12945
12946static void InterceptorICExceptionGetter(
12947    Local<String> name,
12948    const v8::PropertyCallbackInfo<v8::Value>& info) {
12949  ApiTestFuzzer::Fuzz();
12950  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12951    info.GetReturnValue().Set(call_ic_function3);
12952  }
12953  if (interceptor_ic_exception_get_count == 20) {
12954    info.GetIsolate()->ThrowException(v8_num(42));
12955    return;
12956  }
12957}
12958
12959
12960// Test interceptor load/call IC where the interceptor throws an
12961// exception once in a while.
12962THREADED_TEST(InterceptorICGetterExceptions) {
12963  interceptor_ic_exception_get_count = 0;
12964  v8::Isolate* isolate = CcTest::isolate();
12965  v8::HandleScope scope(isolate);
12966  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12967  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12968  LocalContext context(0, templ, v8::Handle<Value>());
12969  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12970  v8::Handle<Value> value = CompileRun(
12971    "function f() {"
12972    "  for (var i = 0; i < 100; i++) {"
12973    "    try { x; } catch(e) { return true; }"
12974    "  }"
12975    "  return false;"
12976    "};"
12977    "f();");
12978  CHECK_EQ(true, value->BooleanValue());
12979  interceptor_ic_exception_get_count = 0;
12980  value = CompileRun(
12981    "function f() {"
12982    "  for (var i = 0; i < 100; i++) {"
12983    "    try { x(42); } catch(e) { return true; }"
12984    "  }"
12985    "  return false;"
12986    "};"
12987    "f();");
12988  CHECK_EQ(true, value->BooleanValue());
12989}
12990
12991
12992static int interceptor_ic_exception_set_count = 0;
12993
12994static void InterceptorICExceptionSetter(
12995      Local<String> key,
12996      Local<Value> value,
12997      const v8::PropertyCallbackInfo<v8::Value>& info) {
12998  ApiTestFuzzer::Fuzz();
12999  if (++interceptor_ic_exception_set_count > 20) {
13000    info.GetIsolate()->ThrowException(v8_num(42));
13001  }
13002}
13003
13004
13005// Test interceptor store IC where the interceptor throws an exception
13006// once in a while.
13007THREADED_TEST(InterceptorICSetterExceptions) {
13008  interceptor_ic_exception_set_count = 0;
13009  v8::Isolate* isolate = CcTest::isolate();
13010  v8::HandleScope scope(isolate);
13011  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13012  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
13013  LocalContext context(0, templ, v8::Handle<Value>());
13014  v8::Handle<Value> value = CompileRun(
13015    "function f() {"
13016    "  for (var i = 0; i < 100; i++) {"
13017    "    try { x = 42; } catch(e) { return true; }"
13018    "  }"
13019    "  return false;"
13020    "};"
13021    "f();");
13022  CHECK_EQ(true, value->BooleanValue());
13023}
13024
13025
13026// Test that we ignore null interceptors.
13027THREADED_TEST(NullNamedInterceptor) {
13028  v8::Isolate* isolate = CcTest::isolate();
13029  v8::HandleScope scope(isolate);
13030  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13031  templ->SetNamedPropertyHandler(
13032      static_cast<v8::NamedPropertyGetterCallback>(0));
13033  LocalContext context;
13034  templ->Set(CcTest::isolate(), "x", v8_num(42));
13035  v8::Handle<v8::Object> obj = templ->NewInstance();
13036  context->Global()->Set(v8_str("obj"), obj);
13037  v8::Handle<Value> value = CompileRun("obj.x");
13038  CHECK(value->IsInt32());
13039  CHECK_EQ(42, value->Int32Value());
13040}
13041
13042
13043// Test that we ignore null interceptors.
13044THREADED_TEST(NullIndexedInterceptor) {
13045  v8::Isolate* isolate = CcTest::isolate();
13046  v8::HandleScope scope(isolate);
13047  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13048  templ->SetIndexedPropertyHandler(
13049      static_cast<v8::IndexedPropertyGetterCallback>(0));
13050  LocalContext context;
13051  templ->Set(CcTest::isolate(), "42", v8_num(42));
13052  v8::Handle<v8::Object> obj = templ->NewInstance();
13053  context->Global()->Set(v8_str("obj"), obj);
13054  v8::Handle<Value> value = CompileRun("obj[42]");
13055  CHECK(value->IsInt32());
13056  CHECK_EQ(42, value->Int32Value());
13057}
13058
13059
13060THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
13061  v8::Isolate* isolate = CcTest::isolate();
13062  v8::HandleScope scope(isolate);
13063  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13064  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
13065  LocalContext env;
13066  env->Global()->Set(v8_str("obj"),
13067                     templ->GetFunction()->NewInstance());
13068  ExpectTrue("obj.x === 42");
13069  ExpectTrue("!obj.propertyIsEnumerable('x')");
13070}
13071
13072
13073static void ThrowingGetter(Local<String> name,
13074                           const v8::PropertyCallbackInfo<v8::Value>& info) {
13075  ApiTestFuzzer::Fuzz();
13076  info.GetIsolate()->ThrowException(Handle<Value>());
13077  info.GetReturnValue().SetUndefined();
13078}
13079
13080
13081THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
13082  LocalContext context;
13083  HandleScope scope(context->GetIsolate());
13084
13085  Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
13086  Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13087  instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
13088
13089  Local<Object> instance = templ->GetFunction()->NewInstance();
13090
13091  Local<Object> another = Object::New(context->GetIsolate());
13092  another->SetPrototype(instance);
13093
13094  Local<Object> with_js_getter = CompileRun(
13095      "o = {};\n"
13096      "o.__defineGetter__('f', function() { throw undefined; });\n"
13097      "o\n").As<Object>();
13098  CHECK(!with_js_getter.IsEmpty());
13099
13100  TryCatch try_catch;
13101
13102  Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
13103  CHECK(try_catch.HasCaught());
13104  try_catch.Reset();
13105  CHECK(result.IsEmpty());
13106
13107  result = another->GetRealNamedProperty(v8_str("f"));
13108  CHECK(try_catch.HasCaught());
13109  try_catch.Reset();
13110  CHECK(result.IsEmpty());
13111
13112  result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
13113  CHECK(try_catch.HasCaught());
13114  try_catch.Reset();
13115  CHECK(result.IsEmpty());
13116
13117  result = another->Get(v8_str("f"));
13118  CHECK(try_catch.HasCaught());
13119  try_catch.Reset();
13120  CHECK(result.IsEmpty());
13121
13122  result = with_js_getter->GetRealNamedProperty(v8_str("f"));
13123  CHECK(try_catch.HasCaught());
13124  try_catch.Reset();
13125  CHECK(result.IsEmpty());
13126
13127  result = with_js_getter->Get(v8_str("f"));
13128  CHECK(try_catch.HasCaught());
13129  try_catch.Reset();
13130  CHECK(result.IsEmpty());
13131}
13132
13133
13134static void ThrowingCallbackWithTryCatch(
13135    const v8::FunctionCallbackInfo<v8::Value>& args) {
13136  TryCatch try_catch;
13137  // Verboseness is important: it triggers message delivery which can call into
13138  // external code.
13139  try_catch.SetVerbose(true);
13140  CompileRun("throw 'from JS';");
13141  CHECK(try_catch.HasCaught());
13142  CHECK(!CcTest::i_isolate()->has_pending_exception());
13143  CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13144}
13145
13146
13147static int call_depth;
13148
13149
13150static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13151  TryCatch try_catch;
13152}
13153
13154
13155static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13156  if (--call_depth) CompileRun("throw 'ThrowInJS';");
13157}
13158
13159
13160static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13161  if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13162}
13163
13164
13165static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13166  Handle<String> errorMessageString = message->Get();
13167  CHECK(!errorMessageString.IsEmpty());
13168  message->GetStackTrace();
13169  message->GetScriptOrigin().ResourceName();
13170}
13171
13172
13173THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13174  LocalContext context;
13175  v8::Isolate* isolate = context->GetIsolate();
13176  HandleScope scope(isolate);
13177
13178  Local<Function> func =
13179      FunctionTemplate::New(isolate,
13180                            ThrowingCallbackWithTryCatch)->GetFunction();
13181  context->Global()->Set(v8_str("func"), func);
13182
13183  MessageCallback callbacks[] =
13184      { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13185  for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13186    MessageCallback callback = callbacks[i];
13187    if (callback != NULL) {
13188      V8::AddMessageListener(callback);
13189    }
13190    // Some small number to control number of times message handler should
13191    // throw an exception.
13192    call_depth = 5;
13193    ExpectFalse(
13194        "var thrown = false;\n"
13195        "try { func(); } catch(e) { thrown = true; }\n"
13196        "thrown\n");
13197    if (callback != NULL) {
13198      V8::RemoveMessageListeners(callback);
13199    }
13200  }
13201}
13202
13203
13204static void ParentGetter(Local<String> name,
13205                         const v8::PropertyCallbackInfo<v8::Value>& info) {
13206  ApiTestFuzzer::Fuzz();
13207  info.GetReturnValue().Set(v8_num(1));
13208}
13209
13210
13211static void ChildGetter(Local<String> name,
13212                        const v8::PropertyCallbackInfo<v8::Value>& info) {
13213  ApiTestFuzzer::Fuzz();
13214  info.GetReturnValue().Set(v8_num(42));
13215}
13216
13217
13218THREADED_TEST(Overriding) {
13219  LocalContext context;
13220  v8::Isolate* isolate = context->GetIsolate();
13221  v8::HandleScope scope(isolate);
13222
13223  // Parent template.
13224  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13225  Local<ObjectTemplate> parent_instance_templ =
13226      parent_templ->InstanceTemplate();
13227  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13228
13229  // Template that inherits from the parent template.
13230  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13231  Local<ObjectTemplate> child_instance_templ =
13232      child_templ->InstanceTemplate();
13233  child_templ->Inherit(parent_templ);
13234  // Override 'f'.  The child version of 'f' should get called for child
13235  // instances.
13236  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13237  // Add 'g' twice.  The 'g' added last should get called for instances.
13238  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13239  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13240
13241  // Add 'h' as an accessor to the proto template with ReadOnly attributes
13242  // so 'h' can be shadowed on the instance object.
13243  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13244  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13245      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13246
13247  // Add 'i' as an accessor to the instance template with ReadOnly attributes
13248  // but the attribute does not have effect because it is duplicated with
13249  // NULL setter.
13250  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13251      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13252
13253
13254
13255  // Instantiate the child template.
13256  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13257
13258  // Check that the child function overrides the parent one.
13259  context->Global()->Set(v8_str("o"), instance);
13260  Local<Value> value = v8_compile("o.f")->Run();
13261  // Check that the 'g' that was added last is hit.
13262  CHECK_EQ(42, value->Int32Value());
13263  value = v8_compile("o.g")->Run();
13264  CHECK_EQ(42, value->Int32Value());
13265
13266  // Check that 'h' cannot be shadowed.
13267  value = v8_compile("o.h = 3; o.h")->Run();
13268  CHECK_EQ(1, value->Int32Value());
13269
13270  // Check that 'i' cannot be shadowed or changed.
13271  value = v8_compile("o.i = 3; o.i")->Run();
13272  CHECK_EQ(42, value->Int32Value());
13273}
13274
13275
13276static void IsConstructHandler(
13277    const v8::FunctionCallbackInfo<v8::Value>& args) {
13278  ApiTestFuzzer::Fuzz();
13279  args.GetReturnValue().Set(args.IsConstructCall());
13280}
13281
13282
13283THREADED_TEST(IsConstructCall) {
13284  v8::Isolate* isolate = CcTest::isolate();
13285  v8::HandleScope scope(isolate);
13286
13287  // Function template with call handler.
13288  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13289  templ->SetCallHandler(IsConstructHandler);
13290
13291  LocalContext context;
13292
13293  context->Global()->Set(v8_str("f"), templ->GetFunction());
13294  Local<Value> value = v8_compile("f()")->Run();
13295  CHECK(!value->BooleanValue());
13296  value = v8_compile("new f()")->Run();
13297  CHECK(value->BooleanValue());
13298}
13299
13300
13301THREADED_TEST(ObjectProtoToString) {
13302  v8::Isolate* isolate = CcTest::isolate();
13303  v8::HandleScope scope(isolate);
13304  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13305  templ->SetClassName(v8_str("MyClass"));
13306
13307  LocalContext context;
13308
13309  Local<String> customized_tostring = v8_str("customized toString");
13310
13311  // Replace Object.prototype.toString
13312  v8_compile("Object.prototype.toString = function() {"
13313                  "  return 'customized toString';"
13314                  "}")->Run();
13315
13316  // Normal ToString call should call replaced Object.prototype.toString
13317  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13318  Local<String> value = instance->ToString();
13319  CHECK(value->IsString() && value->Equals(customized_tostring));
13320
13321  // ObjectProtoToString should not call replace toString function.
13322  value = instance->ObjectProtoToString();
13323  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13324
13325  // Check global
13326  value = context->Global()->ObjectProtoToString();
13327  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13328
13329  // Check ordinary object
13330  Local<Value> object = v8_compile("new Object()")->Run();
13331  value = object.As<v8::Object>()->ObjectProtoToString();
13332  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13333}
13334
13335
13336THREADED_TEST(ObjectGetConstructorName) {
13337  LocalContext context;
13338  v8::HandleScope scope(context->GetIsolate());
13339  v8_compile("function Parent() {};"
13340             "function Child() {};"
13341             "Child.prototype = new Parent();"
13342             "var outer = { inner: function() { } };"
13343             "var p = new Parent();"
13344             "var c = new Child();"
13345             "var x = new outer.inner();")->Run();
13346
13347  Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13348  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13349      v8_str("Parent")));
13350
13351  Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13352  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13353      v8_str("Child")));
13354
13355  Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13356  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13357      v8_str("outer.inner")));
13358}
13359
13360
13361bool ApiTestFuzzer::fuzzing_ = false;
13362v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13363int ApiTestFuzzer::active_tests_;
13364int ApiTestFuzzer::tests_being_run_;
13365int ApiTestFuzzer::current_;
13366
13367
13368// We are in a callback and want to switch to another thread (if we
13369// are currently running the thread fuzzing test).
13370void ApiTestFuzzer::Fuzz() {
13371  if (!fuzzing_) return;
13372  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13373  test->ContextSwitch();
13374}
13375
13376
13377// Let the next thread go.  Since it is also waiting on the V8 lock it may
13378// not start immediately.
13379bool ApiTestFuzzer::NextThread() {
13380  int test_position = GetNextTestNumber();
13381  const char* test_name = RegisterThreadedTest::nth(current_)->name();
13382  if (test_position == current_) {
13383    if (kLogThreading)
13384      printf("Stay with %s\n", test_name);
13385    return false;
13386  }
13387  if (kLogThreading) {
13388    printf("Switch from %s to %s\n",
13389           test_name,
13390           RegisterThreadedTest::nth(test_position)->name());
13391  }
13392  current_ = test_position;
13393  RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13394  return true;
13395}
13396
13397
13398void ApiTestFuzzer::Run() {
13399  // When it is our turn...
13400  gate_.Wait();
13401  {
13402    // ... get the V8 lock and start running the test.
13403    v8::Locker locker(CcTest::isolate());
13404    CallTest();
13405  }
13406  // This test finished.
13407  active_ = false;
13408  active_tests_--;
13409  // If it was the last then signal that fact.
13410  if (active_tests_ == 0) {
13411    all_tests_done_.Signal();
13412  } else {
13413    // Otherwise select a new test and start that.
13414    NextThread();
13415  }
13416}
13417
13418
13419static unsigned linear_congruential_generator;
13420
13421
13422void ApiTestFuzzer::SetUp(PartOfTest part) {
13423  linear_congruential_generator = i::FLAG_testing_prng_seed;
13424  fuzzing_ = true;
13425  int count = RegisterThreadedTest::count();
13426  int start =  count * part / (LAST_PART + 1);
13427  int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13428  active_tests_ = tests_being_run_ = end - start + 1;
13429  for (int i = 0; i < tests_being_run_; i++) {
13430    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13431  }
13432  for (int i = 0; i < active_tests_; i++) {
13433    RegisterThreadedTest::nth(i)->fuzzer_->Start();
13434  }
13435}
13436
13437
13438static void CallTestNumber(int test_number) {
13439  (RegisterThreadedTest::nth(test_number)->callback())();
13440}
13441
13442
13443void ApiTestFuzzer::RunAllTests() {
13444  // Set off the first test.
13445  current_ = -1;
13446  NextThread();
13447  // Wait till they are all done.
13448  all_tests_done_.Wait();
13449}
13450
13451
13452int ApiTestFuzzer::GetNextTestNumber() {
13453  int next_test;
13454  do {
13455    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13456    linear_congruential_generator *= 1664525u;
13457    linear_congruential_generator += 1013904223u;
13458  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13459  return next_test;
13460}
13461
13462
13463void ApiTestFuzzer::ContextSwitch() {
13464  // If the new thread is the same as the current thread there is nothing to do.
13465  if (NextThread()) {
13466    // Now it can start.
13467    v8::Unlocker unlocker(CcTest::isolate());
13468    // Wait till someone starts us again.
13469    gate_.Wait();
13470    // And we're off.
13471  }
13472}
13473
13474
13475void ApiTestFuzzer::TearDown() {
13476  fuzzing_ = false;
13477  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13478    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13479    if (fuzzer != NULL) fuzzer->Join();
13480  }
13481}
13482
13483
13484// Lets not be needlessly self-referential.
13485TEST(Threading1) {
13486  ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13487  ApiTestFuzzer::RunAllTests();
13488  ApiTestFuzzer::TearDown();
13489}
13490
13491
13492TEST(Threading2) {
13493  ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13494  ApiTestFuzzer::RunAllTests();
13495  ApiTestFuzzer::TearDown();
13496}
13497
13498
13499TEST(Threading3) {
13500  ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13501  ApiTestFuzzer::RunAllTests();
13502  ApiTestFuzzer::TearDown();
13503}
13504
13505
13506TEST(Threading4) {
13507  ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13508  ApiTestFuzzer::RunAllTests();
13509  ApiTestFuzzer::TearDown();
13510}
13511
13512
13513void ApiTestFuzzer::CallTest() {
13514  v8::Isolate::Scope scope(CcTest::isolate());
13515  if (kLogThreading)
13516    printf("Start test %d\n", test_number_);
13517  CallTestNumber(test_number_);
13518  if (kLogThreading)
13519    printf("End test %d\n", test_number_);
13520}
13521
13522
13523static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13524  v8::Isolate* isolate = args.GetIsolate();
13525  CHECK(v8::Locker::IsLocked(isolate));
13526  ApiTestFuzzer::Fuzz();
13527  v8::Unlocker unlocker(isolate);
13528  const char* code = "throw 7;";
13529  {
13530    v8::Locker nested_locker(isolate);
13531    v8::HandleScope scope(isolate);
13532    v8::Handle<Value> exception;
13533    { v8::TryCatch try_catch;
13534      v8::Handle<Value> value = CompileRun(code);
13535      CHECK(value.IsEmpty());
13536      CHECK(try_catch.HasCaught());
13537      // Make sure to wrap the exception in a new handle because
13538      // the handle returned from the TryCatch is destroyed
13539      // when the TryCatch is destroyed.
13540      exception = Local<Value>::New(isolate, try_catch.Exception());
13541    }
13542    args.GetIsolate()->ThrowException(exception);
13543  }
13544}
13545
13546
13547static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13548  CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13549  ApiTestFuzzer::Fuzz();
13550  v8::Unlocker unlocker(CcTest::isolate());
13551  const char* code = "throw 7;";
13552  {
13553    v8::Locker nested_locker(CcTest::isolate());
13554    v8::HandleScope scope(args.GetIsolate());
13555    v8::Handle<Value> value = CompileRun(code);
13556    CHECK(value.IsEmpty());
13557    args.GetReturnValue().Set(v8_str("foo"));
13558  }
13559}
13560
13561
13562// These are locking tests that don't need to be run again
13563// as part of the locking aggregation tests.
13564TEST(NestedLockers) {
13565  v8::Isolate* isolate = CcTest::isolate();
13566  v8::Locker locker(isolate);
13567  CHECK(v8::Locker::IsLocked(isolate));
13568  LocalContext env;
13569  v8::HandleScope scope(env->GetIsolate());
13570  Local<v8::FunctionTemplate> fun_templ =
13571      v8::FunctionTemplate::New(isolate, ThrowInJS);
13572  Local<Function> fun = fun_templ->GetFunction();
13573  env->Global()->Set(v8_str("throw_in_js"), fun);
13574  Local<Script> script = v8_compile("(function () {"
13575                                    "  try {"
13576                                    "    throw_in_js();"
13577                                    "    return 42;"
13578                                    "  } catch (e) {"
13579                                    "    return e * 13;"
13580                                    "  }"
13581                                    "})();");
13582  CHECK_EQ(91, script->Run()->Int32Value());
13583}
13584
13585
13586// These are locking tests that don't need to be run again
13587// as part of the locking aggregation tests.
13588TEST(NestedLockersNoTryCatch) {
13589  v8::Locker locker(CcTest::isolate());
13590  LocalContext env;
13591  v8::HandleScope scope(env->GetIsolate());
13592  Local<v8::FunctionTemplate> fun_templ =
13593      v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13594  Local<Function> fun = fun_templ->GetFunction();
13595  env->Global()->Set(v8_str("throw_in_js"), fun);
13596  Local<Script> script = v8_compile("(function () {"
13597                                    "  try {"
13598                                    "    throw_in_js();"
13599                                    "    return 42;"
13600                                    "  } catch (e) {"
13601                                    "    return e * 13;"
13602                                    "  }"
13603                                    "})();");
13604  CHECK_EQ(91, script->Run()->Int32Value());
13605}
13606
13607
13608THREADED_TEST(RecursiveLocking) {
13609  v8::Locker locker(CcTest::isolate());
13610  {
13611    v8::Locker locker2(CcTest::isolate());
13612    CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13613  }
13614}
13615
13616
13617static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13618  ApiTestFuzzer::Fuzz();
13619  v8::Unlocker unlocker(CcTest::isolate());
13620}
13621
13622
13623THREADED_TEST(LockUnlockLock) {
13624  {
13625    v8::Locker locker(CcTest::isolate());
13626    v8::HandleScope scope(CcTest::isolate());
13627    LocalContext env;
13628    Local<v8::FunctionTemplate> fun_templ =
13629        v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13630    Local<Function> fun = fun_templ->GetFunction();
13631    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13632    Local<Script> script = v8_compile("(function () {"
13633                                      "  unlock_for_a_moment();"
13634                                      "  return 42;"
13635                                      "})();");
13636    CHECK_EQ(42, script->Run()->Int32Value());
13637  }
13638  {
13639    v8::Locker locker(CcTest::isolate());
13640    v8::HandleScope scope(CcTest::isolate());
13641    LocalContext env;
13642    Local<v8::FunctionTemplate> fun_templ =
13643        v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13644    Local<Function> fun = fun_templ->GetFunction();
13645    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13646    Local<Script> script = v8_compile("(function () {"
13647                                      "  unlock_for_a_moment();"
13648                                      "  return 42;"
13649                                      "})();");
13650    CHECK_EQ(42, script->Run()->Int32Value());
13651  }
13652}
13653
13654
13655static int GetGlobalObjectsCount() {
13656  int count = 0;
13657  i::HeapIterator it(CcTest::heap());
13658  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13659    if (object->IsJSGlobalObject()) count++;
13660  return count;
13661}
13662
13663
13664static void CheckSurvivingGlobalObjectsCount(int expected) {
13665  // We need to collect all garbage twice to be sure that everything
13666  // has been collected.  This is because inline caches are cleared in
13667  // the first garbage collection but some of the maps have already
13668  // been marked at that point.  Therefore some of the maps are not
13669  // collected until the second garbage collection.
13670  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13671  CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13672  int count = GetGlobalObjectsCount();
13673#ifdef DEBUG
13674  if (count != expected) CcTest::heap()->TracePathToGlobal();
13675#endif
13676  CHECK_EQ(expected, count);
13677}
13678
13679
13680TEST(DontLeakGlobalObjects) {
13681  // Regression test for issues 1139850 and 1174891.
13682
13683  i::FLAG_expose_gc = true;
13684  v8::V8::Initialize();
13685
13686  for (int i = 0; i < 5; i++) {
13687    { v8::HandleScope scope(CcTest::isolate());
13688      LocalContext context;
13689    }
13690    CcTest::isolate()->ContextDisposedNotification();
13691    CheckSurvivingGlobalObjectsCount(0);
13692
13693    { v8::HandleScope scope(CcTest::isolate());
13694      LocalContext context;
13695      v8_compile("Date")->Run();
13696    }
13697    CcTest::isolate()->ContextDisposedNotification();
13698    CheckSurvivingGlobalObjectsCount(0);
13699
13700    { v8::HandleScope scope(CcTest::isolate());
13701      LocalContext context;
13702      v8_compile("/aaa/")->Run();
13703    }
13704    CcTest::isolate()->ContextDisposedNotification();
13705    CheckSurvivingGlobalObjectsCount(0);
13706
13707    { v8::HandleScope scope(CcTest::isolate());
13708      const char* extension_list[] = { "v8/gc" };
13709      v8::ExtensionConfiguration extensions(1, extension_list);
13710      LocalContext context(&extensions);
13711      v8_compile("gc();")->Run();
13712    }
13713    CcTest::isolate()->ContextDisposedNotification();
13714    CheckSurvivingGlobalObjectsCount(0);
13715  }
13716}
13717
13718
13719TEST(CopyablePersistent) {
13720  LocalContext context;
13721  v8::Isolate* isolate = context->GetIsolate();
13722  i::GlobalHandles* globals =
13723      reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13724  int initial_handles = globals->global_handles_count();
13725  typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13726      CopyableObject;
13727  {
13728    CopyableObject handle1;
13729    {
13730      v8::HandleScope scope(isolate);
13731      handle1.Reset(isolate, v8::Object::New(isolate));
13732    }
13733    CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13734    CopyableObject  handle2;
13735    handle2 = handle1;
13736    CHECK(handle1 == handle2);
13737    CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13738    CopyableObject handle3(handle2);
13739    CHECK(handle1 == handle3);
13740    CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13741  }
13742  // Verify autodispose
13743  CHECK_EQ(initial_handles, globals->global_handles_count());
13744}
13745
13746
13747static void WeakApiCallback(
13748    const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13749  Local<Value> value = data.GetValue()->Get(v8_str("key"));
13750  CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13751  data.GetParameter()->Reset();
13752  delete data.GetParameter();
13753}
13754
13755
13756TEST(WeakCallbackApi) {
13757  LocalContext context;
13758  v8::Isolate* isolate = context->GetIsolate();
13759  i::GlobalHandles* globals =
13760      reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13761  int initial_handles = globals->global_handles_count();
13762  {
13763    v8::HandleScope scope(isolate);
13764    v8::Local<v8::Object> obj = v8::Object::New(isolate);
13765    obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13766    v8::Persistent<v8::Object>* handle =
13767        new v8::Persistent<v8::Object>(isolate, obj);
13768    handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13769                                                             WeakApiCallback);
13770  }
13771  reinterpret_cast<i::Isolate*>(isolate)->heap()->
13772      CollectAllGarbage(i::Heap::kNoGCFlags);
13773  // Verify disposed.
13774  CHECK_EQ(initial_handles, globals->global_handles_count());
13775}
13776
13777
13778v8::Persistent<v8::Object> some_object;
13779v8::Persistent<v8::Object> bad_handle;
13780
13781void NewPersistentHandleCallback(
13782    const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13783  v8::HandleScope scope(data.GetIsolate());
13784  bad_handle.Reset(data.GetIsolate(), some_object);
13785  data.GetParameter()->Reset();
13786}
13787
13788
13789THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13790  LocalContext context;
13791  v8::Isolate* isolate = context->GetIsolate();
13792
13793  v8::Persistent<v8::Object> handle1, handle2;
13794  {
13795    v8::HandleScope scope(isolate);
13796    some_object.Reset(isolate, v8::Object::New(isolate));
13797    handle1.Reset(isolate, v8::Object::New(isolate));
13798    handle2.Reset(isolate, v8::Object::New(isolate));
13799  }
13800  // Note: order is implementation dependent alas: currently
13801  // global handle nodes are processed by PostGarbageCollectionProcessing
13802  // in reverse allocation order, so if second allocated handle is deleted,
13803  // weak callback of the first handle would be able to 'reallocate' it.
13804  handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13805  handle2.Reset();
13806  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13807}
13808
13809
13810v8::Persistent<v8::Object> to_be_disposed;
13811
13812void DisposeAndForceGcCallback(
13813    const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13814  to_be_disposed.Reset();
13815  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13816  data.GetParameter()->Reset();
13817}
13818
13819
13820THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13821  LocalContext context;
13822  v8::Isolate* isolate = context->GetIsolate();
13823
13824  v8::Persistent<v8::Object> handle1, handle2;
13825  {
13826    v8::HandleScope scope(isolate);
13827    handle1.Reset(isolate, v8::Object::New(isolate));
13828    handle2.Reset(isolate, v8::Object::New(isolate));
13829  }
13830  handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13831  to_be_disposed.Reset(isolate, handle2);
13832  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13833}
13834
13835void DisposingCallback(
13836    const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13837  data.GetParameter()->Reset();
13838}
13839
13840void HandleCreatingCallback(
13841    const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13842  v8::HandleScope scope(data.GetIsolate());
13843  v8::Persistent<v8::Object>(data.GetIsolate(),
13844                             v8::Object::New(data.GetIsolate()));
13845  data.GetParameter()->Reset();
13846}
13847
13848
13849THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13850  LocalContext context;
13851  v8::Isolate* isolate = context->GetIsolate();
13852
13853  v8::Persistent<v8::Object> handle1, handle2, handle3;
13854  {
13855    v8::HandleScope scope(isolate);
13856    handle3.Reset(isolate, v8::Object::New(isolate));
13857    handle2.Reset(isolate, v8::Object::New(isolate));
13858    handle1.Reset(isolate, v8::Object::New(isolate));
13859  }
13860  handle2.SetWeak(&handle2, DisposingCallback);
13861  handle3.SetWeak(&handle3, HandleCreatingCallback);
13862  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13863}
13864
13865
13866THREADED_TEST(CheckForCrossContextObjectLiterals) {
13867  v8::V8::Initialize();
13868
13869  const int nof = 2;
13870  const char* sources[nof] = {
13871    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13872    "Object()"
13873  };
13874
13875  for (int i = 0; i < nof; i++) {
13876    const char* source = sources[i];
13877    { v8::HandleScope scope(CcTest::isolate());
13878      LocalContext context;
13879      CompileRun(source);
13880    }
13881    { v8::HandleScope scope(CcTest::isolate());
13882      LocalContext context;
13883      CompileRun(source);
13884    }
13885  }
13886}
13887
13888
13889static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13890  v8::EscapableHandleScope inner(env->GetIsolate());
13891  env->Enter();
13892  v8::Local<Value> three = v8_num(3);
13893  v8::Local<Value> value = inner.Escape(three);
13894  env->Exit();
13895  return value;
13896}
13897
13898
13899THREADED_TEST(NestedHandleScopeAndContexts) {
13900  v8::Isolate* isolate = CcTest::isolate();
13901  v8::HandleScope outer(isolate);
13902  v8::Local<Context> env = Context::New(isolate);
13903  env->Enter();
13904  v8::Handle<Value> value = NestedScope(env);
13905  v8::Handle<String> str(value->ToString());
13906  CHECK(!str.IsEmpty());
13907  env->Exit();
13908}
13909
13910
13911static bool MatchPointers(void* key1, void* key2) {
13912  return key1 == key2;
13913}
13914
13915
13916struct SymbolInfo {
13917  size_t id;
13918  size_t size;
13919  std::string name;
13920};
13921
13922
13923class SetFunctionEntryHookTest {
13924 public:
13925  SetFunctionEntryHookTest() {
13926    CHECK(instance_ == NULL);
13927    instance_ = this;
13928  }
13929  ~SetFunctionEntryHookTest() {
13930    CHECK(instance_ == this);
13931    instance_ = NULL;
13932  }
13933  void Reset() {
13934    symbols_.clear();
13935    symbol_locations_.clear();
13936    invocations_.clear();
13937  }
13938  void RunTest();
13939  void OnJitEvent(const v8::JitCodeEvent* event);
13940  static void JitEvent(const v8::JitCodeEvent* event) {
13941    CHECK(instance_ != NULL);
13942    instance_->OnJitEvent(event);
13943  }
13944
13945  void OnEntryHook(uintptr_t function,
13946                   uintptr_t return_addr_location);
13947  static void EntryHook(uintptr_t function,
13948                        uintptr_t return_addr_location) {
13949    CHECK(instance_ != NULL);
13950    instance_->OnEntryHook(function, return_addr_location);
13951  }
13952
13953  static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13954    CHECK(instance_ != NULL);
13955    args.GetReturnValue().Set(v8_num(42));
13956  }
13957  void RunLoopInNewEnv(v8::Isolate* isolate);
13958
13959  // Records addr as location of symbol.
13960  void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13961
13962  // Finds the symbol containing addr
13963  SymbolInfo* FindSymbolForAddr(i::Address addr);
13964  // Returns the number of invocations where the caller name contains
13965  // \p caller_name and the function name contains \p function_name.
13966  int CountInvocations(const char* caller_name,
13967                       const char* function_name);
13968
13969  i::Handle<i::JSFunction> foo_func_;
13970  i::Handle<i::JSFunction> bar_func_;
13971
13972  typedef std::map<size_t, SymbolInfo> SymbolMap;
13973  typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13974  typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13975  SymbolMap symbols_;
13976  SymbolLocationMap symbol_locations_;
13977  InvocationMap invocations_;
13978
13979  static SetFunctionEntryHookTest* instance_;
13980};
13981SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13982
13983
13984// Returns true if addr is in the range [start, start+len).
13985static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13986  if (start <= addr && start + len > addr)
13987    return true;
13988
13989  return false;
13990}
13991
13992void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13993                                              SymbolInfo* symbol) {
13994  // Insert the symbol at the new location.
13995  SymbolLocationMap::iterator it =
13996      symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13997  // Now erase symbols to the left and right that overlap this one.
13998  while (it != symbol_locations_.begin()) {
13999    SymbolLocationMap::iterator left = it;
14000    --left;
14001    if (!Overlaps(left->first, left->second->size, addr))
14002      break;
14003    symbol_locations_.erase(left);
14004  }
14005
14006  // Now erase symbols to the left and right that overlap this one.
14007  while (true) {
14008    SymbolLocationMap::iterator right = it;
14009    ++right;
14010    if (right == symbol_locations_.end())
14011        break;
14012    if (!Overlaps(addr, symbol->size, right->first))
14013      break;
14014    symbol_locations_.erase(right);
14015  }
14016}
14017
14018
14019void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
14020  switch (event->type) {
14021    case v8::JitCodeEvent::CODE_ADDED: {
14022        CHECK(event->code_start != NULL);
14023        CHECK_NE(0, static_cast<int>(event->code_len));
14024        CHECK(event->name.str != NULL);
14025        size_t symbol_id = symbols_.size();
14026
14027        // Record the new symbol.
14028        SymbolInfo& info = symbols_[symbol_id];
14029        info.id = symbol_id;
14030        info.size = event->code_len;
14031        info.name.assign(event->name.str, event->name.str + event->name.len);
14032
14033        // And record it's location.
14034        InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
14035      }
14036      break;
14037
14038    case v8::JitCodeEvent::CODE_MOVED: {
14039        // We would like to never see code move that we haven't seen before,
14040        // but the code creation event does not happen until the line endings
14041        // have been calculated (this is so that we can report the line in the
14042        // script at which the function source is found, see
14043        // Compiler::RecordFunctionCompilation) and the line endings
14044        // calculations can cause a GC, which can move the newly created code
14045        // before its existence can be logged.
14046        SymbolLocationMap::iterator it(
14047            symbol_locations_.find(
14048                reinterpret_cast<i::Address>(event->code_start)));
14049        if (it != symbol_locations_.end()) {
14050          // Found a symbol at this location, move it.
14051          SymbolInfo* info = it->second;
14052          symbol_locations_.erase(it);
14053          InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
14054                         info);
14055        }
14056      }
14057    default:
14058      break;
14059  }
14060}
14061
14062void SetFunctionEntryHookTest::OnEntryHook(
14063    uintptr_t function, uintptr_t return_addr_location) {
14064  // Get the function's code object.
14065  i::Code* function_code = i::Code::GetCodeFromTargetAddress(
14066      reinterpret_cast<i::Address>(function));
14067  CHECK(function_code != NULL);
14068
14069  // Then try and look up the caller's code object.
14070  i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
14071
14072  // Count the invocation.
14073  SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
14074  SymbolInfo* function_symbol =
14075      FindSymbolForAddr(reinterpret_cast<i::Address>(function));
14076  ++invocations_[std::make_pair(caller_symbol, function_symbol)];
14077
14078  if (!bar_func_.is_null() && function_code == bar_func_->code()) {
14079    // Check that we have a symbol for the "bar" function at the right location.
14080    SymbolLocationMap::iterator it(
14081        symbol_locations_.find(function_code->instruction_start()));
14082    CHECK(it != symbol_locations_.end());
14083  }
14084
14085  if (!foo_func_.is_null() && function_code == foo_func_->code()) {
14086    // Check that we have a symbol for "foo" at the right location.
14087    SymbolLocationMap::iterator it(
14088        symbol_locations_.find(function_code->instruction_start()));
14089    CHECK(it != symbol_locations_.end());
14090  }
14091}
14092
14093
14094SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
14095  SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
14096  // Do we have a direct hit on a symbol?
14097  if (it != symbol_locations_.end()) {
14098    if (it->first == addr)
14099      return it->second;
14100  }
14101
14102  // If not a direct hit, it'll have to be the previous symbol.
14103  if (it == symbol_locations_.begin())
14104    return NULL;
14105
14106  --it;
14107  size_t offs = addr - it->first;
14108  if (offs < it->second->size)
14109    return it->second;
14110
14111  return NULL;
14112}
14113
14114
14115int SetFunctionEntryHookTest::CountInvocations(
14116    const char* caller_name, const char* function_name) {
14117  InvocationMap::iterator it(invocations_.begin());
14118  int invocations = 0;
14119  for (; it != invocations_.end(); ++it) {
14120    SymbolInfo* caller = it->first.first;
14121    SymbolInfo* function = it->first.second;
14122
14123    // Filter out non-matching functions.
14124    if (function_name != NULL) {
14125      if (function->name.find(function_name) == std::string::npos)
14126        continue;
14127    }
14128
14129    // Filter out non-matching callers.
14130    if (caller_name != NULL) {
14131      if (caller == NULL)
14132        continue;
14133      if (caller->name.find(caller_name) == std::string::npos)
14134        continue;
14135    }
14136
14137    // It matches add the invocation count to the tally.
14138    invocations += it->second;
14139  }
14140
14141  return invocations;
14142}
14143
14144
14145void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14146  v8::HandleScope outer(isolate);
14147  v8::Local<Context> env = Context::New(isolate);
14148  env->Enter();
14149
14150  Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14151  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14152  env->Global()->Set(v8_str("obj"), t->NewInstance());
14153
14154  const char* script =
14155      "function bar() {\n"
14156      "  var sum = 0;\n"
14157      "  for (i = 0; i < 100; ++i)\n"
14158      "    sum = foo(i);\n"
14159      "  return sum;\n"
14160      "}\n"
14161      "function foo(i) { return i * i; }\n"
14162      "// Invoke on the runtime function.\n"
14163      "obj.asdf()";
14164  CompileRun(script);
14165  bar_func_ = i::Handle<i::JSFunction>::cast(
14166          v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14167  DCHECK(!bar_func_.is_null());
14168
14169  foo_func_ =
14170      i::Handle<i::JSFunction>::cast(
14171           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14172  DCHECK(!foo_func_.is_null());
14173
14174  v8::Handle<v8::Value> value = CompileRun("bar();");
14175  CHECK(value->IsNumber());
14176  CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14177
14178  // Test the optimized codegen path.
14179  value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14180                     "bar();");
14181  CHECK(value->IsNumber());
14182  CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14183
14184  env->Exit();
14185}
14186
14187
14188void SetFunctionEntryHookTest::RunTest() {
14189  // Work in a new isolate throughout.
14190  v8::Isolate::CreateParams create_params;
14191  create_params.entry_hook = EntryHook;
14192  create_params.code_event_handler = JitEvent;
14193  v8::Isolate* isolate = v8::Isolate::New(create_params);
14194
14195  {
14196    v8::Isolate::Scope scope(isolate);
14197
14198    RunLoopInNewEnv(isolate);
14199
14200    // Check the exepected invocation counts.
14201    CHECK_EQ(2, CountInvocations(NULL, "bar"));
14202    CHECK_EQ(200, CountInvocations("bar", "foo"));
14203    CHECK_EQ(200, CountInvocations(NULL, "foo"));
14204
14205    // Verify that we have an entry hook on some specific stubs.
14206    CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14207    CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14208    CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14209  }
14210  isolate->Dispose();
14211
14212  Reset();
14213
14214  // Make sure a second isolate is unaffected by the previous entry hook.
14215  isolate = v8::Isolate::New();
14216  {
14217    v8::Isolate::Scope scope(isolate);
14218
14219    // Reset the entry count to zero and set the entry hook.
14220    RunLoopInNewEnv(isolate);
14221
14222    // We should record no invocations in this isolate.
14223    CHECK_EQ(0, static_cast<int>(invocations_.size()));
14224  }
14225
14226  isolate->Dispose();
14227}
14228
14229
14230TEST(SetFunctionEntryHook) {
14231  // FunctionEntryHook does not work well with experimental natives.
14232  // Experimental natives are compiled during snapshot deserialization.
14233  // This test breaks because InstallGetter (function from snapshot that
14234  // only gets called from experimental natives) is compiled with entry hooks.
14235  i::FLAG_allow_natives_syntax = true;
14236  i::FLAG_use_inlining = false;
14237
14238  SetFunctionEntryHookTest test;
14239  test.RunTest();
14240}
14241
14242
14243static i::HashMap* code_map = NULL;
14244static i::HashMap* jitcode_line_info = NULL;
14245static int saw_bar = 0;
14246static int move_events = 0;
14247
14248
14249static bool FunctionNameIs(const char* expected,
14250                           const v8::JitCodeEvent* event) {
14251  // Log lines for functions are of the general form:
14252  // "LazyCompile:<type><function_name>", where the type is one of
14253  // "*", "~" or "".
14254  static const char kPreamble[] = "LazyCompile:";
14255  static size_t kPreambleLen = sizeof(kPreamble) - 1;
14256
14257  if (event->name.len < sizeof(kPreamble) - 1 ||
14258      strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14259    return false;
14260  }
14261
14262  const char* tail = event->name.str + kPreambleLen;
14263  size_t tail_len = event->name.len - kPreambleLen;
14264  size_t expected_len = strlen(expected);
14265  if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14266    --tail_len;
14267    ++tail;
14268  }
14269
14270  // Check for tails like 'bar :1'.
14271  if (tail_len > expected_len + 2 &&
14272      tail[expected_len] == ' ' &&
14273      tail[expected_len + 1] == ':' &&
14274      tail[expected_len + 2] &&
14275      !strncmp(tail, expected, expected_len)) {
14276    return true;
14277  }
14278
14279  if (tail_len != expected_len)
14280    return false;
14281
14282  return strncmp(tail, expected, expected_len) == 0;
14283}
14284
14285
14286static void event_handler(const v8::JitCodeEvent* event) {
14287  CHECK(event != NULL);
14288  CHECK(code_map != NULL);
14289  CHECK(jitcode_line_info != NULL);
14290
14291  class DummyJitCodeLineInfo {
14292  };
14293
14294  switch (event->type) {
14295    case v8::JitCodeEvent::CODE_ADDED: {
14296        CHECK(event->code_start != NULL);
14297        CHECK_NE(0, static_cast<int>(event->code_len));
14298        CHECK(event->name.str != NULL);
14299        i::HashMap::Entry* entry =
14300            code_map->Lookup(event->code_start,
14301                             i::ComputePointerHash(event->code_start),
14302                             true);
14303        entry->value = reinterpret_cast<void*>(event->code_len);
14304
14305        if (FunctionNameIs("bar", event)) {
14306          ++saw_bar;
14307        }
14308      }
14309      break;
14310
14311    case v8::JitCodeEvent::CODE_MOVED: {
14312        uint32_t hash = i::ComputePointerHash(event->code_start);
14313        // We would like to never see code move that we haven't seen before,
14314        // but the code creation event does not happen until the line endings
14315        // have been calculated (this is so that we can report the line in the
14316        // script at which the function source is found, see
14317        // Compiler::RecordFunctionCompilation) and the line endings
14318        // calculations can cause a GC, which can move the newly created code
14319        // before its existence can be logged.
14320        i::HashMap::Entry* entry =
14321            code_map->Lookup(event->code_start, hash, false);
14322        if (entry != NULL) {
14323          ++move_events;
14324
14325          CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14326          code_map->Remove(event->code_start, hash);
14327
14328          entry = code_map->Lookup(event->new_code_start,
14329                                   i::ComputePointerHash(event->new_code_start),
14330                                   true);
14331          CHECK(entry != NULL);
14332          entry->value = reinterpret_cast<void*>(event->code_len);
14333        }
14334      }
14335      break;
14336
14337    case v8::JitCodeEvent::CODE_REMOVED:
14338      // Object/code removal events are currently not dispatched from the GC.
14339      CHECK(false);
14340      break;
14341
14342    // For CODE_START_LINE_INFO_RECORDING event, we will create one
14343    // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14344    // record it in jitcode_line_info.
14345    case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14346        DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14347        v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14348        temp_event->user_data = line_info;
14349        i::HashMap::Entry* entry =
14350            jitcode_line_info->Lookup(line_info,
14351                                      i::ComputePointerHash(line_info),
14352                                      true);
14353        entry->value = reinterpret_cast<void*>(line_info);
14354      }
14355      break;
14356    // For these two events, we will check whether the event->user_data
14357    // data structure is created before during CODE_START_LINE_INFO_RECORDING
14358    // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14359    case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14360        CHECK(event->user_data != NULL);
14361        uint32_t hash = i::ComputePointerHash(event->user_data);
14362        i::HashMap::Entry* entry =
14363            jitcode_line_info->Lookup(event->user_data, hash, false);
14364        CHECK(entry != NULL);
14365        delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14366      }
14367      break;
14368
14369    case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14370        CHECK(event->user_data != NULL);
14371        uint32_t hash = i::ComputePointerHash(event->user_data);
14372        i::HashMap::Entry* entry =
14373            jitcode_line_info->Lookup(event->user_data, hash, false);
14374        CHECK(entry != NULL);
14375      }
14376      break;
14377
14378    default:
14379      // Impossible event.
14380      CHECK(false);
14381      break;
14382  }
14383}
14384
14385
14386UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14387  i::FLAG_stress_compaction = true;
14388  i::FLAG_incremental_marking = false;
14389  if (i::FLAG_never_compact) return;
14390  const char* script =
14391    "function bar() {"
14392    "  var sum = 0;"
14393    "  for (i = 0; i < 100; ++i)"
14394    "    sum = foo(i);"
14395    "  return sum;"
14396    "}"
14397    "function foo(i) { return i * i; };"
14398    "bar();";
14399
14400  // Run this test in a new isolate to make sure we don't
14401  // have remnants of state from other code.
14402  v8::Isolate* isolate = v8::Isolate::New();
14403  isolate->Enter();
14404  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14405  i::Heap* heap = i_isolate->heap();
14406
14407  {
14408    v8::HandleScope scope(isolate);
14409    i::HashMap code(MatchPointers);
14410    code_map = &code;
14411
14412    i::HashMap lineinfo(MatchPointers);
14413    jitcode_line_info = &lineinfo;
14414
14415    saw_bar = 0;
14416    move_events = 0;
14417
14418    isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14419
14420    // Generate new code objects sparsely distributed across several
14421    // different fragmented code-space pages.
14422    const int kIterations = 10;
14423    for (int i = 0; i < kIterations; ++i) {
14424      LocalContext env(isolate);
14425      i::AlwaysAllocateScope always_allocate(i_isolate);
14426      SimulateFullSpace(heap->code_space());
14427      CompileRun(script);
14428
14429      // Keep a strong reference to the code object in the handle scope.
14430      i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14431          v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14432      i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14433          v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14434
14435      // Clear the compilation cache to get more wastage.
14436      reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14437    }
14438
14439    // Force code movement.
14440    heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14441
14442    isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14443
14444    CHECK_LE(kIterations, saw_bar);
14445    CHECK_LT(0, move_events);
14446
14447    code_map = NULL;
14448    jitcode_line_info = NULL;
14449  }
14450
14451  isolate->Exit();
14452  isolate->Dispose();
14453
14454  // Do this in a new isolate.
14455  isolate = v8::Isolate::New();
14456  isolate->Enter();
14457
14458  // Verify that we get callbacks for existing code objects when we
14459  // request enumeration of existing code.
14460  {
14461    v8::HandleScope scope(isolate);
14462    LocalContext env(isolate);
14463    CompileRun(script);
14464
14465    // Now get code through initial iteration.
14466    i::HashMap code(MatchPointers);
14467    code_map = &code;
14468
14469    i::HashMap lineinfo(MatchPointers);
14470    jitcode_line_info = &lineinfo;
14471
14472    isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14473                                    event_handler);
14474    isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14475
14476    jitcode_line_info = NULL;
14477    // We expect that we got some events. Note that if we could get code removal
14478    // notifications, we could compare two collections, one created by listening
14479    // from the time of creation of an isolate, and the other by subscribing
14480    // with EnumExisting.
14481    CHECK_LT(0, code.occupancy());
14482
14483    code_map = NULL;
14484  }
14485
14486  isolate->Exit();
14487  isolate->Dispose();
14488}
14489
14490
14491THREADED_TEST(ExternalAllocatedMemory) {
14492  v8::Isolate* isolate = CcTest::isolate();
14493  v8::HandleScope outer(isolate);
14494  v8::Local<Context> env(Context::New(isolate));
14495  CHECK(!env.IsEmpty());
14496  const int64_t kSize = 1024*1024;
14497  int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14498  CHECK_EQ(baseline + kSize,
14499           isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14500  CHECK_EQ(baseline,
14501           isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14502}
14503
14504
14505// Regression test for issue 54, object templates with internal fields
14506// but no accessors or interceptors did not get their internal field
14507// count set on instances.
14508THREADED_TEST(Regress54) {
14509  LocalContext context;
14510  v8::Isolate* isolate = context->GetIsolate();
14511  v8::HandleScope outer(isolate);
14512  static v8::Persistent<v8::ObjectTemplate> templ;
14513  if (templ.IsEmpty()) {
14514    v8::EscapableHandleScope inner(isolate);
14515    v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14516    local->SetInternalFieldCount(1);
14517    templ.Reset(isolate, inner.Escape(local));
14518  }
14519  v8::Handle<v8::Object> result =
14520      v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14521  CHECK_EQ(1, result->InternalFieldCount());
14522}
14523
14524
14525// If part of the threaded tests, this test makes ThreadingTest fail
14526// on mac.
14527TEST(CatchStackOverflow) {
14528  LocalContext context;
14529  v8::HandleScope scope(context->GetIsolate());
14530  v8::TryCatch try_catch;
14531  v8::Handle<v8::Value> result = CompileRun(
14532    "function f() {"
14533    "  return f();"
14534    "}"
14535    ""
14536    "f();");
14537  CHECK(result.IsEmpty());
14538}
14539
14540
14541static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14542                                    const char* resource_name,
14543                                    int line_offset) {
14544  v8::HandleScope scope(CcTest::isolate());
14545  v8::TryCatch try_catch;
14546  v8::Handle<v8::Value> result = script->Run();
14547  CHECK(result.IsEmpty());
14548  CHECK(try_catch.HasCaught());
14549  v8::Handle<v8::Message> message = try_catch.Message();
14550  CHECK(!message.IsEmpty());
14551  CHECK_EQ(10 + line_offset, message->GetLineNumber());
14552  CHECK_EQ(91, message->GetStartPosition());
14553  CHECK_EQ(92, message->GetEndPosition());
14554  CHECK_EQ(2, message->GetStartColumn());
14555  CHECK_EQ(3, message->GetEndColumn());
14556  v8::String::Utf8Value line(message->GetSourceLine());
14557  CHECK_EQ("  throw 'nirk';", *line);
14558  v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
14559  CHECK_EQ(resource_name, *name);
14560}
14561
14562
14563THREADED_TEST(TryCatchSourceInfo) {
14564  LocalContext context;
14565  v8::HandleScope scope(context->GetIsolate());
14566  v8::Local<v8::String> source = v8_str(
14567      "function Foo() {\n"
14568      "  return Bar();\n"
14569      "}\n"
14570      "\n"
14571      "function Bar() {\n"
14572      "  return Baz();\n"
14573      "}\n"
14574      "\n"
14575      "function Baz() {\n"
14576      "  throw 'nirk';\n"
14577      "}\n"
14578      "\n"
14579      "Foo();\n");
14580
14581  const char* resource_name;
14582  v8::Handle<v8::Script> script;
14583  resource_name = "test.js";
14584  script = CompileWithOrigin(source, resource_name);
14585  CheckTryCatchSourceInfo(script, resource_name, 0);
14586
14587  resource_name = "test1.js";
14588  v8::ScriptOrigin origin1(
14589      v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14590  script = v8::Script::Compile(source, &origin1);
14591  CheckTryCatchSourceInfo(script, resource_name, 0);
14592
14593  resource_name = "test2.js";
14594  v8::ScriptOrigin origin2(
14595      v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14596      v8::Integer::New(context->GetIsolate(), 7));
14597  script = v8::Script::Compile(source, &origin2);
14598  CheckTryCatchSourceInfo(script, resource_name, 7);
14599}
14600
14601
14602THREADED_TEST(CompilationCache) {
14603  LocalContext context;
14604  v8::HandleScope scope(context->GetIsolate());
14605  v8::Handle<v8::String> source0 =
14606      v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14607  v8::Handle<v8::String> source1 =
14608      v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14609  v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14610  v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14611  v8::Handle<v8::Script> script2 =
14612      v8::Script::Compile(source0);  // different origin
14613  CHECK_EQ(1234, script0->Run()->Int32Value());
14614  CHECK_EQ(1234, script1->Run()->Int32Value());
14615  CHECK_EQ(1234, script2->Run()->Int32Value());
14616}
14617
14618
14619static void FunctionNameCallback(
14620    const v8::FunctionCallbackInfo<v8::Value>& args) {
14621  ApiTestFuzzer::Fuzz();
14622  args.GetReturnValue().Set(v8_num(42));
14623}
14624
14625
14626THREADED_TEST(CallbackFunctionName) {
14627  LocalContext context;
14628  v8::Isolate* isolate = context->GetIsolate();
14629  v8::HandleScope scope(isolate);
14630  Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14631  t->Set(v8_str("asdf"),
14632         v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14633  context->Global()->Set(v8_str("obj"), t->NewInstance());
14634  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14635  CHECK(value->IsString());
14636  v8::String::Utf8Value name(value);
14637  CHECK_EQ("asdf", *name);
14638}
14639
14640
14641THREADED_TEST(DateAccess) {
14642  LocalContext context;
14643  v8::HandleScope scope(context->GetIsolate());
14644  v8::Handle<v8::Value> date =
14645      v8::Date::New(context->GetIsolate(), 1224744689038.0);
14646  CHECK(date->IsDate());
14647  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14648}
14649
14650
14651void CheckProperties(v8::Isolate* isolate,
14652                     v8::Handle<v8::Value> val,
14653                     int elmc,
14654                     const char* elmv[]) {
14655  v8::Handle<v8::Object> obj = val.As<v8::Object>();
14656  v8::Handle<v8::Array> props = obj->GetPropertyNames();
14657  CHECK_EQ(elmc, props->Length());
14658  for (int i = 0; i < elmc; i++) {
14659    v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14660    CHECK_EQ(elmv[i], *elm);
14661  }
14662}
14663
14664
14665void CheckOwnProperties(v8::Isolate* isolate,
14666                        v8::Handle<v8::Value> val,
14667                        int elmc,
14668                        const char* elmv[]) {
14669  v8::Handle<v8::Object> obj = val.As<v8::Object>();
14670  v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14671  CHECK_EQ(elmc, props->Length());
14672  for (int i = 0; i < elmc; i++) {
14673    v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14674    CHECK_EQ(elmv[i], *elm);
14675  }
14676}
14677
14678
14679THREADED_TEST(PropertyEnumeration) {
14680  LocalContext context;
14681  v8::Isolate* isolate = context->GetIsolate();
14682  v8::HandleScope scope(isolate);
14683  v8::Handle<v8::Value> obj = CompileRun(
14684      "var result = [];"
14685      "result[0] = {};"
14686      "result[1] = {a: 1, b: 2};"
14687      "result[2] = [1, 2, 3];"
14688      "var proto = {x: 1, y: 2, z: 3};"
14689      "var x = { __proto__: proto, w: 0, z: 1 };"
14690      "result[3] = x;"
14691      "result;");
14692  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14693  CHECK_EQ(4, elms->Length());
14694  int elmc0 = 0;
14695  const char** elmv0 = NULL;
14696  CheckProperties(
14697      isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14698  CheckOwnProperties(
14699      isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14700  int elmc1 = 2;
14701  const char* elmv1[] = {"a", "b"};
14702  CheckProperties(
14703      isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14704  CheckOwnProperties(
14705      isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14706  int elmc2 = 3;
14707  const char* elmv2[] = {"0", "1", "2"};
14708  CheckProperties(
14709      isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14710  CheckOwnProperties(
14711      isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14712  int elmc3 = 4;
14713  const char* elmv3[] = {"w", "z", "x", "y"};
14714  CheckProperties(
14715      isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14716  int elmc4 = 2;
14717  const char* elmv4[] = {"w", "z"};
14718  CheckOwnProperties(
14719      isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14720}
14721
14722
14723THREADED_TEST(PropertyEnumeration2) {
14724  LocalContext context;
14725  v8::Isolate* isolate = context->GetIsolate();
14726  v8::HandleScope scope(isolate);
14727  v8::Handle<v8::Value> obj = CompileRun(
14728      "var result = [];"
14729      "result[0] = {};"
14730      "result[1] = {a: 1, b: 2};"
14731      "result[2] = [1, 2, 3];"
14732      "var proto = {x: 1, y: 2, z: 3};"
14733      "var x = { __proto__: proto, w: 0, z: 1 };"
14734      "result[3] = x;"
14735      "result;");
14736  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14737  CHECK_EQ(4, elms->Length());
14738  int elmc0 = 0;
14739  const char** elmv0 = NULL;
14740  CheckProperties(isolate,
14741                  elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14742
14743  v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14744  v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14745  CHECK_EQ(0, props->Length());
14746  for (uint32_t i = 0; i < props->Length(); i++) {
14747    printf("p[%d]\n", i);
14748  }
14749}
14750
14751static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14752                                  Local<Value> name,
14753                                  v8::AccessType type,
14754                                  Local<Value> data) {
14755  return type != v8::ACCESS_SET;
14756}
14757
14758
14759static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14760                                    uint32_t key,
14761                                    v8::AccessType type,
14762                                    Local<Value> data) {
14763  return type != v8::ACCESS_SET;
14764}
14765
14766
14767THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14768  LocalContext context;
14769  v8::Isolate* isolate = context->GetIsolate();
14770  v8::HandleScope scope(isolate);
14771  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14772  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14773                                 IndexedSetAccessBlocker);
14774  templ->Set(v8_str("x"), v8::True(isolate));
14775  Local<v8::Object> instance = templ->NewInstance();
14776  context->Global()->Set(v8_str("obj"), instance);
14777  Local<Value> value = CompileRun("obj.x");
14778  CHECK(value->BooleanValue());
14779}
14780
14781
14782static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14783                                  Local<Value> name,
14784                                  v8::AccessType type,
14785                                  Local<Value> data) {
14786  return false;
14787}
14788
14789
14790static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14791                                    uint32_t key,
14792                                    v8::AccessType type,
14793                                    Local<Value> data) {
14794  return false;
14795}
14796
14797
14798
14799THREADED_TEST(AccessChecksReenabledCorrectly) {
14800  LocalContext context;
14801  v8::Isolate* isolate = context->GetIsolate();
14802  v8::HandleScope scope(isolate);
14803  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14804  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14805                                 IndexedGetAccessBlocker);
14806  templ->Set(v8_str("a"), v8_str("a"));
14807  // Add more than 8 (see kMaxFastProperties) properties
14808  // so that the constructor will force copying map.
14809  // Cannot sprintf, gcc complains unsafety.
14810  char buf[4];
14811  for (char i = '0'; i <= '9' ; i++) {
14812    buf[0] = i;
14813    for (char j = '0'; j <= '9'; j++) {
14814      buf[1] = j;
14815      for (char k = '0'; k <= '9'; k++) {
14816        buf[2] = k;
14817        buf[3] = 0;
14818        templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14819      }
14820    }
14821  }
14822
14823  Local<v8::Object> instance_1 = templ->NewInstance();
14824  context->Global()->Set(v8_str("obj_1"), instance_1);
14825
14826  Local<Value> value_1 = CompileRun("obj_1.a");
14827  CHECK(value_1.IsEmpty());
14828
14829  Local<v8::Object> instance_2 = templ->NewInstance();
14830  context->Global()->Set(v8_str("obj_2"), instance_2);
14831
14832  Local<Value> value_2 = CompileRun("obj_2.a");
14833  CHECK(value_2.IsEmpty());
14834}
14835
14836
14837// This tests that access check information remains on the global
14838// object template when creating contexts.
14839THREADED_TEST(AccessControlRepeatedContextCreation) {
14840  v8::Isolate* isolate = CcTest::isolate();
14841  v8::HandleScope handle_scope(isolate);
14842  v8::Handle<v8::ObjectTemplate> global_template =
14843      v8::ObjectTemplate::New(isolate);
14844  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14845                                           IndexedSetAccessBlocker);
14846  i::Handle<i::ObjectTemplateInfo> internal_template =
14847      v8::Utils::OpenHandle(*global_template);
14848  CHECK(!internal_template->constructor()->IsUndefined());
14849  i::Handle<i::FunctionTemplateInfo> constructor(
14850      i::FunctionTemplateInfo::cast(internal_template->constructor()));
14851  CHECK(!constructor->access_check_info()->IsUndefined());
14852  v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14853  CHECK(!context0.IsEmpty());
14854  CHECK(!constructor->access_check_info()->IsUndefined());
14855}
14856
14857
14858THREADED_TEST(TurnOnAccessCheck) {
14859  v8::Isolate* isolate = CcTest::isolate();
14860  v8::HandleScope handle_scope(isolate);
14861
14862  // Create an environment with access check to the global object disabled by
14863  // default.
14864  v8::Handle<v8::ObjectTemplate> global_template =
14865      v8::ObjectTemplate::New(isolate);
14866  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14867                                           IndexedGetAccessBlocker,
14868                                           v8::Handle<v8::Value>(),
14869                                           false);
14870  v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14871  Context::Scope context_scope(context);
14872
14873  // Set up a property and a number of functions.
14874  context->Global()->Set(v8_str("a"), v8_num(1));
14875  CompileRun("function f1() {return a;}"
14876             "function f2() {return a;}"
14877             "function g1() {return h();}"
14878             "function g2() {return h();}"
14879             "function h() {return 1;}");
14880  Local<Function> f1 =
14881      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14882  Local<Function> f2 =
14883      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14884  Local<Function> g1 =
14885      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14886  Local<Function> g2 =
14887      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14888  Local<Function> h =
14889      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14890
14891  // Get the global object.
14892  v8::Handle<v8::Object> global = context->Global();
14893
14894  // Call f1 one time and f2 a number of times. This will ensure that f1 still
14895  // uses the runtime system to retreive property a whereas f2 uses global load
14896  // inline cache.
14897  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14898  for (int i = 0; i < 4; i++) {
14899    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14900  }
14901
14902  // Same for g1 and g2.
14903  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14904  for (int i = 0; i < 4; i++) {
14905    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14906  }
14907
14908  // Detach the global and turn on access check.
14909  Local<Object> hidden_global = Local<Object>::Cast(
14910      context->Global()->GetPrototype());
14911  context->DetachGlobal();
14912  hidden_global->TurnOnAccessCheck();
14913
14914  // Failing access check results in exception.
14915  CHECK(f1->Call(global, 0, NULL).IsEmpty());
14916  CHECK(f2->Call(global, 0, NULL).IsEmpty());
14917  CHECK(g1->Call(global, 0, NULL).IsEmpty());
14918  CHECK(g2->Call(global, 0, NULL).IsEmpty());
14919
14920  // No failing access check when just returning a constant.
14921  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14922}
14923
14924
14925static const char* kPropertyA = "a";
14926static const char* kPropertyH = "h";
14927
14928static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14929                                       Local<Value> name,
14930                                       v8::AccessType type,
14931                                       Local<Value> data) {
14932  if (!name->IsString()) return false;
14933  i::Handle<i::String> name_handle =
14934      v8::Utils::OpenHandle(String::Cast(*name));
14935  return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14936      && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14937}
14938
14939
14940THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14941  v8::Isolate* isolate = CcTest::isolate();
14942  v8::HandleScope handle_scope(isolate);
14943
14944  // Create an environment with access check to the global object disabled by
14945  // default. When the registered access checker will block access to properties
14946  // a and h.
14947  v8::Handle<v8::ObjectTemplate> global_template =
14948     v8::ObjectTemplate::New(isolate);
14949  global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14950                                           IndexedGetAccessBlocker,
14951                                           v8::Handle<v8::Value>(),
14952                                           false);
14953  v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14954  Context::Scope context_scope(context);
14955
14956  // Set up a property and a number of functions.
14957  context->Global()->Set(v8_str("a"), v8_num(1));
14958  static const char* source = "function f1() {return a;}"
14959                              "function f2() {return a;}"
14960                              "function g1() {return h();}"
14961                              "function g2() {return h();}"
14962                              "function h() {return 1;}";
14963
14964  CompileRun(source);
14965  Local<Function> f1;
14966  Local<Function> f2;
14967  Local<Function> g1;
14968  Local<Function> g2;
14969  Local<Function> h;
14970  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14971  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14972  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14973  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14974  h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14975
14976  // Get the global object.
14977  v8::Handle<v8::Object> global = context->Global();
14978
14979  // Call f1 one time and f2 a number of times. This will ensure that f1 still
14980  // uses the runtime system to retreive property a whereas f2 uses global load
14981  // inline cache.
14982  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14983  for (int i = 0; i < 4; i++) {
14984    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14985  }
14986
14987  // Same for g1 and g2.
14988  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14989  for (int i = 0; i < 4; i++) {
14990    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14991  }
14992
14993  // Detach the global and turn on access check now blocking access to property
14994  // a and function h.
14995  Local<Object> hidden_global = Local<Object>::Cast(
14996      context->Global()->GetPrototype());
14997  context->DetachGlobal();
14998  hidden_global->TurnOnAccessCheck();
14999
15000  // Failing access check results in exception.
15001  CHECK(f1->Call(global, 0, NULL).IsEmpty());
15002  CHECK(f2->Call(global, 0, NULL).IsEmpty());
15003  CHECK(g1->Call(global, 0, NULL).IsEmpty());
15004  CHECK(g2->Call(global, 0, NULL).IsEmpty());
15005
15006  // No failing access check when just returning a constant.
15007  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15008
15009  // Now compile the source again. And get the newly compiled functions, except
15010  // for h for which access is blocked.
15011  CompileRun(source);
15012  f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
15013  f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
15014  g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
15015  g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
15016  CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
15017
15018  // Failing access check results in exception.
15019  v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
15020  CHECK(result.IsEmpty());
15021  CHECK(f1->Call(global, 0, NULL).IsEmpty());
15022  CHECK(f2->Call(global, 0, NULL).IsEmpty());
15023  CHECK(g1->Call(global, 0, NULL).IsEmpty());
15024  CHECK(g2->Call(global, 0, NULL).IsEmpty());
15025}
15026
15027
15028// Tests that ScriptData can be serialized and deserialized.
15029TEST(PreCompileSerialization) {
15030  v8::V8::Initialize();
15031  LocalContext env;
15032  v8::Isolate* isolate = env->GetIsolate();
15033  HandleScope handle_scope(isolate);
15034
15035  i::FLAG_min_preparse_length = 0;
15036  const char* script = "function foo(a) { return a+1; }";
15037  v8::ScriptCompiler::Source source(v8_str(script));
15038  v8::ScriptCompiler::Compile(isolate, &source,
15039                              v8::ScriptCompiler::kProduceParserCache);
15040  // Serialize.
15041  const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
15042  i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
15043  i::MemCopy(serialized_data, cd->data, cd->length);
15044
15045  // Deserialize.
15046  i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
15047
15048  // Verify that the original is the same as the deserialized.
15049  CHECK_EQ(cd->length, deserialized->length());
15050  CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
15051
15052  delete deserialized;
15053  i::DeleteArray(serialized_data);
15054}
15055
15056
15057// This tests that we do not allow dictionary load/call inline caches
15058// to use functions that have not yet been compiled.  The potential
15059// problem of loading a function that has not yet been compiled can
15060// arise because we share code between contexts via the compilation
15061// cache.
15062THREADED_TEST(DictionaryICLoadedFunction) {
15063  v8::HandleScope scope(CcTest::isolate());
15064  // Test LoadIC.
15065  for (int i = 0; i < 2; i++) {
15066    LocalContext context;
15067    context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15068    context->Global()->Delete(v8_str("tmp"));
15069    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15070  }
15071  // Test CallIC.
15072  for (int i = 0; i < 2; i++) {
15073    LocalContext context;
15074    context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15075    context->Global()->Delete(v8_str("tmp"));
15076    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15077  }
15078}
15079
15080
15081// Test that cross-context new calls use the context of the callee to
15082// create the new JavaScript object.
15083THREADED_TEST(CrossContextNew) {
15084  v8::Isolate* isolate = CcTest::isolate();
15085  v8::HandleScope scope(isolate);
15086  v8::Local<Context> context0 = Context::New(isolate);
15087  v8::Local<Context> context1 = Context::New(isolate);
15088
15089  // Allow cross-domain access.
15090  Local<String> token = v8_str("<security token>");
15091  context0->SetSecurityToken(token);
15092  context1->SetSecurityToken(token);
15093
15094  // Set an 'x' property on the Object prototype and define a
15095  // constructor function in context0.
15096  context0->Enter();
15097  CompileRun("Object.prototype.x = 42; function C() {};");
15098  context0->Exit();
15099
15100  // Call the constructor function from context0 and check that the
15101  // result has the 'x' property.
15102  context1->Enter();
15103  context1->Global()->Set(v8_str("other"), context0->Global());
15104  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15105  CHECK(value->IsInt32());
15106  CHECK_EQ(42, value->Int32Value());
15107  context1->Exit();
15108}
15109
15110
15111// Verify that we can clone an object
15112TEST(ObjectClone) {
15113  LocalContext env;
15114  v8::Isolate* isolate = env->GetIsolate();
15115  v8::HandleScope scope(isolate);
15116
15117  const char* sample =
15118    "var rv = {};"      \
15119    "rv.alpha = 'hello';" \
15120    "rv.beta = 123;"     \
15121    "rv;";
15122
15123  // Create an object, verify basics.
15124  Local<Value> val = CompileRun(sample);
15125  CHECK(val->IsObject());
15126  Local<v8::Object> obj = val.As<v8::Object>();
15127  obj->Set(v8_str("gamma"), v8_str("cloneme"));
15128
15129  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15130  CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15131  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15132
15133  // Clone it.
15134  Local<v8::Object> clone = obj->Clone();
15135  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15136  CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15137  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15138
15139  // Set a property on the clone, verify each object.
15140  clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15141  CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15142  CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15143}
15144
15145
15146class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
15147 public:
15148  explicit OneByteVectorResource(i::Vector<const char> vector)
15149      : data_(vector) {}
15150  virtual ~OneByteVectorResource() {}
15151  virtual size_t length() const { return data_.length(); }
15152  virtual const char* data() const { return data_.start(); }
15153 private:
15154  i::Vector<const char> data_;
15155};
15156
15157
15158class UC16VectorResource : public v8::String::ExternalStringResource {
15159 public:
15160  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15161      : data_(vector) {}
15162  virtual ~UC16VectorResource() {}
15163  virtual size_t length() const { return data_.length(); }
15164  virtual const i::uc16* data() const { return data_.start(); }
15165 private:
15166  i::Vector<const i::uc16> data_;
15167};
15168
15169
15170static void MorphAString(i::String* string,
15171                         OneByteVectorResource* one_byte_resource,
15172                         UC16VectorResource* uc16_resource) {
15173  CHECK(i::StringShape(string).IsExternal());
15174  if (string->IsOneByteRepresentation()) {
15175    // Check old map is not internalized or long.
15176    CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
15177    // Morph external string to be TwoByte string.
15178    string->set_map(CcTest::heap()->external_string_map());
15179    i::ExternalTwoByteString* morphed =
15180         i::ExternalTwoByteString::cast(string);
15181    morphed->set_resource(uc16_resource);
15182  } else {
15183    // Check old map is not internalized or long.
15184    CHECK(string->map() == CcTest::heap()->external_string_map());
15185    // Morph external string to be one-byte string.
15186    string->set_map(CcTest::heap()->external_one_byte_string_map());
15187    i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
15188    morphed->set_resource(one_byte_resource);
15189  }
15190}
15191
15192
15193// Test that we can still flatten a string if the components it is built up
15194// from have been turned into 16 bit strings in the mean time.
15195THREADED_TEST(MorphCompositeStringTest) {
15196  char utf_buffer[129];
15197  const char* c_string = "Now is the time for all good men"
15198                         " to come to the aid of the party";
15199  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15200  {
15201    LocalContext env;
15202    i::Factory* factory = CcTest::i_isolate()->factory();
15203    v8::HandleScope scope(env->GetIsolate());
15204    OneByteVectorResource one_byte_resource(
15205        i::Vector<const char>(c_string, i::StrLength(c_string)));
15206    UC16VectorResource uc16_resource(
15207        i::Vector<const uint16_t>(two_byte_string,
15208                                  i::StrLength(c_string)));
15209
15210    Local<String> lhs(
15211        v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15212                                        &one_byte_resource).ToHandleChecked()));
15213    Local<String> rhs(
15214        v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15215                                        &one_byte_resource).ToHandleChecked()));
15216
15217    env->Global()->Set(v8_str("lhs"), lhs);
15218    env->Global()->Set(v8_str("rhs"), rhs);
15219
15220    CompileRun(
15221        "var cons = lhs + rhs;"
15222        "var slice = lhs.substring(1, lhs.length - 1);"
15223        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15224
15225    CHECK(lhs->IsOneByte());
15226    CHECK(rhs->IsOneByte());
15227
15228    MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
15229                 &uc16_resource);
15230    MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
15231                 &uc16_resource);
15232
15233    // This should UTF-8 without flattening, since everything is ASCII.
15234    Handle<String> cons = v8_compile("cons")->Run().As<String>();
15235    CHECK_EQ(128, cons->Utf8Length());
15236    int nchars = -1;
15237    CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15238    CHECK_EQ(128, nchars);
15239    CHECK_EQ(0, strcmp(
15240        utf_buffer,
15241        "Now is the time for all good men to come to the aid of the party"
15242        "Now is the time for all good men to come to the aid of the party"));
15243
15244    // Now do some stuff to make sure the strings are flattened, etc.
15245    CompileRun(
15246        "/[^a-z]/.test(cons);"
15247        "/[^a-z]/.test(slice);"
15248        "/[^a-z]/.test(slice_on_cons);");
15249    const char* expected_cons =
15250        "Now is the time for all good men to come to the aid of the party"
15251        "Now is the time for all good men to come to the aid of the party";
15252    const char* expected_slice =
15253        "ow is the time for all good men to come to the aid of the part";
15254    const char* expected_slice_on_cons =
15255        "ow is the time for all good men to come to the aid of the party"
15256        "Now is the time for all good men to come to the aid of the part";
15257    CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15258             env->Global()->Get(v8_str("cons")));
15259    CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15260             env->Global()->Get(v8_str("slice")));
15261    CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15262             env->Global()->Get(v8_str("slice_on_cons")));
15263  }
15264  i::DeleteArray(two_byte_string);
15265}
15266
15267
15268TEST(CompileExternalTwoByteSource) {
15269  LocalContext context;
15270  v8::HandleScope scope(context->GetIsolate());
15271
15272  // This is a very short list of sources, which currently is to check for a
15273  // regression caused by r2703.
15274  const char* one_byte_sources[] = {
15275      "0.5",
15276      "-0.5",   // This mainly testes PushBack in the Scanner.
15277      "--0.5",  // This mainly testes PushBack in the Scanner.
15278      NULL};
15279
15280  // Compile the sources as external two byte strings.
15281  for (int i = 0; one_byte_sources[i] != NULL; i++) {
15282    uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15283    TestResource* uc16_resource = new TestResource(two_byte_string);
15284    v8::Local<v8::String> source =
15285        v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15286    v8::Script::Compile(source);
15287  }
15288}
15289
15290
15291#ifndef V8_INTERPRETED_REGEXP
15292
15293struct RegExpInterruptionData {
15294  int loop_count;
15295  UC16VectorResource* string_resource;
15296  v8::Persistent<v8::String> string;
15297} regexp_interruption_data;
15298
15299
15300class RegExpInterruptionThread : public v8::base::Thread {
15301 public:
15302  explicit RegExpInterruptionThread(v8::Isolate* isolate)
15303      : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15304
15305  virtual void Run() {
15306    for (regexp_interruption_data.loop_count = 0;
15307         regexp_interruption_data.loop_count < 7;
15308         regexp_interruption_data.loop_count++) {
15309      v8::base::OS::Sleep(50);  // Wait a bit before requesting GC.
15310      reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15311    }
15312    v8::base::OS::Sleep(50);  // Wait a bit before terminating.
15313    v8::V8::TerminateExecution(isolate_);
15314  }
15315
15316 private:
15317  v8::Isolate* isolate_;
15318};
15319
15320
15321void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15322  if (regexp_interruption_data.loop_count != 2) return;
15323  v8::HandleScope scope(CcTest::isolate());
15324  v8::Local<v8::String> string = v8::Local<v8::String>::New(
15325      CcTest::isolate(), regexp_interruption_data.string);
15326  string->MakeExternal(regexp_interruption_data.string_resource);
15327}
15328
15329
15330// Test that RegExp execution can be interrupted.  Specifically, we test
15331// * interrupting with GC
15332// * turn the subject string from one-byte internal to two-byte external string
15333// * force termination
15334TEST(RegExpInterruption) {
15335  v8::HandleScope scope(CcTest::isolate());
15336  LocalContext env;
15337
15338  RegExpInterruptionThread timeout_thread(CcTest::isolate());
15339
15340  v8::V8::AddGCPrologueCallback(RunBeforeGC);
15341  static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15342  i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
15343  v8::Local<v8::String> string = v8_str(one_byte_content);
15344
15345  CcTest::global()->Set(v8_str("a"), string);
15346  regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15347  regexp_interruption_data.string_resource = new UC16VectorResource(
15348      i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
15349
15350  v8::TryCatch try_catch;
15351  timeout_thread.Start();
15352
15353  CompileRun("/((a*)*)*b/.exec(a)");
15354  CHECK(try_catch.HasTerminated());
15355
15356  timeout_thread.Join();
15357
15358  regexp_interruption_data.string.Reset();
15359  i::DeleteArray(uc16_content);
15360}
15361
15362#endif  // V8_INTERPRETED_REGEXP
15363
15364
15365// Test that we cannot set a property on the global object if there
15366// is a read-only property in the prototype chain.
15367TEST(ReadOnlyPropertyInGlobalProto) {
15368  v8::Isolate* isolate = CcTest::isolate();
15369  v8::HandleScope scope(isolate);
15370  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15371  LocalContext context(0, templ);
15372  v8::Handle<v8::Object> global = context->Global();
15373  v8::Handle<v8::Object> global_proto =
15374      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15375  global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
15376                         v8::ReadOnly);
15377  global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
15378                         v8::ReadOnly);
15379  // Check without 'eval' or 'with'.
15380  v8::Handle<v8::Value> res =
15381      CompileRun("function f() { x = 42; return x; }; f()");
15382  CHECK_EQ(v8::Integer::New(isolate, 0), res);
15383  // Check with 'eval'.
15384  res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15385  CHECK_EQ(v8::Integer::New(isolate, 0), res);
15386  // Check with 'with'.
15387  res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15388  CHECK_EQ(v8::Integer::New(isolate, 0), res);
15389}
15390
15391static int force_set_set_count = 0;
15392static int force_set_get_count = 0;
15393bool pass_on_get = false;
15394
15395static void ForceSetGetter(v8::Local<v8::String> name,
15396                           const v8::PropertyCallbackInfo<v8::Value>& info) {
15397  force_set_get_count++;
15398  if (pass_on_get) {
15399    return;
15400  }
15401  info.GetReturnValue().Set(3);
15402}
15403
15404static void ForceSetSetter(v8::Local<v8::String> name,
15405                           v8::Local<v8::Value> value,
15406                           const v8::PropertyCallbackInfo<void>& info) {
15407  force_set_set_count++;
15408}
15409
15410static void ForceSetInterceptSetter(
15411    v8::Local<v8::String> name,
15412    v8::Local<v8::Value> value,
15413    const v8::PropertyCallbackInfo<v8::Value>& info) {
15414  force_set_set_count++;
15415  info.GetReturnValue().SetUndefined();
15416}
15417
15418
15419TEST(ForceSet) {
15420  force_set_get_count = 0;
15421  force_set_set_count = 0;
15422  pass_on_get = false;
15423
15424  v8::Isolate* isolate = CcTest::isolate();
15425  v8::HandleScope scope(isolate);
15426  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15427  v8::Handle<v8::String> access_property =
15428      v8::String::NewFromUtf8(isolate, "a");
15429  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15430  LocalContext context(NULL, templ);
15431  v8::Handle<v8::Object> global = context->Global();
15432
15433  // Ordinary properties
15434  v8::Handle<v8::String> simple_property =
15435      v8::String::NewFromUtf8(isolate, "p");
15436  global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15437  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15438  // This should fail because the property is read-only
15439  global->Set(simple_property, v8::Int32::New(isolate, 5));
15440  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15441  // This should succeed even though the property is read-only
15442  global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15443  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15444
15445  // Accessors
15446  CHECK_EQ(0, force_set_set_count);
15447  CHECK_EQ(0, force_set_get_count);
15448  CHECK_EQ(3, global->Get(access_property)->Int32Value());
15449  // CHECK_EQ the property shouldn't override it, just call the setter
15450  // which in this case does nothing.
15451  global->Set(access_property, v8::Int32::New(isolate, 7));
15452  CHECK_EQ(3, global->Get(access_property)->Int32Value());
15453  CHECK_EQ(1, force_set_set_count);
15454  CHECK_EQ(2, force_set_get_count);
15455  // Forcing the property to be set should override the accessor without
15456  // calling it
15457  global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15458  CHECK_EQ(8, global->Get(access_property)->Int32Value());
15459  CHECK_EQ(1, force_set_set_count);
15460  CHECK_EQ(2, force_set_get_count);
15461}
15462
15463
15464TEST(ForceSetWithInterceptor) {
15465  force_set_get_count = 0;
15466  force_set_set_count = 0;
15467  pass_on_get = false;
15468
15469  v8::Isolate* isolate = CcTest::isolate();
15470  v8::HandleScope scope(isolate);
15471  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15472  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15473  LocalContext context(NULL, templ);
15474  v8::Handle<v8::Object> global = context->Global();
15475
15476  v8::Handle<v8::String> some_property =
15477      v8::String::NewFromUtf8(isolate, "a");
15478  CHECK_EQ(0, force_set_set_count);
15479  CHECK_EQ(0, force_set_get_count);
15480  CHECK_EQ(3, global->Get(some_property)->Int32Value());
15481  // Setting the property shouldn't override it, just call the setter
15482  // which in this case does nothing.
15483  global->Set(some_property, v8::Int32::New(isolate, 7));
15484  CHECK_EQ(3, global->Get(some_property)->Int32Value());
15485  CHECK_EQ(1, force_set_set_count);
15486  CHECK_EQ(2, force_set_get_count);
15487  // Getting the property when the interceptor returns an empty handle
15488  // should yield undefined, since the property isn't present on the
15489  // object itself yet.
15490  pass_on_get = true;
15491  CHECK(global->Get(some_property)->IsUndefined());
15492  CHECK_EQ(1, force_set_set_count);
15493  CHECK_EQ(3, force_set_get_count);
15494  // Forcing the property to be set should cause the value to be
15495  // set locally without calling the interceptor.
15496  global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15497  CHECK_EQ(8, global->Get(some_property)->Int32Value());
15498  CHECK_EQ(1, force_set_set_count);
15499  CHECK_EQ(4, force_set_get_count);
15500  // Reenabling the interceptor should cause it to take precedence over
15501  // the property
15502  pass_on_get = false;
15503  CHECK_EQ(3, global->Get(some_property)->Int32Value());
15504  CHECK_EQ(1, force_set_set_count);
15505  CHECK_EQ(5, force_set_get_count);
15506  // The interceptor should also work for other properties
15507  CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15508                  ->Int32Value());
15509  CHECK_EQ(1, force_set_set_count);
15510  CHECK_EQ(6, force_set_get_count);
15511}
15512
15513
15514THREADED_TEST(ForceDelete) {
15515  v8::Isolate* isolate = CcTest::isolate();
15516  v8::HandleScope scope(isolate);
15517  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15518  LocalContext context(NULL, templ);
15519  v8::Handle<v8::Object> global = context->Global();
15520
15521  // Ordinary properties
15522  v8::Handle<v8::String> simple_property =
15523      v8::String::NewFromUtf8(isolate, "p");
15524  global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15525  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15526  // This should fail because the property is dont-delete.
15527  CHECK(!global->Delete(simple_property));
15528  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15529  // This should succeed even though the property is dont-delete.
15530  CHECK(global->ForceDelete(simple_property));
15531  CHECK(global->Get(simple_property)->IsUndefined());
15532}
15533
15534
15535static int force_delete_interceptor_count = 0;
15536static bool pass_on_delete = false;
15537
15538
15539static void ForceDeleteDeleter(
15540    v8::Local<v8::String> name,
15541    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15542  force_delete_interceptor_count++;
15543  if (pass_on_delete) return;
15544  info.GetReturnValue().Set(true);
15545}
15546
15547
15548THREADED_TEST(ForceDeleteWithInterceptor) {
15549  force_delete_interceptor_count = 0;
15550  pass_on_delete = false;
15551
15552  v8::Isolate* isolate = CcTest::isolate();
15553  v8::HandleScope scope(isolate);
15554  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15555  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15556  LocalContext context(NULL, templ);
15557  v8::Handle<v8::Object> global = context->Global();
15558
15559  v8::Handle<v8::String> some_property =
15560      v8::String::NewFromUtf8(isolate, "a");
15561  global->ForceSet(some_property, v8::Integer::New(isolate, 42),
15562                   v8::DontDelete);
15563
15564  // Deleting a property should get intercepted and nothing should
15565  // happen.
15566  CHECK_EQ(0, force_delete_interceptor_count);
15567  CHECK(global->Delete(some_property));
15568  CHECK_EQ(1, force_delete_interceptor_count);
15569  CHECK_EQ(42, global->Get(some_property)->Int32Value());
15570  // Deleting the property when the interceptor returns an empty
15571  // handle should not delete the property since it is DontDelete.
15572  pass_on_delete = true;
15573  CHECK(!global->Delete(some_property));
15574  CHECK_EQ(2, force_delete_interceptor_count);
15575  CHECK_EQ(42, global->Get(some_property)->Int32Value());
15576  // Forcing the property to be deleted should delete the value
15577  // without calling the interceptor.
15578  CHECK(global->ForceDelete(some_property));
15579  CHECK(global->Get(some_property)->IsUndefined());
15580  CHECK_EQ(2, force_delete_interceptor_count);
15581}
15582
15583
15584// Make sure that forcing a delete invalidates any IC stubs, so we
15585// don't read the hole value.
15586THREADED_TEST(ForceDeleteIC) {
15587  LocalContext context;
15588  v8::HandleScope scope(context->GetIsolate());
15589  // Create a DontDelete variable on the global object.
15590  CompileRun("this.__proto__ = { foo: 'horse' };"
15591             "var foo = 'fish';"
15592             "function f() { return foo.length; }");
15593  // Initialize the IC for foo in f.
15594  CompileRun("for (var i = 0; i < 4; i++) f();");
15595  // Make sure the value of foo is correct before the deletion.
15596  CHECK_EQ(4, CompileRun("f()")->Int32Value());
15597  // Force the deletion of foo.
15598  CHECK(context->Global()->ForceDelete(v8_str("foo")));
15599  // Make sure the value for foo is read from the prototype, and that
15600  // we don't get in trouble with reading the deleted cell value
15601  // sentinel.
15602  CHECK_EQ(5, CompileRun("f()")->Int32Value());
15603}
15604
15605
15606TEST(InlinedFunctionAcrossContexts) {
15607  i::FLAG_allow_natives_syntax = true;
15608  v8::Isolate* isolate = CcTest::isolate();
15609  v8::HandleScope outer_scope(isolate);
15610  v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15611  v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15612  ctx1->Enter();
15613
15614  {
15615    v8::HandleScope inner_scope(CcTest::isolate());
15616    CompileRun("var G = 42; function foo() { return G; }");
15617    v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15618    ctx2->Enter();
15619    ctx2->Global()->Set(v8_str("o"), foo);
15620    v8::Local<v8::Value> res = CompileRun(
15621        "function f() { return o(); }"
15622        "for (var i = 0; i < 10; ++i) f();"
15623        "%OptimizeFunctionOnNextCall(f);"
15624        "f();");
15625    CHECK_EQ(42, res->Int32Value());
15626    ctx2->Exit();
15627    v8::Handle<v8::String> G_property =
15628        v8::String::NewFromUtf8(CcTest::isolate(), "G");
15629    CHECK(ctx1->Global()->ForceDelete(G_property));
15630    ctx2->Enter();
15631    ExpectString(
15632        "(function() {"
15633        "  try {"
15634        "    return f();"
15635        "  } catch(e) {"
15636        "    return e.toString();"
15637        "  }"
15638        " })()",
15639        "ReferenceError: G is not defined");
15640    ctx2->Exit();
15641    ctx1->Exit();
15642  }
15643}
15644
15645
15646static v8::Local<Context> calling_context0;
15647static v8::Local<Context> calling_context1;
15648static v8::Local<Context> calling_context2;
15649
15650
15651// Check that the call to the callback is initiated in
15652// calling_context2, the directly calling context is calling_context1
15653// and the callback itself is in calling_context0.
15654static void GetCallingContextCallback(
15655    const v8::FunctionCallbackInfo<v8::Value>& args) {
15656  ApiTestFuzzer::Fuzz();
15657  CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15658  CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15659  CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15660  args.GetReturnValue().Set(42);
15661}
15662
15663
15664THREADED_TEST(GetCurrentContextWhenNotInContext) {
15665  i::Isolate* isolate = CcTest::i_isolate();
15666  CHECK(isolate != NULL);
15667  CHECK(isolate->context() == NULL);
15668  v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15669  v8::HandleScope scope(v8_isolate);
15670  // The following should not crash, but return an empty handle.
15671  v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15672  CHECK(current.IsEmpty());
15673}
15674
15675
15676THREADED_TEST(GetCallingContext) {
15677  v8::Isolate* isolate = CcTest::isolate();
15678  v8::HandleScope scope(isolate);
15679
15680  Local<Context> calling_context0(Context::New(isolate));
15681  Local<Context> calling_context1(Context::New(isolate));
15682  Local<Context> calling_context2(Context::New(isolate));
15683  ::calling_context0 = calling_context0;
15684  ::calling_context1 = calling_context1;
15685  ::calling_context2 = calling_context2;
15686
15687  // Allow cross-domain access.
15688  Local<String> token = v8_str("<security token>");
15689  calling_context0->SetSecurityToken(token);
15690  calling_context1->SetSecurityToken(token);
15691  calling_context2->SetSecurityToken(token);
15692
15693  // Create an object with a C++ callback in context0.
15694  calling_context0->Enter();
15695  Local<v8::FunctionTemplate> callback_templ =
15696      v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15697  calling_context0->Global()->Set(v8_str("callback"),
15698                                  callback_templ->GetFunction());
15699  calling_context0->Exit();
15700
15701  // Expose context0 in context1 and set up a function that calls the
15702  // callback function.
15703  calling_context1->Enter();
15704  calling_context1->Global()->Set(v8_str("context0"),
15705                                  calling_context0->Global());
15706  CompileRun("function f() { context0.callback() }");
15707  calling_context1->Exit();
15708
15709  // Expose context1 in context2 and call the callback function in
15710  // context0 indirectly through f in context1.
15711  calling_context2->Enter();
15712  calling_context2->Global()->Set(v8_str("context1"),
15713                                  calling_context1->Global());
15714  CompileRun("context1.f()");
15715  calling_context2->Exit();
15716  ::calling_context0.Clear();
15717  ::calling_context1.Clear();
15718  ::calling_context2.Clear();
15719}
15720
15721
15722// Check that a variable declaration with no explicit initialization
15723// value does shadow an existing property in the prototype chain.
15724THREADED_TEST(InitGlobalVarInProtoChain) {
15725  LocalContext context;
15726  v8::HandleScope scope(context->GetIsolate());
15727  // Introduce a variable in the prototype chain.
15728  CompileRun("__proto__.x = 42");
15729  v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15730  CHECK(!result->IsUndefined());
15731  CHECK_EQ(43, result->Int32Value());
15732}
15733
15734
15735// Regression test for issue 398.
15736// If a function is added to an object, creating a constant function
15737// field, and the result is cloned, replacing the constant function on the
15738// original should not affect the clone.
15739// See http://code.google.com/p/v8/issues/detail?id=398
15740THREADED_TEST(ReplaceConstantFunction) {
15741  LocalContext context;
15742  v8::Isolate* isolate = context->GetIsolate();
15743  v8::HandleScope scope(isolate);
15744  v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15745  v8::Handle<v8::FunctionTemplate> func_templ =
15746      v8::FunctionTemplate::New(isolate);
15747  v8::Handle<v8::String> foo_string =
15748      v8::String::NewFromUtf8(isolate, "foo");
15749  obj->Set(foo_string, func_templ->GetFunction());
15750  v8::Handle<v8::Object> obj_clone = obj->Clone();
15751  obj_clone->Set(foo_string,
15752                 v8::String::NewFromUtf8(isolate, "Hello"));
15753  CHECK(!obj->Get(foo_string)->IsUndefined());
15754}
15755
15756
15757static void CheckElementValue(i::Isolate* isolate,
15758                              int expected,
15759                              i::Handle<i::Object> obj,
15760                              int offset) {
15761  i::Object* element =
15762      *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15763  CHECK_EQ(expected, i::Smi::cast(element)->value());
15764}
15765
15766
15767THREADED_TEST(PixelArray) {
15768  LocalContext context;
15769  i::Isolate* isolate = CcTest::i_isolate();
15770  i::Factory* factory = isolate->factory();
15771  v8::HandleScope scope(context->GetIsolate());
15772  const int kElementCount = 260;
15773  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15774  i::Handle<i::ExternalUint8ClampedArray> pixels =
15775      i::Handle<i::ExternalUint8ClampedArray>::cast(
15776          factory->NewExternalArray(kElementCount,
15777                                    v8::kExternalUint8ClampedArray,
15778                                    pixel_data));
15779  // Force GC to trigger verification.
15780  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15781  for (int i = 0; i < kElementCount; i++) {
15782    pixels->set(i, i % 256);
15783  }
15784  // Force GC to trigger verification.
15785  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15786  for (int i = 0; i < kElementCount; i++) {
15787    CHECK_EQ(i % 256, pixels->get_scalar(i));
15788    CHECK_EQ(i % 256, pixel_data[i]);
15789  }
15790
15791  v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15792  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15793  // Set the elements to be the pixels.
15794  // jsobj->set_elements(*pixels);
15795  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15796  CheckElementValue(isolate, 1, jsobj, 1);
15797  obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15798  context->Global()->Set(v8_str("pixels"), obj);
15799  v8::Handle<v8::Value> result = CompileRun("pixels.field");
15800  CHECK_EQ(1503, result->Int32Value());
15801  result = CompileRun("pixels[1]");
15802  CHECK_EQ(1, result->Int32Value());
15803
15804  result = CompileRun("var sum = 0;"
15805                      "for (var i = 0; i < 8; i++) {"
15806                      "  sum += pixels[i] = pixels[i] = -i;"
15807                      "}"
15808                      "sum;");
15809  CHECK_EQ(-28, result->Int32Value());
15810
15811  result = CompileRun("var sum = 0;"
15812                      "for (var i = 0; i < 8; i++) {"
15813                      "  sum += pixels[i] = pixels[i] = 0;"
15814                      "}"
15815                      "sum;");
15816  CHECK_EQ(0, result->Int32Value());
15817
15818  result = CompileRun("var sum = 0;"
15819                      "for (var i = 0; i < 8; i++) {"
15820                      "  sum += pixels[i] = pixels[i] = 255;"
15821                      "}"
15822                      "sum;");
15823  CHECK_EQ(8 * 255, result->Int32Value());
15824
15825  result = CompileRun("var sum = 0;"
15826                      "for (var i = 0; i < 8; i++) {"
15827                      "  sum += pixels[i] = pixels[i] = 256 + i;"
15828                      "}"
15829                      "sum;");
15830  CHECK_EQ(2076, result->Int32Value());
15831
15832  result = CompileRun("var sum = 0;"
15833                      "for (var i = 0; i < 8; i++) {"
15834                      "  sum += pixels[i] = pixels[i] = i;"
15835                      "}"
15836                      "sum;");
15837  CHECK_EQ(28, result->Int32Value());
15838
15839  result = CompileRun("var sum = 0;"
15840                      "for (var i = 0; i < 8; i++) {"
15841                      "  sum += pixels[i];"
15842                      "}"
15843                      "sum;");
15844  CHECK_EQ(28, result->Int32Value());
15845
15846  i::Handle<i::Smi> value(i::Smi::FromInt(2),
15847                          reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15848  i::Handle<i::Object> no_failure;
15849  no_failure = i::JSObject::SetElement(
15850      jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15851  DCHECK(!no_failure.is_null());
15852  USE(no_failure);
15853  CheckElementValue(isolate, 2, jsobj, 1);
15854  *value.location() = i::Smi::FromInt(256);
15855  no_failure = i::JSObject::SetElement(
15856      jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15857  DCHECK(!no_failure.is_null());
15858  USE(no_failure);
15859  CheckElementValue(isolate, 255, jsobj, 1);
15860  *value.location() = i::Smi::FromInt(-1);
15861  no_failure = i::JSObject::SetElement(
15862      jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15863  DCHECK(!no_failure.is_null());
15864  USE(no_failure);
15865  CheckElementValue(isolate, 0, jsobj, 1);
15866
15867  result = CompileRun("for (var i = 0; i < 8; i++) {"
15868                      "  pixels[i] = (i * 65) - 109;"
15869                      "}"
15870                      "pixels[1] + pixels[6];");
15871  CHECK_EQ(255, result->Int32Value());
15872  CheckElementValue(isolate, 0, jsobj, 0);
15873  CheckElementValue(isolate, 0, jsobj, 1);
15874  CheckElementValue(isolate, 21, jsobj, 2);
15875  CheckElementValue(isolate, 86, jsobj, 3);
15876  CheckElementValue(isolate, 151, jsobj, 4);
15877  CheckElementValue(isolate, 216, jsobj, 5);
15878  CheckElementValue(isolate, 255, jsobj, 6);
15879  CheckElementValue(isolate, 255, jsobj, 7);
15880  result = CompileRun("var sum = 0;"
15881                      "for (var i = 0; i < 8; i++) {"
15882                      "  sum += pixels[i];"
15883                      "}"
15884                      "sum;");
15885  CHECK_EQ(984, result->Int32Value());
15886
15887  result = CompileRun("for (var i = 0; i < 8; i++) {"
15888                      "  pixels[i] = (i * 1.1);"
15889                      "}"
15890                      "pixels[1] + pixels[6];");
15891  CHECK_EQ(8, result->Int32Value());
15892  CheckElementValue(isolate, 0, jsobj, 0);
15893  CheckElementValue(isolate, 1, jsobj, 1);
15894  CheckElementValue(isolate, 2, jsobj, 2);
15895  CheckElementValue(isolate, 3, jsobj, 3);
15896  CheckElementValue(isolate, 4, jsobj, 4);
15897  CheckElementValue(isolate, 6, jsobj, 5);
15898  CheckElementValue(isolate, 7, jsobj, 6);
15899  CheckElementValue(isolate, 8, jsobj, 7);
15900
15901  result = CompileRun("for (var i = 0; i < 8; i++) {"
15902                      "  pixels[7] = undefined;"
15903                      "}"
15904                      "pixels[7];");
15905  CHECK_EQ(0, result->Int32Value());
15906  CheckElementValue(isolate, 0, jsobj, 7);
15907
15908  result = CompileRun("for (var i = 0; i < 8; i++) {"
15909                      "  pixels[6] = '2.3';"
15910                      "}"
15911                      "pixels[6];");
15912  CHECK_EQ(2, result->Int32Value());
15913  CheckElementValue(isolate, 2, jsobj, 6);
15914
15915  result = CompileRun("for (var i = 0; i < 8; i++) {"
15916                      "  pixels[5] = NaN;"
15917                      "}"
15918                      "pixels[5];");
15919  CHECK_EQ(0, result->Int32Value());
15920  CheckElementValue(isolate, 0, jsobj, 5);
15921
15922  result = CompileRun("for (var i = 0; i < 8; i++) {"
15923                      "  pixels[8] = Infinity;"
15924                      "}"
15925                      "pixels[8];");
15926  CHECK_EQ(255, result->Int32Value());
15927  CheckElementValue(isolate, 255, jsobj, 8);
15928
15929  result = CompileRun("for (var i = 0; i < 8; i++) {"
15930                      "  pixels[9] = -Infinity;"
15931                      "}"
15932                      "pixels[9];");
15933  CHECK_EQ(0, result->Int32Value());
15934  CheckElementValue(isolate, 0, jsobj, 9);
15935
15936  result = CompileRun("pixels[3] = 33;"
15937                      "delete pixels[3];"
15938                      "pixels[3];");
15939  CHECK_EQ(33, result->Int32Value());
15940
15941  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15942                      "pixels[2] = 12; pixels[3] = 13;"
15943                      "pixels.__defineGetter__('2',"
15944                      "function() { return 120; });"
15945                      "pixels[2];");
15946  CHECK_EQ(12, result->Int32Value());
15947
15948  result = CompileRun("var js_array = new Array(40);"
15949                      "js_array[0] = 77;"
15950                      "js_array;");
15951  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15952
15953  result = CompileRun("pixels[1] = 23;"
15954                      "pixels.__proto__ = [];"
15955                      "js_array.__proto__ = pixels;"
15956                      "js_array.concat(pixels);");
15957  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15958  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15959
15960  result = CompileRun("pixels[1] = 23;");
15961  CHECK_EQ(23, result->Int32Value());
15962
15963  // Test for index greater than 255.  Regression test for:
15964  // http://code.google.com/p/chromium/issues/detail?id=26337.
15965  result = CompileRun("pixels[256] = 255;");
15966  CHECK_EQ(255, result->Int32Value());
15967  result = CompileRun("var i = 0;"
15968                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15969                      "i");
15970  CHECK_EQ(255, result->Int32Value());
15971
15972  // Make sure that pixel array ICs recognize when a non-pixel array
15973  // is passed to it.
15974  result = CompileRun("function pa_load(p) {"
15975                      "  var sum = 0;"
15976                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15977                      "  return sum;"
15978                      "}"
15979                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15980                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15981                      "just_ints = new Object();"
15982                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15983                      "for (var i = 0; i < 10; ++i) {"
15984                      "  result = pa_load(just_ints);"
15985                      "}"
15986                      "result");
15987  CHECK_EQ(32640, result->Int32Value());
15988
15989  // Make sure that pixel array ICs recognize out-of-bound accesses.
15990  result = CompileRun("function pa_load(p, start) {"
15991                      "  var sum = 0;"
15992                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15993                      "  return sum;"
15994                      "}"
15995                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15996                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15997                      "for (var i = 0; i < 10; ++i) {"
15998                      "  result = pa_load(pixels,-10);"
15999                      "}"
16000                      "result");
16001  CHECK_EQ(0, result->Int32Value());
16002
16003  // Make sure that generic ICs properly handles a pixel array.
16004  result = CompileRun("function pa_load(p) {"
16005                      "  var sum = 0;"
16006                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16007                      "  return sum;"
16008                      "}"
16009                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16010                      "just_ints = new Object();"
16011                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16012                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16013                      "for (var i = 0; i < 10; ++i) {"
16014                      "  result = pa_load(pixels);"
16015                      "}"
16016                      "result");
16017  CHECK_EQ(32640, result->Int32Value());
16018
16019  // Make sure that generic load ICs recognize out-of-bound accesses in
16020  // pixel arrays.
16021  result = CompileRun("function pa_load(p, start) {"
16022                      "  var sum = 0;"
16023                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
16024                      "  return sum;"
16025                      "}"
16026                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16027                      "just_ints = new Object();"
16028                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16029                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
16030                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16031                      "for (var i = 0; i < 10; ++i) {"
16032                      "  result = pa_load(pixels,-10);"
16033                      "}"
16034                      "result");
16035  CHECK_EQ(0, result->Int32Value());
16036
16037  // Make sure that generic ICs properly handles other types than pixel
16038  // arrays (that the inlined fast pixel array test leaves the right information
16039  // in the right registers).
16040  result = CompileRun("function pa_load(p) {"
16041                      "  var sum = 0;"
16042                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16043                      "  return sum;"
16044                      "}"
16045                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16046                      "just_ints = new Object();"
16047                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16048                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16049                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16050                      "sparse_array = new Object();"
16051                      "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16052                      "sparse_array[1000000] = 3;"
16053                      "for (var i = 0; i < 10; ++i) {"
16054                      "  result = pa_load(sparse_array);"
16055                      "}"
16056                      "result");
16057  CHECK_EQ(32640, result->Int32Value());
16058
16059  // Make sure that pixel array store ICs clamp values correctly.
16060  result = CompileRun("function pa_store(p) {"
16061                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16062                      "}"
16063                      "pa_store(pixels);"
16064                      "var sum = 0;"
16065                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16066                      "sum");
16067  CHECK_EQ(48896, result->Int32Value());
16068
16069  // Make sure that pixel array stores correctly handle accesses outside
16070  // of the pixel array..
16071  result = CompileRun("function pa_store(p,start) {"
16072                      "  for (var j = 0; j < 256; j++) {"
16073                      "    p[j+start] = j * 2;"
16074                      "  }"
16075                      "}"
16076                      "pa_store(pixels,0);"
16077                      "pa_store(pixels,-128);"
16078                      "var sum = 0;"
16079                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16080                      "sum");
16081  CHECK_EQ(65280, result->Int32Value());
16082
16083  // Make sure that the generic store stub correctly handle accesses outside
16084  // of the pixel array..
16085  result = CompileRun("function pa_store(p,start) {"
16086                      "  for (var j = 0; j < 256; j++) {"
16087                      "    p[j+start] = j * 2;"
16088                      "  }"
16089                      "}"
16090                      "pa_store(pixels,0);"
16091                      "just_ints = new Object();"
16092                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16093                      "pa_store(just_ints, 0);"
16094                      "pa_store(pixels,-128);"
16095                      "var sum = 0;"
16096                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16097                      "sum");
16098  CHECK_EQ(65280, result->Int32Value());
16099
16100  // Make sure that the generic keyed store stub clamps pixel array values
16101  // correctly.
16102  result = CompileRun("function pa_store(p) {"
16103                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16104                      "}"
16105                      "pa_store(pixels);"
16106                      "just_ints = new Object();"
16107                      "pa_store(just_ints);"
16108                      "pa_store(pixels);"
16109                      "var sum = 0;"
16110                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16111                      "sum");
16112  CHECK_EQ(48896, result->Int32Value());
16113
16114  // Make sure that pixel array loads are optimized by crankshaft.
16115  result = CompileRun("function pa_load(p) {"
16116                      "  var sum = 0;"
16117                      "  for (var i=0; i<256; ++i) {"
16118                      "    sum += p[i];"
16119                      "  }"
16120                      "  return sum; "
16121                      "}"
16122                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16123                      "for (var i = 0; i < 5000; ++i) {"
16124                      "  result = pa_load(pixels);"
16125                      "}"
16126                      "result");
16127  CHECK_EQ(32640, result->Int32Value());
16128
16129  // Make sure that pixel array stores are optimized by crankshaft.
16130  result = CompileRun("function pa_init(p) {"
16131                      "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16132                      "}"
16133                      "function pa_load(p) {"
16134                      "  var sum = 0;"
16135                      "  for (var i=0; i<256; ++i) {"
16136                      "    sum += p[i];"
16137                      "  }"
16138                      "  return sum; "
16139                      "}"
16140                      "for (var i = 0; i < 5000; ++i) {"
16141                      "  pa_init(pixels);"
16142                      "}"
16143                      "result = pa_load(pixels);"
16144                      "result");
16145  CHECK_EQ(32640, result->Int32Value());
16146
16147  free(pixel_data);
16148}
16149
16150
16151THREADED_TEST(PixelArrayInfo) {
16152  LocalContext context;
16153  v8::HandleScope scope(context->GetIsolate());
16154  for (int size = 0; size < 100; size += 10) {
16155    uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16156    v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16157    obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16158    CHECK(obj->HasIndexedPropertiesInPixelData());
16159    CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16160    CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16161    free(pixel_data);
16162  }
16163}
16164
16165
16166static void NotHandledIndexedPropertyGetter(
16167    uint32_t index,
16168    const v8::PropertyCallbackInfo<v8::Value>& info) {
16169  ApiTestFuzzer::Fuzz();
16170}
16171
16172
16173static void NotHandledIndexedPropertySetter(
16174    uint32_t index,
16175    Local<Value> value,
16176    const v8::PropertyCallbackInfo<v8::Value>& info) {
16177  ApiTestFuzzer::Fuzz();
16178}
16179
16180
16181THREADED_TEST(PixelArrayWithInterceptor) {
16182  LocalContext context;
16183  i::Factory* factory = CcTest::i_isolate()->factory();
16184  v8::Isolate* isolate = context->GetIsolate();
16185  v8::HandleScope scope(isolate);
16186  const int kElementCount = 260;
16187  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16188  i::Handle<i::ExternalUint8ClampedArray> pixels =
16189      i::Handle<i::ExternalUint8ClampedArray>::cast(
16190          factory->NewExternalArray(kElementCount,
16191                                    v8::kExternalUint8ClampedArray,
16192                                    pixel_data));
16193  for (int i = 0; i < kElementCount; i++) {
16194    pixels->set(i, i % 256);
16195  }
16196  v8::Handle<v8::ObjectTemplate> templ =
16197      v8::ObjectTemplate::New(context->GetIsolate());
16198  templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16199                                   NotHandledIndexedPropertySetter);
16200  v8::Handle<v8::Object> obj = templ->NewInstance();
16201  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16202  context->Global()->Set(v8_str("pixels"), obj);
16203  v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16204  CHECK_EQ(1, result->Int32Value());
16205  result = CompileRun("var sum = 0;"
16206                      "for (var i = 0; i < 8; i++) {"
16207                      "  sum += pixels[i] = pixels[i] = -i;"
16208                      "}"
16209                      "sum;");
16210  CHECK_EQ(-28, result->Int32Value());
16211  result = CompileRun("pixels.hasOwnProperty('1')");
16212  CHECK(result->BooleanValue());
16213  free(pixel_data);
16214}
16215
16216
16217static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16218  switch (array_type) {
16219    case v8::kExternalInt8Array:
16220    case v8::kExternalUint8Array:
16221    case v8::kExternalUint8ClampedArray:
16222      return 1;
16223      break;
16224    case v8::kExternalInt16Array:
16225    case v8::kExternalUint16Array:
16226      return 2;
16227      break;
16228    case v8::kExternalInt32Array:
16229    case v8::kExternalUint32Array:
16230    case v8::kExternalFloat32Array:
16231      return 4;
16232      break;
16233    case v8::kExternalFloat64Array:
16234      return 8;
16235      break;
16236    default:
16237      UNREACHABLE();
16238      return -1;
16239  }
16240  UNREACHABLE();
16241  return -1;
16242}
16243
16244
16245template <class ExternalArrayClass, class ElementType>
16246static void ObjectWithExternalArrayTestHelper(
16247    Handle<Context> context,
16248    v8::Handle<Object> obj,
16249    int element_count,
16250    v8::ExternalArrayType array_type,
16251    int64_t low, int64_t high) {
16252  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16253  i::Isolate* isolate = jsobj->GetIsolate();
16254  obj->Set(v8_str("field"),
16255           v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16256  context->Global()->Set(v8_str("ext_array"), obj);
16257  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16258  CHECK_EQ(1503, result->Int32Value());
16259  result = CompileRun("ext_array[1]");
16260  CHECK_EQ(1, result->Int32Value());
16261
16262  // Check assigned smis
16263  result = CompileRun("for (var i = 0; i < 8; i++) {"
16264                      "  ext_array[i] = i;"
16265                      "}"
16266                      "var sum = 0;"
16267                      "for (var i = 0; i < 8; i++) {"
16268                      "  sum += ext_array[i];"
16269                      "}"
16270                      "sum;");
16271
16272  CHECK_EQ(28, result->Int32Value());
16273  // Check pass through of assigned smis
16274  result = CompileRun("var sum = 0;"
16275                      "for (var i = 0; i < 8; i++) {"
16276                      "  sum += ext_array[i] = ext_array[i] = -i;"
16277                      "}"
16278                      "sum;");
16279  CHECK_EQ(-28, result->Int32Value());
16280
16281
16282  // Check assigned smis in reverse order
16283  result = CompileRun("for (var i = 8; --i >= 0; ) {"
16284                      "  ext_array[i] = i;"
16285                      "}"
16286                      "var sum = 0;"
16287                      "for (var i = 0; i < 8; i++) {"
16288                      "  sum += ext_array[i];"
16289                      "}"
16290                      "sum;");
16291  CHECK_EQ(28, result->Int32Value());
16292
16293  // Check pass through of assigned HeapNumbers
16294  result = CompileRun("var sum = 0;"
16295                      "for (var i = 0; i < 16; i+=2) {"
16296                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16297                      "}"
16298                      "sum;");
16299  CHECK_EQ(-28, result->Int32Value());
16300
16301  // Check assigned HeapNumbers
16302  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16303                      "  ext_array[i] = (i * 0.5);"
16304                      "}"
16305                      "var sum = 0;"
16306                      "for (var i = 0; i < 16; i+=2) {"
16307                      "  sum += ext_array[i];"
16308                      "}"
16309                      "sum;");
16310  CHECK_EQ(28, result->Int32Value());
16311
16312  // Check assigned HeapNumbers in reverse order
16313  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16314                      "  ext_array[i] = (i * 0.5);"
16315                      "}"
16316                      "var sum = 0;"
16317                      "for (var i = 0; i < 16; i+=2) {"
16318                      "  sum += ext_array[i];"
16319                      "}"
16320                      "sum;");
16321  CHECK_EQ(28, result->Int32Value());
16322
16323  i::ScopedVector<char> test_buf(1024);
16324
16325  // Check legal boundary conditions.
16326  // The repeated loads and stores ensure the ICs are exercised.
16327  const char* boundary_program =
16328      "var res = 0;"
16329      "for (var i = 0; i < 16; i++) {"
16330      "  ext_array[i] = %lld;"
16331      "  if (i > 8) {"
16332      "    res = ext_array[i];"
16333      "  }"
16334      "}"
16335      "res;";
16336  i::SNPrintF(test_buf,
16337              boundary_program,
16338              low);
16339  result = CompileRun(test_buf.start());
16340  CHECK_EQ(low, result->IntegerValue());
16341
16342  i::SNPrintF(test_buf,
16343              boundary_program,
16344              high);
16345  result = CompileRun(test_buf.start());
16346  CHECK_EQ(high, result->IntegerValue());
16347
16348  // Check misprediction of type in IC.
16349  result = CompileRun("var tmp_array = ext_array;"
16350                      "var sum = 0;"
16351                      "for (var i = 0; i < 8; i++) {"
16352                      "  tmp_array[i] = i;"
16353                      "  sum += tmp_array[i];"
16354                      "  if (i == 4) {"
16355                      "    tmp_array = {};"
16356                      "  }"
16357                      "}"
16358                      "sum;");
16359  // Force GC to trigger verification.
16360  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16361  CHECK_EQ(28, result->Int32Value());
16362
16363  // Make sure out-of-range loads do not throw.
16364  i::SNPrintF(test_buf,
16365              "var caught_exception = false;"
16366              "try {"
16367              "  ext_array[%d];"
16368              "} catch (e) {"
16369              "  caught_exception = true;"
16370              "}"
16371              "caught_exception;",
16372              element_count);
16373  result = CompileRun(test_buf.start());
16374  CHECK_EQ(false, result->BooleanValue());
16375
16376  // Make sure out-of-range stores do not throw.
16377  i::SNPrintF(test_buf,
16378              "var caught_exception = false;"
16379              "try {"
16380              "  ext_array[%d] = 1;"
16381              "} catch (e) {"
16382              "  caught_exception = true;"
16383              "}"
16384              "caught_exception;",
16385              element_count);
16386  result = CompileRun(test_buf.start());
16387  CHECK_EQ(false, result->BooleanValue());
16388
16389  // Check other boundary conditions, values and operations.
16390  result = CompileRun("for (var i = 0; i < 8; i++) {"
16391                      "  ext_array[7] = undefined;"
16392                      "}"
16393                      "ext_array[7];");
16394  CHECK_EQ(0, result->Int32Value());
16395  if (array_type == v8::kExternalFloat64Array ||
16396      array_type == v8::kExternalFloat32Array) {
16397    CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()),
16398             static_cast<int>(
16399                 i::Object::GetElement(
16400                     isolate, jsobj, 7).ToHandleChecked()->Number()));
16401  } else {
16402    CheckElementValue(isolate, 0, jsobj, 7);
16403  }
16404
16405  result = CompileRun("for (var i = 0; i < 8; i++) {"
16406                      "  ext_array[6] = '2.3';"
16407                      "}"
16408                      "ext_array[6];");
16409  CHECK_EQ(2, result->Int32Value());
16410  CHECK_EQ(2,
16411           static_cast<int>(
16412               i::Object::GetElement(
16413                   isolate, jsobj, 6).ToHandleChecked()->Number()));
16414
16415  if (array_type != v8::kExternalFloat32Array &&
16416      array_type != v8::kExternalFloat64Array) {
16417    // Though the specification doesn't state it, be explicit about
16418    // converting NaNs and +/-Infinity to zero.
16419    result = CompileRun("for (var i = 0; i < 8; i++) {"
16420                        "  ext_array[i] = 5;"
16421                        "}"
16422                        "for (var i = 0; i < 8; i++) {"
16423                        "  ext_array[i] = NaN;"
16424                        "}"
16425                        "ext_array[5];");
16426    CHECK_EQ(0, result->Int32Value());
16427    CheckElementValue(isolate, 0, jsobj, 5);
16428
16429    result = CompileRun("for (var i = 0; i < 8; i++) {"
16430                        "  ext_array[i] = 5;"
16431                        "}"
16432                        "for (var i = 0; i < 8; i++) {"
16433                        "  ext_array[i] = Infinity;"
16434                        "}"
16435                        "ext_array[5];");
16436    int expected_value =
16437        (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16438    CHECK_EQ(expected_value, result->Int32Value());
16439    CheckElementValue(isolate, expected_value, jsobj, 5);
16440
16441    result = CompileRun("for (var i = 0; i < 8; i++) {"
16442                        "  ext_array[i] = 5;"
16443                        "}"
16444                        "for (var i = 0; i < 8; i++) {"
16445                        "  ext_array[i] = -Infinity;"
16446                        "}"
16447                        "ext_array[5];");
16448    CHECK_EQ(0, result->Int32Value());
16449    CheckElementValue(isolate, 0, jsobj, 5);
16450
16451    // Check truncation behavior of integral arrays.
16452    const char* unsigned_data =
16453        "var source_data = [0.6, 10.6];"
16454        "var expected_results = [0, 10];";
16455    const char* signed_data =
16456        "var source_data = [0.6, 10.6, -0.6, -10.6];"
16457        "var expected_results = [0, 10, 0, -10];";
16458    const char* pixel_data =
16459        "var source_data = [0.6, 10.6];"
16460        "var expected_results = [1, 11];";
16461    bool is_unsigned =
16462        (array_type == v8::kExternalUint8Array ||
16463         array_type == v8::kExternalUint16Array ||
16464         array_type == v8::kExternalUint32Array);
16465    bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16466
16467    i::SNPrintF(test_buf,
16468                "%s"
16469                "var all_passed = true;"
16470                "for (var i = 0; i < source_data.length; i++) {"
16471                "  for (var j = 0; j < 8; j++) {"
16472                "    ext_array[j] = source_data[i];"
16473                "  }"
16474                "  all_passed = all_passed &&"
16475                "               (ext_array[5] == expected_results[i]);"
16476                "}"
16477                "all_passed;",
16478                (is_unsigned ?
16479                     unsigned_data :
16480                     (is_pixel_data ? pixel_data : signed_data)));
16481    result = CompileRun(test_buf.start());
16482    CHECK_EQ(true, result->BooleanValue());
16483  }
16484
16485  i::Handle<ExternalArrayClass> array(
16486      ExternalArrayClass::cast(jsobj->elements()));
16487  for (int i = 0; i < element_count; i++) {
16488    array->set(i, static_cast<ElementType>(i));
16489  }
16490
16491  // Test complex assignments
16492  result = CompileRun("function ee_op_test_complex_func(sum) {"
16493                      " for (var i = 0; i < 40; ++i) {"
16494                      "   sum += (ext_array[i] += 1);"
16495                      "   sum += (ext_array[i] -= 1);"
16496                      " } "
16497                      " return sum;"
16498                      "}"
16499                      "sum=0;"
16500                      "for (var i=0;i<10000;++i) {"
16501                      "  sum=ee_op_test_complex_func(sum);"
16502                      "}"
16503                      "sum;");
16504  CHECK_EQ(16000000, result->Int32Value());
16505
16506  // Test count operations
16507  result = CompileRun("function ee_op_test_count_func(sum) {"
16508                      " for (var i = 0; i < 40; ++i) {"
16509                      "   sum += (++ext_array[i]);"
16510                      "   sum += (--ext_array[i]);"
16511                      " } "
16512                      " return sum;"
16513                      "}"
16514                      "sum=0;"
16515                      "for (var i=0;i<10000;++i) {"
16516                      "  sum=ee_op_test_count_func(sum);"
16517                      "}"
16518                      "sum;");
16519  CHECK_EQ(16000000, result->Int32Value());
16520
16521  result = CompileRun("ext_array[3] = 33;"
16522                      "delete ext_array[3];"
16523                      "ext_array[3];");
16524  CHECK_EQ(33, result->Int32Value());
16525
16526  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16527                      "ext_array[2] = 12; ext_array[3] = 13;"
16528                      "ext_array.__defineGetter__('2',"
16529                      "function() { return 120; });"
16530                      "ext_array[2];");
16531  CHECK_EQ(12, result->Int32Value());
16532
16533  result = CompileRun("var js_array = new Array(40);"
16534                      "js_array[0] = 77;"
16535                      "js_array;");
16536  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16537
16538  result = CompileRun("ext_array[1] = 23;"
16539                      "ext_array.__proto__ = [];"
16540                      "js_array.__proto__ = ext_array;"
16541                      "js_array.concat(ext_array);");
16542  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16543  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16544
16545  result = CompileRun("ext_array[1] = 23;");
16546  CHECK_EQ(23, result->Int32Value());
16547}
16548
16549
16550template <class FixedTypedArrayClass,
16551          i::ElementsKind elements_kind,
16552          class ElementType>
16553static void FixedTypedArrayTestHelper(
16554    v8::ExternalArrayType array_type,
16555    ElementType low,
16556    ElementType high) {
16557  i::FLAG_allow_natives_syntax = true;
16558  LocalContext context;
16559  i::Isolate* isolate = CcTest::i_isolate();
16560  i::Factory* factory = isolate->factory();
16561  v8::HandleScope scope(context->GetIsolate());
16562  const int kElementCount = 260;
16563  i::Handle<FixedTypedArrayClass> fixed_array =
16564    i::Handle<FixedTypedArrayClass>::cast(
16565        factory->NewFixedTypedArray(kElementCount, array_type));
16566  CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16567           fixed_array->map()->instance_type());
16568  CHECK_EQ(kElementCount, fixed_array->length());
16569  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16570  for (int i = 0; i < kElementCount; i++) {
16571    fixed_array->set(i, static_cast<ElementType>(i));
16572  }
16573  // Force GC to trigger verification.
16574  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16575  for (int i = 0; i < kElementCount; i++) {
16576    CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16577             static_cast<int64_t>(fixed_array->get_scalar(i)));
16578  }
16579  v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16580  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16581  i::Handle<i::Map> fixed_array_map =
16582      i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16583  jsobj->set_map(*fixed_array_map);
16584  jsobj->set_elements(*fixed_array);
16585
16586  ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16587      context.local(), obj, kElementCount, array_type,
16588      static_cast<int64_t>(low),
16589      static_cast<int64_t>(high));
16590}
16591
16592
16593THREADED_TEST(FixedUint8Array) {
16594  FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16595    v8::kExternalUint8Array,
16596    0x0, 0xFF);
16597}
16598
16599
16600THREADED_TEST(FixedUint8ClampedArray) {
16601  FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16602                            i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16603    v8::kExternalUint8ClampedArray,
16604    0x0, 0xFF);
16605}
16606
16607
16608THREADED_TEST(FixedInt8Array) {
16609  FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16610    v8::kExternalInt8Array,
16611    -0x80, 0x7F);
16612}
16613
16614
16615THREADED_TEST(FixedUint16Array) {
16616  FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16617    v8::kExternalUint16Array,
16618    0x0, 0xFFFF);
16619}
16620
16621
16622THREADED_TEST(FixedInt16Array) {
16623  FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16624    v8::kExternalInt16Array,
16625    -0x8000, 0x7FFF);
16626}
16627
16628
16629THREADED_TEST(FixedUint32Array) {
16630  FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16631    v8::kExternalUint32Array,
16632    0x0, UINT_MAX);
16633}
16634
16635
16636THREADED_TEST(FixedInt32Array) {
16637  FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16638    v8::kExternalInt32Array,
16639    INT_MIN, INT_MAX);
16640}
16641
16642
16643THREADED_TEST(FixedFloat32Array) {
16644  FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16645    v8::kExternalFloat32Array,
16646    -500, 500);
16647}
16648
16649
16650THREADED_TEST(FixedFloat64Array) {
16651  FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16652    v8::kExternalFloat64Array,
16653    -500, 500);
16654}
16655
16656
16657template <class ExternalArrayClass, class ElementType>
16658static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16659                                    int64_t low,
16660                                    int64_t high) {
16661  LocalContext context;
16662  i::Isolate* isolate = CcTest::i_isolate();
16663  i::Factory* factory = isolate->factory();
16664  v8::HandleScope scope(context->GetIsolate());
16665  const int kElementCount = 40;
16666  int element_size = ExternalArrayElementSize(array_type);
16667  ElementType* array_data =
16668      static_cast<ElementType*>(malloc(kElementCount * element_size));
16669  i::Handle<ExternalArrayClass> array =
16670      i::Handle<ExternalArrayClass>::cast(
16671          factory->NewExternalArray(kElementCount, array_type, array_data));
16672  // Force GC to trigger verification.
16673  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16674  for (int i = 0; i < kElementCount; i++) {
16675    array->set(i, static_cast<ElementType>(i));
16676  }
16677  // Force GC to trigger verification.
16678  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16679  for (int i = 0; i < kElementCount; i++) {
16680    CHECK_EQ(static_cast<int64_t>(i),
16681             static_cast<int64_t>(array->get_scalar(i)));
16682    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16683  }
16684
16685  v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16686  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16687  // Set the elements to be the external array.
16688  obj->SetIndexedPropertiesToExternalArrayData(array_data,
16689                                               array_type,
16690                                               kElementCount);
16691  CHECK_EQ(1,
16692           static_cast<int>(
16693               i::Object::GetElement(
16694                   isolate, jsobj, 1).ToHandleChecked()->Number()));
16695
16696  ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16697      context.local(), obj, kElementCount, array_type, low, high);
16698
16699  v8::Handle<v8::Value> result;
16700
16701  // Test more complex manipulations which cause eax to contain values
16702  // that won't be completely overwritten by loads from the arrays.
16703  // This catches bugs in the instructions used for the KeyedLoadIC
16704  // for byte and word types.
16705  {
16706    const int kXSize = 300;
16707    const int kYSize = 300;
16708    const int kLargeElementCount = kXSize * kYSize * 4;
16709    ElementType* large_array_data =
16710        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16711    v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16712    // Set the elements to be the external array.
16713    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16714                                                       array_type,
16715                                                       kLargeElementCount);
16716    context->Global()->Set(v8_str("large_array"), large_obj);
16717    // Initialize contents of a few rows.
16718    for (int x = 0; x < 300; x++) {
16719      int row = 0;
16720      int offset = row * 300 * 4;
16721      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16722      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16723      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16724      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16725      row = 150;
16726      offset = row * 300 * 4;
16727      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16728      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16729      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16730      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16731      row = 298;
16732      offset = row * 300 * 4;
16733      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16734      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16735      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16736      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16737    }
16738    // The goal of the code below is to make "offset" large enough
16739    // that the computation of the index (which goes into eax) has
16740    // high bits set which will not be overwritten by a byte or short
16741    // load.
16742    result = CompileRun("var failed = false;"
16743                        "var offset = 0;"
16744                        "for (var i = 0; i < 300; i++) {"
16745                        "  if (large_array[4 * i] != 127 ||"
16746                        "      large_array[4 * i + 1] != 0 ||"
16747                        "      large_array[4 * i + 2] != 0 ||"
16748                        "      large_array[4 * i + 3] != 127) {"
16749                        "    failed = true;"
16750                        "  }"
16751                        "}"
16752                        "offset = 150 * 300 * 4;"
16753                        "for (var i = 0; i < 300; i++) {"
16754                        "  if (large_array[offset + 4 * i] != 127 ||"
16755                        "      large_array[offset + 4 * i + 1] != 0 ||"
16756                        "      large_array[offset + 4 * i + 2] != 0 ||"
16757                        "      large_array[offset + 4 * i + 3] != 127) {"
16758                        "    failed = true;"
16759                        "  }"
16760                        "}"
16761                        "offset = 298 * 300 * 4;"
16762                        "for (var i = 0; i < 300; i++) {"
16763                        "  if (large_array[offset + 4 * i] != 127 ||"
16764                        "      large_array[offset + 4 * i + 1] != 0 ||"
16765                        "      large_array[offset + 4 * i + 2] != 0 ||"
16766                        "      large_array[offset + 4 * i + 3] != 127) {"
16767                        "    failed = true;"
16768                        "  }"
16769                        "}"
16770                        "!failed;");
16771    CHECK_EQ(true, result->BooleanValue());
16772    free(large_array_data);
16773  }
16774
16775  // The "" property descriptor is overloaded to store information about
16776  // the external array. Ensure that setting and accessing the "" property
16777  // works (it should overwrite the information cached about the external
16778  // array in the DescriptorArray) in various situations.
16779  result = CompileRun("ext_array[''] = 23; ext_array['']");
16780  CHECK_EQ(23, result->Int32Value());
16781
16782  // Property "" set after the external array is associated with the object.
16783  {
16784    v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16785    obj2->Set(v8_str("ee_test_field"),
16786              v8::Int32::New(context->GetIsolate(), 256));
16787    obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16788    // Set the elements to be the external array.
16789    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16790                                                  array_type,
16791                                                  kElementCount);
16792    context->Global()->Set(v8_str("ext_array"), obj2);
16793    result = CompileRun("ext_array['']");
16794    CHECK_EQ(1503, result->Int32Value());
16795  }
16796
16797  // Property "" set after the external array is associated with the object.
16798  {
16799    v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16800    obj2->Set(v8_str("ee_test_field_2"),
16801              v8::Int32::New(context->GetIsolate(), 256));
16802    // Set the elements to be the external array.
16803    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16804                                                  array_type,
16805                                                  kElementCount);
16806    obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16807    context->Global()->Set(v8_str("ext_array"), obj2);
16808    result = CompileRun("ext_array['']");
16809    CHECK_EQ(1503, result->Int32Value());
16810  }
16811
16812  // Should reuse the map from previous test.
16813  {
16814    v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16815    obj2->Set(v8_str("ee_test_field_2"),
16816              v8::Int32::New(context->GetIsolate(), 256));
16817    // Set the elements to be the external array. Should re-use the map
16818    // from previous test.
16819    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16820                                                  array_type,
16821                                                  kElementCount);
16822    context->Global()->Set(v8_str("ext_array"), obj2);
16823    result = CompileRun("ext_array['']");
16824  }
16825
16826  // Property "" is a constant function that shouldn't not be interfered with
16827  // when an external array is set.
16828  {
16829    v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16830    // Start
16831    obj2->Set(v8_str("ee_test_field3"),
16832              v8::Int32::New(context->GetIsolate(), 256));
16833
16834    // Add a constant function to an object.
16835    context->Global()->Set(v8_str("ext_array"), obj2);
16836    result = CompileRun("ext_array[''] = function() {return 1503;};"
16837                        "ext_array['']();");
16838
16839    // Add an external array transition to the same map that
16840    // has the constant transition.
16841    v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16842    obj3->Set(v8_str("ee_test_field3"),
16843              v8::Int32::New(context->GetIsolate(), 256));
16844    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16845                                                  array_type,
16846                                                  kElementCount);
16847    context->Global()->Set(v8_str("ext_array"), obj3);
16848  }
16849
16850  // If a external array transition is in the map, it should get clobbered
16851  // by a constant function.
16852  {
16853    // Add an external array transition.
16854    v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16855    obj3->Set(v8_str("ee_test_field4"),
16856              v8::Int32::New(context->GetIsolate(), 256));
16857    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16858                                                  array_type,
16859                                                  kElementCount);
16860
16861    // Add a constant function to the same map that just got an external array
16862    // transition.
16863    v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16864    obj2->Set(v8_str("ee_test_field4"),
16865              v8::Int32::New(context->GetIsolate(), 256));
16866    context->Global()->Set(v8_str("ext_array"), obj2);
16867    result = CompileRun("ext_array[''] = function() {return 1503;};"
16868                        "ext_array['']();");
16869  }
16870
16871  free(array_data);
16872}
16873
16874
16875THREADED_TEST(ExternalInt8Array) {
16876  ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16877      v8::kExternalInt8Array,
16878      -128,
16879      127);
16880}
16881
16882
16883THREADED_TEST(ExternalUint8Array) {
16884  ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16885      v8::kExternalUint8Array,
16886      0,
16887      255);
16888}
16889
16890
16891THREADED_TEST(ExternalUint8ClampedArray) {
16892  ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16893      v8::kExternalUint8ClampedArray,
16894      0,
16895      255);
16896}
16897
16898
16899THREADED_TEST(ExternalInt16Array) {
16900  ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16901      v8::kExternalInt16Array,
16902      -32768,
16903      32767);
16904}
16905
16906
16907THREADED_TEST(ExternalUint16Array) {
16908  ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16909      v8::kExternalUint16Array,
16910      0,
16911      65535);
16912}
16913
16914
16915THREADED_TEST(ExternalInt32Array) {
16916  ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16917      v8::kExternalInt32Array,
16918      INT_MIN,   // -2147483648
16919      INT_MAX);  //  2147483647
16920}
16921
16922
16923THREADED_TEST(ExternalUint32Array) {
16924  ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16925      v8::kExternalUint32Array,
16926      0,
16927      UINT_MAX);  // 4294967295
16928}
16929
16930
16931THREADED_TEST(ExternalFloat32Array) {
16932  ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16933      v8::kExternalFloat32Array,
16934      -500,
16935      500);
16936}
16937
16938
16939THREADED_TEST(ExternalFloat64Array) {
16940  ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16941      v8::kExternalFloat64Array,
16942      -500,
16943      500);
16944}
16945
16946
16947THREADED_TEST(ExternalArrays) {
16948  TestExternalInt8Array();
16949  TestExternalUint8Array();
16950  TestExternalInt16Array();
16951  TestExternalUint16Array();
16952  TestExternalInt32Array();
16953  TestExternalUint32Array();
16954  TestExternalFloat32Array();
16955}
16956
16957
16958void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16959  LocalContext context;
16960  v8::HandleScope scope(context->GetIsolate());
16961  for (int size = 0; size < 100; size += 10) {
16962    int element_size = ExternalArrayElementSize(array_type);
16963    void* external_data = malloc(size * element_size);
16964    v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16965    obj->SetIndexedPropertiesToExternalArrayData(
16966        external_data, array_type, size);
16967    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16968    CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16969    CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16970    CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16971    free(external_data);
16972  }
16973}
16974
16975
16976THREADED_TEST(ExternalArrayInfo) {
16977  ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16978  ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16979  ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16980  ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16981  ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16982  ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16983  ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16984  ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16985  ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16986}
16987
16988
16989void ExtArrayLimitsHelper(v8::Isolate* isolate,
16990                          v8::ExternalArrayType array_type,
16991                          int size) {
16992  v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16993  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16994  last_location = last_message = NULL;
16995  obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16996  CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16997  CHECK_NE(NULL, last_location);
16998  CHECK_NE(NULL, last_message);
16999}
17000
17001
17002TEST(ExternalArrayLimits) {
17003  LocalContext context;
17004  v8::Isolate* isolate = context->GetIsolate();
17005  v8::HandleScope scope(isolate);
17006  ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
17007  ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
17008  ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
17009  ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
17010  ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
17011  ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
17012  ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
17013  ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
17014  ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
17015  ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
17016  ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
17017  ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
17018  ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
17019  ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
17020  ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
17021  ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
17022  ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
17023  ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
17024}
17025
17026
17027template <typename ElementType, typename TypedArray,
17028          class ExternalArrayClass>
17029void TypedArrayTestHelper(v8::ExternalArrayType array_type,
17030                          int64_t low, int64_t high) {
17031  const int kElementCount = 50;
17032
17033  i::ScopedVector<ElementType> backing_store(kElementCount+2);
17034
17035  LocalContext env;
17036  v8::Isolate* isolate = env->GetIsolate();
17037  v8::HandleScope handle_scope(isolate);
17038
17039  Local<v8::ArrayBuffer> ab =
17040      v8::ArrayBuffer::New(isolate, backing_store.start(),
17041                           (kElementCount + 2) * sizeof(ElementType));
17042  Local<TypedArray> ta =
17043      TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17044  CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17045  CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17046  CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17047  CHECK_EQ(kElementCount*sizeof(ElementType),
17048           static_cast<int>(ta->ByteLength()));
17049  CHECK_EQ(ab, ta->Buffer());
17050
17051  ElementType* data = backing_store.start() + 2;
17052  for (int i = 0; i < kElementCount; i++) {
17053    data[i] = static_cast<ElementType>(i);
17054  }
17055
17056  ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17057      env.local(), ta, kElementCount, array_type, low, high);
17058}
17059
17060
17061THREADED_TEST(Uint8Array) {
17062  TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17063      v8::kExternalUint8Array, 0, 0xFF);
17064}
17065
17066
17067THREADED_TEST(Int8Array) {
17068  TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17069      v8::kExternalInt8Array, -0x80, 0x7F);
17070}
17071
17072
17073THREADED_TEST(Uint16Array) {
17074  TypedArrayTestHelper<uint16_t,
17075                       v8::Uint16Array,
17076                       i::ExternalUint16Array>(
17077      v8::kExternalUint16Array, 0, 0xFFFF);
17078}
17079
17080
17081THREADED_TEST(Int16Array) {
17082  TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17083      v8::kExternalInt16Array, -0x8000, 0x7FFF);
17084}
17085
17086
17087THREADED_TEST(Uint32Array) {
17088  TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17089      v8::kExternalUint32Array, 0, UINT_MAX);
17090}
17091
17092
17093THREADED_TEST(Int32Array) {
17094  TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17095      v8::kExternalInt32Array, INT_MIN, INT_MAX);
17096}
17097
17098
17099THREADED_TEST(Float32Array) {
17100  TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17101      v8::kExternalFloat32Array, -500, 500);
17102}
17103
17104
17105THREADED_TEST(Float64Array) {
17106  TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17107      v8::kExternalFloat64Array, -500, 500);
17108}
17109
17110
17111THREADED_TEST(Uint8ClampedArray) {
17112  TypedArrayTestHelper<uint8_t,
17113                       v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17114      v8::kExternalUint8ClampedArray, 0, 0xFF);
17115}
17116
17117
17118THREADED_TEST(DataView) {
17119  const int kSize = 50;
17120
17121  i::ScopedVector<uint8_t> backing_store(kSize+2);
17122
17123  LocalContext env;
17124  v8::Isolate* isolate = env->GetIsolate();
17125  v8::HandleScope handle_scope(isolate);
17126
17127  Local<v8::ArrayBuffer> ab =
17128      v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17129  Local<v8::DataView> dv =
17130      v8::DataView::New(ab, 2, kSize);
17131  CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17132  CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17133  CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17134  CHECK_EQ(ab, dv->Buffer());
17135}
17136
17137
17138#define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
17139  THREADED_TEST(Is##View) {                                                   \
17140    LocalContext env;                                                         \
17141    v8::Isolate* isolate = env->GetIsolate();                                 \
17142    v8::HandleScope handle_scope(isolate);                                    \
17143                                                                              \
17144    Handle<Value> result = CompileRun(                                        \
17145        "var ab = new ArrayBuffer(128);"                                      \
17146        "new " #View "(ab)");                                                 \
17147    CHECK(result->IsArrayBufferView());                                       \
17148    CHECK(result->Is##View());                                                \
17149    CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
17150  }
17151
17152IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17153IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17154IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17155IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17156IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17157IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17158IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17159IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17160IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17161IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17162
17163#undef IS_ARRAY_BUFFER_VIEW_TEST
17164
17165
17166
17167THREADED_TEST(ScriptContextDependence) {
17168  LocalContext c1;
17169  v8::HandleScope scope(c1->GetIsolate());
17170  const char *source = "foo";
17171  v8::Handle<v8::Script> dep = v8_compile(source);
17172  v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17173      c1->GetIsolate(), source));
17174  v8::Handle<v8::UnboundScript> indep =
17175      v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17176  c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17177                    v8::Integer::New(c1->GetIsolate(), 100));
17178  CHECK_EQ(dep->Run()->Int32Value(), 100);
17179  CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17180  LocalContext c2;
17181  c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17182                    v8::Integer::New(c2->GetIsolate(), 101));
17183  CHECK_EQ(dep->Run()->Int32Value(), 100);
17184  CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17185}
17186
17187
17188THREADED_TEST(StackTrace) {
17189  LocalContext context;
17190  v8::HandleScope scope(context->GetIsolate());
17191  v8::TryCatch try_catch;
17192  const char *source = "function foo() { FAIL.FAIL; }; foo();";
17193  v8::Handle<v8::String> src =
17194      v8::String::NewFromUtf8(context->GetIsolate(), source);
17195  v8::Handle<v8::String> origin =
17196      v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17197  v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17198  v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17199      ->BindToCurrentContext()
17200      ->Run();
17201  CHECK(try_catch.HasCaught());
17202  v8::String::Utf8Value stack(try_catch.StackTrace());
17203  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17204}
17205
17206
17207// Checks that a StackFrame has certain expected values.
17208void checkStackFrame(const char* expected_script_name,
17209    const char* expected_func_name, int expected_line_number,
17210    int expected_column, bool is_eval, bool is_constructor,
17211    v8::Handle<v8::StackFrame> frame) {
17212  v8::HandleScope scope(CcTest::isolate());
17213  v8::String::Utf8Value func_name(frame->GetFunctionName());
17214  v8::String::Utf8Value script_name(frame->GetScriptName());
17215  if (*script_name == NULL) {
17216    // The situation where there is no associated script, like for evals.
17217    CHECK(expected_script_name == NULL);
17218  } else {
17219    CHECK(strstr(*script_name, expected_script_name) != NULL);
17220  }
17221  CHECK(strstr(*func_name, expected_func_name) != NULL);
17222  CHECK_EQ(expected_line_number, frame->GetLineNumber());
17223  CHECK_EQ(expected_column, frame->GetColumn());
17224  CHECK_EQ(is_eval, frame->IsEval());
17225  CHECK_EQ(is_constructor, frame->IsConstructor());
17226}
17227
17228
17229void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17230  v8::HandleScope scope(args.GetIsolate());
17231  const char* origin = "capture-stack-trace-test";
17232  const int kOverviewTest = 1;
17233  const int kDetailedTest = 2;
17234
17235  DCHECK(args.Length() == 1);
17236
17237  int testGroup = args[0]->Int32Value();
17238  if (testGroup == kOverviewTest) {
17239    v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17240        args.GetIsolate(), 10, v8::StackTrace::kOverview);
17241    CHECK_EQ(4, stackTrace->GetFrameCount());
17242    checkStackFrame(origin, "bar", 2, 10, false, false,
17243                    stackTrace->GetFrame(0));
17244    checkStackFrame(origin, "foo", 6, 3, false, false,
17245                    stackTrace->GetFrame(1));
17246    // This is the source string inside the eval which has the call to foo.
17247    checkStackFrame(NULL, "", 1, 5, false, false,
17248                    stackTrace->GetFrame(2));
17249    // The last frame is an anonymous function which has the initial eval call.
17250    checkStackFrame(origin, "", 8, 7, false, false,
17251                    stackTrace->GetFrame(3));
17252
17253    CHECK(stackTrace->AsArray()->IsArray());
17254  } else if (testGroup == kDetailedTest) {
17255    v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17256        args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17257    CHECK_EQ(4, stackTrace->GetFrameCount());
17258    checkStackFrame(origin, "bat", 4, 22, false, false,
17259                    stackTrace->GetFrame(0));
17260    checkStackFrame(origin, "baz", 8, 3, false, true,
17261                    stackTrace->GetFrame(1));
17262    bool is_eval = true;
17263    // This is the source string inside the eval which has the call to baz.
17264    checkStackFrame(NULL, "", 1, 5, is_eval, false,
17265                    stackTrace->GetFrame(2));
17266    // The last frame is an anonymous function which has the initial eval call.
17267    checkStackFrame(origin, "", 10, 1, false, false,
17268                    stackTrace->GetFrame(3));
17269
17270    CHECK(stackTrace->AsArray()->IsArray());
17271  }
17272}
17273
17274
17275// Tests the C++ StackTrace API.
17276// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17277// THREADED_TEST(CaptureStackTrace) {
17278TEST(CaptureStackTrace) {
17279  v8::Isolate* isolate = CcTest::isolate();
17280  v8::HandleScope scope(isolate);
17281  v8::Handle<v8::String> origin =
17282      v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17283  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17284  templ->Set(v8_str("AnalyzeStackInNativeCode"),
17285             v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17286  LocalContext context(0, templ);
17287
17288  // Test getting OVERVIEW information. Should ignore information that is not
17289  // script name, function name, line number, and column offset.
17290  const char *overview_source =
17291    "function bar() {\n"
17292    "  var y; AnalyzeStackInNativeCode(1);\n"
17293    "}\n"
17294    "function foo() {\n"
17295    "\n"
17296    "  bar();\n"
17297    "}\n"
17298    "var x;eval('new foo();');";
17299  v8::Handle<v8::String> overview_src =
17300      v8::String::NewFromUtf8(isolate, overview_source);
17301  v8::ScriptCompiler::Source script_source(overview_src,
17302                                           v8::ScriptOrigin(origin));
17303  v8::Handle<Value> overview_result(
17304      v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17305          ->BindToCurrentContext()
17306          ->Run());
17307  CHECK(!overview_result.IsEmpty());
17308  CHECK(overview_result->IsObject());
17309
17310  // Test getting DETAILED information.
17311  const char *detailed_source =
17312    "function bat() {AnalyzeStackInNativeCode(2);\n"
17313    "}\n"
17314    "\n"
17315    "function baz() {\n"
17316    "  bat();\n"
17317    "}\n"
17318    "eval('new baz();');";
17319  v8::Handle<v8::String> detailed_src =
17320      v8::String::NewFromUtf8(isolate, detailed_source);
17321  // Make the script using a non-zero line and column offset.
17322  v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17323  v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17324  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17325  v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17326  v8::Handle<v8::UnboundScript> detailed_script(
17327      v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17328  v8::Handle<Value> detailed_result(
17329      detailed_script->BindToCurrentContext()->Run());
17330  CHECK(!detailed_result.IsEmpty());
17331  CHECK(detailed_result->IsObject());
17332}
17333
17334
17335static void StackTraceForUncaughtExceptionListener(
17336    v8::Handle<v8::Message> message,
17337    v8::Handle<Value>) {
17338  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17339  CHECK_EQ(2, stack_trace->GetFrameCount());
17340  checkStackFrame("origin", "foo", 2, 3, false, false,
17341                  stack_trace->GetFrame(0));
17342  checkStackFrame("origin", "bar", 5, 3, false, false,
17343                  stack_trace->GetFrame(1));
17344}
17345
17346
17347TEST(CaptureStackTraceForUncaughtException) {
17348  report_count = 0;
17349  LocalContext env;
17350  v8::HandleScope scope(env->GetIsolate());
17351  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17352  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17353
17354  CompileRunWithOrigin(
17355      "function foo() {\n"
17356      "  throw 1;\n"
17357      "};\n"
17358      "function bar() {\n"
17359      "  foo();\n"
17360      "};",
17361      "origin");
17362  v8::Local<v8::Object> global = env->Global();
17363  Local<Value> trouble = global->Get(v8_str("bar"));
17364  CHECK(trouble->IsFunction());
17365  Function::Cast(*trouble)->Call(global, 0, NULL);
17366  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17367  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17368}
17369
17370
17371TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17372  LocalContext env;
17373  v8::HandleScope scope(env->GetIsolate());
17374  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17375                                                    1024,
17376                                                    v8::StackTrace::kDetailed);
17377
17378  CompileRun(
17379      "var setters = ['column', 'lineNumber', 'scriptName',\n"
17380      "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17381      "    'isConstructor'];\n"
17382      "for (var i = 0; i < setters.length; i++) {\n"
17383      "  var prop = setters[i];\n"
17384      "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17385      "}\n");
17386  CompileRun("throw 'exception';");
17387  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17388}
17389
17390
17391static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17392                                     v8::Handle<v8::Value> data) {
17393  // Use the frame where JavaScript is called from.
17394  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17395  CHECK(!stack_trace.IsEmpty());
17396  int frame_count = stack_trace->GetFrameCount();
17397  CHECK_EQ(3, frame_count);
17398  int line_number[] = {1, 2, 5};
17399  for (int i = 0; i < frame_count; i++) {
17400    CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17401  }
17402}
17403
17404
17405// Test that we only return the stack trace at the site where the exception
17406// is first thrown (not where it is rethrown).
17407TEST(RethrowStackTrace) {
17408  LocalContext env;
17409  v8::HandleScope scope(env->GetIsolate());
17410  // We make sure that
17411  // - the stack trace of the ReferenceError in g() is reported.
17412  // - the stack trace is not overwritten when e1 is rethrown by t().
17413  // - the stack trace of e2 does not overwrite that of e1.
17414  const char* source =
17415      "function g() { error; }          \n"
17416      "function f() { g(); }            \n"
17417      "function t(e) { throw e; }       \n"
17418      "try {                            \n"
17419      "  f();                           \n"
17420      "} catch (e1) {                   \n"
17421      "  try {                          \n"
17422      "    error;                       \n"
17423      "  } catch (e2) {                 \n"
17424      "    t(e1);                       \n"
17425      "  }                              \n"
17426      "}                                \n";
17427  v8::V8::AddMessageListener(RethrowStackTraceHandler);
17428  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17429  CompileRun(source);
17430  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17431  v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17432}
17433
17434
17435static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17436                                              v8::Handle<v8::Value> data) {
17437  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17438  CHECK(!stack_trace.IsEmpty());
17439  int frame_count = stack_trace->GetFrameCount();
17440  CHECK_EQ(2, frame_count);
17441  int line_number[] = {3, 7};
17442  for (int i = 0; i < frame_count; i++) {
17443    CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17444  }
17445}
17446
17447
17448// Test that we do not recognize identity for primitive exceptions.
17449TEST(RethrowPrimitiveStackTrace) {
17450  LocalContext env;
17451  v8::HandleScope scope(env->GetIsolate());
17452  // We do not capture stack trace for non Error objects on creation time.
17453  // Instead, we capture the stack trace on last throw.
17454  const char* source =
17455      "function g() { throw 404; }      \n"
17456      "function f() { g(); }            \n"
17457      "function t(e) { throw e; }       \n"
17458      "try {                            \n"
17459      "  f();                           \n"
17460      "} catch (e1) {                   \n"
17461      "  t(e1)                          \n"
17462      "}                                \n";
17463  v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17464  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17465  CompileRun(source);
17466  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17467  v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17468}
17469
17470
17471static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17472                                              v8::Handle<v8::Value> data) {
17473  // Use the frame where JavaScript is called from.
17474  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17475  CHECK(!stack_trace.IsEmpty());
17476  CHECK_EQ(1, stack_trace->GetFrameCount());
17477  CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17478}
17479
17480
17481// Test that the stack trace is captured when the error object is created and
17482// not where it is thrown.
17483TEST(RethrowExistingStackTrace) {
17484  LocalContext env;
17485  v8::HandleScope scope(env->GetIsolate());
17486  const char* source =
17487      "var e = new Error();           \n"
17488      "throw e;                       \n";
17489  v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17490  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17491  CompileRun(source);
17492  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17493  v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17494}
17495
17496
17497static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17498                                               v8::Handle<v8::Value> data) {
17499  // Use the frame where JavaScript is called from.
17500  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17501  CHECK(!stack_trace.IsEmpty());
17502  CHECK_EQ(1, stack_trace->GetFrameCount());
17503  CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17504}
17505
17506
17507// Test that the stack trace is captured where the bogus Error object is thrown.
17508TEST(RethrowBogusErrorStackTrace) {
17509  LocalContext env;
17510  v8::HandleScope scope(env->GetIsolate());
17511  const char* source =
17512      "var e = {__proto__: new Error()} \n"
17513      "throw e;                         \n";
17514  v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17515  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17516  CompileRun(source);
17517  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17518  v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17519}
17520
17521
17522void AnalyzeStackOfEvalWithSourceURL(
17523    const v8::FunctionCallbackInfo<v8::Value>& args) {
17524  v8::HandleScope scope(args.GetIsolate());
17525  v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17526      args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17527  CHECK_EQ(5, stackTrace->GetFrameCount());
17528  v8::Handle<v8::String> url = v8_str("eval_url");
17529  for (int i = 0; i < 3; i++) {
17530    v8::Handle<v8::String> name =
17531        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17532    CHECK(!name.IsEmpty());
17533    CHECK_EQ(url, name);
17534  }
17535}
17536
17537
17538TEST(SourceURLInStackTrace) {
17539  v8::Isolate* isolate = CcTest::isolate();
17540  v8::HandleScope scope(isolate);
17541  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17542  templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17543             v8::FunctionTemplate::New(isolate,
17544                                       AnalyzeStackOfEvalWithSourceURL));
17545  LocalContext context(0, templ);
17546
17547  const char *source =
17548    "function outer() {\n"
17549    "function bar() {\n"
17550    "  AnalyzeStackOfEvalWithSourceURL();\n"
17551    "}\n"
17552    "function foo() {\n"
17553    "\n"
17554    "  bar();\n"
17555    "}\n"
17556    "foo();\n"
17557    "}\n"
17558    "eval('(' + outer +')()%s');";
17559
17560  i::ScopedVector<char> code(1024);
17561  i::SNPrintF(code, source, "//# sourceURL=eval_url");
17562  CHECK(CompileRun(code.start())->IsUndefined());
17563  i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17564  CHECK(CompileRun(code.start())->IsUndefined());
17565}
17566
17567
17568static int scriptIdInStack[2];
17569
17570void AnalyzeScriptIdInStack(
17571    const v8::FunctionCallbackInfo<v8::Value>& args) {
17572  v8::HandleScope scope(args.GetIsolate());
17573  v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17574      args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17575  CHECK_EQ(2, stackTrace->GetFrameCount());
17576  for (int i = 0; i < 2; i++) {
17577    scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17578  }
17579}
17580
17581
17582TEST(ScriptIdInStackTrace) {
17583  v8::Isolate* isolate = CcTest::isolate();
17584  v8::HandleScope scope(isolate);
17585  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17586  templ->Set(v8_str("AnalyzeScriptIdInStack"),
17587             v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17588  LocalContext context(0, templ);
17589
17590  v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17591    isolate,
17592    "function foo() {\n"
17593    "  AnalyzeScriptIdInStack();"
17594    "}\n"
17595    "foo();\n");
17596  v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17597  script->Run();
17598  for (int i = 0; i < 2; i++) {
17599    CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17600    CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17601  }
17602}
17603
17604
17605void AnalyzeStackOfInlineScriptWithSourceURL(
17606    const v8::FunctionCallbackInfo<v8::Value>& args) {
17607  v8::HandleScope scope(args.GetIsolate());
17608  v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17609      args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17610  CHECK_EQ(4, stackTrace->GetFrameCount());
17611  v8::Handle<v8::String> url = v8_str("url");
17612  for (int i = 0; i < 3; i++) {
17613    v8::Handle<v8::String> name =
17614        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17615    CHECK(!name.IsEmpty());
17616    CHECK_EQ(url, name);
17617  }
17618}
17619
17620
17621TEST(InlineScriptWithSourceURLInStackTrace) {
17622  v8::Isolate* isolate = CcTest::isolate();
17623  v8::HandleScope scope(isolate);
17624  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17625  templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17626             v8::FunctionTemplate::New(
17627                 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17628  LocalContext context(0, templ);
17629
17630  const char *source =
17631    "function outer() {\n"
17632    "function bar() {\n"
17633    "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
17634    "}\n"
17635    "function foo() {\n"
17636    "\n"
17637    "  bar();\n"
17638    "}\n"
17639    "foo();\n"
17640    "}\n"
17641    "outer()\n%s";
17642
17643  i::ScopedVector<char> code(1024);
17644  i::SNPrintF(code, source, "//# sourceURL=source_url");
17645  CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17646  i::SNPrintF(code, source, "//@ sourceURL=source_url");
17647  CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17648}
17649
17650
17651void AnalyzeStackOfDynamicScriptWithSourceURL(
17652    const v8::FunctionCallbackInfo<v8::Value>& args) {
17653  v8::HandleScope scope(args.GetIsolate());
17654  v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17655      args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17656  CHECK_EQ(4, stackTrace->GetFrameCount());
17657  v8::Handle<v8::String> url = v8_str("source_url");
17658  for (int i = 0; i < 3; i++) {
17659    v8::Handle<v8::String> name =
17660        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17661    CHECK(!name.IsEmpty());
17662    CHECK_EQ(url, name);
17663  }
17664}
17665
17666
17667TEST(DynamicWithSourceURLInStackTrace) {
17668  v8::Isolate* isolate = CcTest::isolate();
17669  v8::HandleScope scope(isolate);
17670  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17671  templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17672             v8::FunctionTemplate::New(
17673                 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17674  LocalContext context(0, templ);
17675
17676  const char *source =
17677    "function outer() {\n"
17678    "function bar() {\n"
17679    "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17680    "}\n"
17681    "function foo() {\n"
17682    "\n"
17683    "  bar();\n"
17684    "}\n"
17685    "foo();\n"
17686    "}\n"
17687    "outer()\n%s";
17688
17689  i::ScopedVector<char> code(1024);
17690  i::SNPrintF(code, source, "//# sourceURL=source_url");
17691  CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17692  i::SNPrintF(code, source, "//@ sourceURL=source_url");
17693  CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17694}
17695
17696
17697TEST(DynamicWithSourceURLInStackTraceString) {
17698  LocalContext context;
17699  v8::HandleScope scope(context->GetIsolate());
17700
17701  const char *source =
17702    "function outer() {\n"
17703    "  function foo() {\n"
17704    "    FAIL.FAIL;\n"
17705    "  }\n"
17706    "  foo();\n"
17707    "}\n"
17708    "outer()\n%s";
17709
17710  i::ScopedVector<char> code(1024);
17711  i::SNPrintF(code, source, "//# sourceURL=source_url");
17712  v8::TryCatch try_catch;
17713  CompileRunWithOrigin(code.start(), "", 0, 0);
17714  CHECK(try_catch.HasCaught());
17715  v8::String::Utf8Value stack(try_catch.StackTrace());
17716  CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17717}
17718
17719
17720TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17721  LocalContext context;
17722  v8::HandleScope scope(context->GetIsolate());
17723
17724  const char *source =
17725    "function outer() {\n"
17726    "  var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
17727    "  //# sourceURL=source_url\";\n"
17728    "  eval(scriptContents);\n"
17729    "  foo(); }\n"
17730    "outer();\n"
17731    "//# sourceURL=outer_url";
17732
17733  v8::TryCatch try_catch;
17734  CompileRun(source);
17735  CHECK(try_catch.HasCaught());
17736
17737  Local<v8::Message> message = try_catch.Message();
17738  Handle<Value> sourceURL =
17739    message->GetScriptOrigin().ResourceName();
17740  CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17741}
17742
17743
17744TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17745  LocalContext context;
17746  v8::HandleScope scope(context->GetIsolate());
17747
17748  const char *source =
17749    "function outer() {\n"
17750    "  var scriptContents = \"function boo(){ boo(); }\\\n"
17751    "  //# sourceURL=source_url\";\n"
17752    "  eval(scriptContents);\n"
17753    "  boo(); }\n"
17754    "outer();\n"
17755    "//# sourceURL=outer_url";
17756
17757  v8::TryCatch try_catch;
17758  CompileRun(source);
17759  CHECK(try_catch.HasCaught());
17760
17761  Local<v8::Message> message = try_catch.Message();
17762  Handle<Value> sourceURL =
17763    message->GetScriptOrigin().ResourceName();
17764  CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17765}
17766
17767
17768static void CreateGarbageInOldSpace() {
17769  i::Factory* factory = CcTest::i_isolate()->factory();
17770  v8::HandleScope scope(CcTest::isolate());
17771  i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17772  for (int i = 0; i < 1000; i++) {
17773    factory->NewFixedArray(1000, i::TENURED);
17774  }
17775}
17776
17777
17778// Test that idle notification can be handled and eventually returns true.
17779TEST(IdleNotification) {
17780  const intptr_t MB = 1024 * 1024;
17781  const int IdlePauseInMs = 1000;
17782  LocalContext env;
17783  v8::HandleScope scope(env->GetIsolate());
17784  intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17785  CreateGarbageInOldSpace();
17786  intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17787  CHECK_GT(size_with_garbage, initial_size + MB);
17788  bool finished = false;
17789  for (int i = 0; i < 200 && !finished; i++) {
17790    finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17791  }
17792  intptr_t final_size = CcTest::heap()->SizeOfObjects();
17793  CHECK(finished);
17794  CHECK_LT(final_size, initial_size + 1);
17795}
17796
17797
17798// Test that idle notification can be handled and eventually collects garbage.
17799TEST(IdleNotificationWithSmallHint) {
17800  const intptr_t MB = 1024 * 1024;
17801  const int IdlePauseInMs = 900;
17802  LocalContext env;
17803  v8::HandleScope scope(env->GetIsolate());
17804  intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17805  CreateGarbageInOldSpace();
17806  intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17807  CHECK_GT(size_with_garbage, initial_size + MB);
17808  bool finished = false;
17809  for (int i = 0; i < 200 && !finished; i++) {
17810    finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17811  }
17812  intptr_t final_size = CcTest::heap()->SizeOfObjects();
17813  CHECK(finished);
17814  CHECK_LT(final_size, initial_size + 1);
17815}
17816
17817
17818// Test that idle notification can be handled and eventually collects garbage.
17819TEST(IdleNotificationWithLargeHint) {
17820  const intptr_t MB = 1024 * 1024;
17821  const int IdlePauseInMs = 900;
17822  LocalContext env;
17823  v8::HandleScope scope(env->GetIsolate());
17824  intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17825  CreateGarbageInOldSpace();
17826  intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17827  CHECK_GT(size_with_garbage, initial_size + MB);
17828  bool finished = false;
17829  for (int i = 0; i < 200 && !finished; i++) {
17830    finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17831  }
17832  intptr_t final_size = CcTest::heap()->SizeOfObjects();
17833  CHECK(finished);
17834  CHECK_LT(final_size, initial_size + 1);
17835}
17836
17837
17838TEST(Regress2107) {
17839  const intptr_t MB = 1024 * 1024;
17840  const int kIdlePauseInMs = 1000;
17841  LocalContext env;
17842  v8::Isolate* isolate = env->GetIsolate();
17843  v8::HandleScope scope(env->GetIsolate());
17844  intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17845  // Send idle notification to start a round of incremental GCs.
17846  env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17847  // Emulate 7 page reloads.
17848  for (int i = 0; i < 7; i++) {
17849    {
17850      v8::HandleScope inner_scope(env->GetIsolate());
17851      v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17852      ctx->Enter();
17853      CreateGarbageInOldSpace();
17854      ctx->Exit();
17855    }
17856    env->GetIsolate()->ContextDisposedNotification();
17857    env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17858  }
17859  // Create garbage and check that idle notification still collects it.
17860  CreateGarbageInOldSpace();
17861  intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17862  CHECK_GT(size_with_garbage, initial_size + MB);
17863  bool finished = false;
17864  for (int i = 0; i < 200 && !finished; i++) {
17865    finished = env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17866  }
17867  intptr_t final_size = CcTest::heap()->SizeOfObjects();
17868  CHECK_LT(final_size, initial_size + 1);
17869}
17870
17871
17872TEST(Regress2333) {
17873  LocalContext env;
17874  for (int i = 0; i < 3; i++) {
17875    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17876  }
17877}
17878
17879static uint32_t* stack_limit;
17880
17881static void GetStackLimitCallback(
17882    const v8::FunctionCallbackInfo<v8::Value>& args) {
17883  stack_limit = reinterpret_cast<uint32_t*>(
17884      CcTest::i_isolate()->stack_guard()->real_climit());
17885}
17886
17887
17888// Uses the address of a local variable to determine the stack top now.
17889// Given a size, returns an address that is that far from the current
17890// top of stack.
17891static uint32_t* ComputeStackLimit(uint32_t size) {
17892  uint32_t* answer = &size - (size / sizeof(size));
17893  // If the size is very large and the stack is very near the bottom of
17894  // memory then the calculation above may wrap around and give an address
17895  // that is above the (downwards-growing) stack.  In that case we return
17896  // a very low address.
17897  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17898  return answer;
17899}
17900
17901
17902// We need at least 165kB for an x64 debug build with clang and ASAN.
17903static const int stack_breathing_room = 256 * i::KB;
17904
17905
17906TEST(SetStackLimit) {
17907  uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17908
17909  // Set stack limit.
17910  CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
17911
17912  // Execute a script.
17913  LocalContext env;
17914  v8::HandleScope scope(env->GetIsolate());
17915  Local<v8::FunctionTemplate> fun_templ =
17916      v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17917  Local<Function> fun = fun_templ->GetFunction();
17918  env->Global()->Set(v8_str("get_stack_limit"), fun);
17919  CompileRun("get_stack_limit();");
17920
17921  CHECK(stack_limit == set_limit);
17922}
17923
17924
17925TEST(SetStackLimitInThread) {
17926  uint32_t* set_limit;
17927  {
17928    v8::Locker locker(CcTest::isolate());
17929    set_limit = ComputeStackLimit(stack_breathing_room);
17930
17931    // Set stack limit.
17932    CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
17933
17934    // Execute a script.
17935    v8::HandleScope scope(CcTest::isolate());
17936    LocalContext env;
17937    Local<v8::FunctionTemplate> fun_templ =
17938        v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17939    Local<Function> fun = fun_templ->GetFunction();
17940    env->Global()->Set(v8_str("get_stack_limit"), fun);
17941    CompileRun("get_stack_limit();");
17942
17943    CHECK(stack_limit == set_limit);
17944  }
17945  {
17946    v8::Locker locker(CcTest::isolate());
17947    CHECK(stack_limit == set_limit);
17948  }
17949}
17950
17951
17952THREADED_TEST(GetHeapStatistics) {
17953  LocalContext c1;
17954  v8::HandleScope scope(c1->GetIsolate());
17955  v8::HeapStatistics heap_statistics;
17956  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17957  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17958  c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17959  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17960  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17961}
17962
17963
17964class VisitorImpl : public v8::ExternalResourceVisitor {
17965 public:
17966  explicit VisitorImpl(TestResource** resource) {
17967    for (int i = 0; i < 4; i++) {
17968      resource_[i] = resource[i];
17969      found_resource_[i] = false;
17970    }
17971  }
17972  virtual ~VisitorImpl() {}
17973  virtual void VisitExternalString(v8::Handle<v8::String> string) {
17974    if (!string->IsExternal()) {
17975      CHECK(string->IsExternalOneByte());
17976      return;
17977    }
17978    v8::String::ExternalStringResource* resource =
17979        string->GetExternalStringResource();
17980    CHECK(resource);
17981    for (int i = 0; i < 4; i++) {
17982      if (resource_[i] == resource) {
17983        CHECK(!found_resource_[i]);
17984        found_resource_[i] = true;
17985      }
17986    }
17987  }
17988  void CheckVisitedResources() {
17989    for (int i = 0; i < 4; i++) {
17990      CHECK(found_resource_[i]);
17991    }
17992  }
17993
17994 private:
17995  v8::String::ExternalStringResource* resource_[4];
17996  bool found_resource_[4];
17997};
17998
17999
18000TEST(ExternalizeOldSpaceTwoByteCons) {
18001  LocalContext env;
18002  v8::HandleScope scope(env->GetIsolate());
18003  v8::Local<v8::String> cons =
18004      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18005  CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18006  CcTest::heap()->CollectAllAvailableGarbage();
18007  CHECK(CcTest::heap()->old_pointer_space()->Contains(
18008            *v8::Utils::OpenHandle(*cons)));
18009
18010  TestResource* resource = new TestResource(
18011      AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
18012  cons->MakeExternal(resource);
18013
18014  CHECK(cons->IsExternal());
18015  CHECK_EQ(resource, cons->GetExternalStringResource());
18016  String::Encoding encoding;
18017  CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18018  CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
18019}
18020
18021
18022TEST(ExternalizeOldSpaceOneByteCons) {
18023  LocalContext env;
18024  v8::HandleScope scope(env->GetIsolate());
18025  v8::Local<v8::String> cons =
18026      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18027  CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18028  CcTest::heap()->CollectAllAvailableGarbage();
18029  CHECK(CcTest::heap()->old_pointer_space()->Contains(
18030            *v8::Utils::OpenHandle(*cons)));
18031
18032  TestOneByteResource* resource =
18033      new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
18034  cons->MakeExternal(resource);
18035
18036  CHECK(cons->IsExternalOneByte());
18037  CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
18038  String::Encoding encoding;
18039  CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18040  CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
18041}
18042
18043
18044TEST(VisitExternalStrings) {
18045  LocalContext env;
18046  v8::HandleScope scope(env->GetIsolate());
18047  const char* string = "Some string";
18048  uint16_t* two_byte_string = AsciiToTwoByteString(string);
18049  TestResource* resource[4];
18050  resource[0] = new TestResource(two_byte_string);
18051  v8::Local<v8::String> string0 =
18052      v8::String::NewExternal(env->GetIsolate(), resource[0]);
18053  resource[1] = new TestResource(two_byte_string, NULL, false);
18054  v8::Local<v8::String> string1 =
18055      v8::String::NewExternal(env->GetIsolate(), resource[1]);
18056
18057  // Externalized symbol.
18058  resource[2] = new TestResource(two_byte_string, NULL, false);
18059  v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
18060      env->GetIsolate(), string, v8::String::kInternalizedString);
18061  CHECK(string2->MakeExternal(resource[2]));
18062
18063  // Symbolized External.
18064  resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18065  v8::Local<v8::String> string3 =
18066      v8::String::NewExternal(env->GetIsolate(), resource[3]);
18067  CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
18068  // Turn into a symbol.
18069  i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18070  CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18071      string3_i).is_null());
18072  CHECK(string3_i->IsInternalizedString());
18073
18074  // We need to add usages for string* to avoid warnings in GCC 4.7
18075  CHECK(string0->IsExternal());
18076  CHECK(string1->IsExternal());
18077  CHECK(string2->IsExternal());
18078  CHECK(string3->IsExternal());
18079
18080  VisitorImpl visitor(resource);
18081  v8::V8::VisitExternalResources(&visitor);
18082  visitor.CheckVisitedResources();
18083}
18084
18085
18086TEST(ExternalStringCollectedAtTearDown) {
18087  int destroyed = 0;
18088  v8::Isolate* isolate = v8::Isolate::New();
18089  { v8::Isolate::Scope isolate_scope(isolate);
18090    v8::HandleScope handle_scope(isolate);
18091    const char* s = "One string to test them all, one string to find them.";
18092    TestOneByteResource* inscription =
18093        new TestOneByteResource(i::StrDup(s), &destroyed);
18094    v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
18095    // Ring is still alive.  Orcs are roaming freely across our lands.
18096    CHECK_EQ(0, destroyed);
18097    USE(ring);
18098  }
18099
18100  isolate->Dispose();
18101  // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18102  CHECK_EQ(1, destroyed);
18103}
18104
18105
18106TEST(ExternalInternalizedStringCollectedAtTearDown) {
18107  int destroyed = 0;
18108  v8::Isolate* isolate = v8::Isolate::New();
18109  { v8::Isolate::Scope isolate_scope(isolate);
18110    LocalContext env(isolate);
18111    v8::HandleScope handle_scope(isolate);
18112    CompileRun("var ring = 'One string to test them all';");
18113    const char* s = "One string to test them all";
18114    TestOneByteResource* inscription =
18115        new TestOneByteResource(i::StrDup(s), &destroyed);
18116    v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18117    CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18118    ring->MakeExternal(inscription);
18119    // Ring is still alive.  Orcs are roaming freely across our lands.
18120    CHECK_EQ(0, destroyed);
18121    USE(ring);
18122  }
18123
18124  isolate->Dispose();
18125  // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18126  CHECK_EQ(1, destroyed);
18127}
18128
18129
18130TEST(ExternalInternalizedStringCollectedAtGC) {
18131  int destroyed = 0;
18132  { LocalContext env;
18133    v8::HandleScope handle_scope(env->GetIsolate());
18134    CompileRun("var ring = 'One string to test them all';");
18135    const char* s = "One string to test them all";
18136    TestOneByteResource* inscription =
18137        new TestOneByteResource(i::StrDup(s), &destroyed);
18138    v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18139    CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18140    ring->MakeExternal(inscription);
18141    // Ring is still alive.  Orcs are roaming freely across our lands.
18142    CHECK_EQ(0, destroyed);
18143    USE(ring);
18144  }
18145
18146  // Garbage collector deals swift blows to evil.
18147  CcTest::i_isolate()->compilation_cache()->Clear();
18148  CcTest::heap()->CollectAllAvailableGarbage();
18149
18150  // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18151  CHECK_EQ(1, destroyed);
18152}
18153
18154
18155static double DoubleFromBits(uint64_t value) {
18156  double target;
18157  i::MemCopy(&target, &value, sizeof(target));
18158  return target;
18159}
18160
18161
18162static uint64_t DoubleToBits(double value) {
18163  uint64_t target;
18164  i::MemCopy(&target, &value, sizeof(target));
18165  return target;
18166}
18167
18168
18169static double DoubleToDateTime(double input) {
18170  double date_limit = 864e13;
18171  if (std::isnan(input) || input < -date_limit || input > date_limit) {
18172    return v8::base::OS::nan_value();
18173  }
18174  return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18175}
18176
18177
18178// We don't have a consistent way to write 64-bit constants syntactically, so we
18179// split them into two 32-bit constants and combine them programmatically.
18180static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18181  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18182}
18183
18184
18185THREADED_TEST(QuietSignalingNaNs) {
18186  LocalContext context;
18187  v8::Isolate* isolate = context->GetIsolate();
18188  v8::HandleScope scope(isolate);
18189  v8::TryCatch try_catch;
18190
18191  // Special double values.
18192  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18193  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18194  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18195  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18196  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18197  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18198  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18199
18200  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18201  // on either side of the epoch.
18202  double date_limit = 864e13;
18203
18204  double test_values[] = {
18205      snan,
18206      qnan,
18207      infinity,
18208      max_normal,
18209      date_limit + 1,
18210      date_limit,
18211      min_normal,
18212      max_denormal,
18213      min_denormal,
18214      0,
18215      -0,
18216      -min_denormal,
18217      -max_denormal,
18218      -min_normal,
18219      -date_limit,
18220      -date_limit - 1,
18221      -max_normal,
18222      -infinity,
18223      -qnan,
18224      -snan
18225  };
18226  int num_test_values = 20;
18227
18228  for (int i = 0; i < num_test_values; i++) {
18229    double test_value = test_values[i];
18230
18231    // Check that Number::New preserves non-NaNs and quiets SNaNs.
18232    v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18233    double stored_number = number->NumberValue();
18234    if (!std::isnan(test_value)) {
18235      CHECK_EQ(test_value, stored_number);
18236    } else {
18237      uint64_t stored_bits = DoubleToBits(stored_number);
18238      // Check if quiet nan (bits 51..62 all set).
18239#if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18240    !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18241      // Most significant fraction bit for quiet nan is set to 0
18242      // on MIPS architecture. Allowed by IEEE-754.
18243      CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18244#else
18245      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18246#endif
18247    }
18248
18249    // Check that Date::New preserves non-NaNs in the date range and
18250    // quiets SNaNs.
18251    v8::Handle<v8::Value> date =
18252        v8::Date::New(isolate, test_value);
18253    double expected_stored_date = DoubleToDateTime(test_value);
18254    double stored_date = date->NumberValue();
18255    if (!std::isnan(expected_stored_date)) {
18256      CHECK_EQ(expected_stored_date, stored_date);
18257    } else {
18258      uint64_t stored_bits = DoubleToBits(stored_date);
18259      // Check if quiet nan (bits 51..62 all set).
18260#if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18261    !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18262      // Most significant fraction bit for quiet nan is set to 0
18263      // on MIPS architecture. Allowed by IEEE-754.
18264      CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18265#else
18266      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18267#endif
18268    }
18269  }
18270}
18271
18272
18273static void SpaghettiIncident(
18274    const v8::FunctionCallbackInfo<v8::Value>& args) {
18275  v8::HandleScope scope(args.GetIsolate());
18276  v8::TryCatch tc;
18277  v8::Handle<v8::String> str(args[0]->ToString());
18278  USE(str);
18279  if (tc.HasCaught())
18280    tc.ReThrow();
18281}
18282
18283
18284// Test that an exception can be propagated down through a spaghetti
18285// stack using ReThrow.
18286THREADED_TEST(SpaghettiStackReThrow) {
18287  v8::Isolate* isolate = CcTest::isolate();
18288  v8::HandleScope scope(isolate);
18289  LocalContext context;
18290  context->Global()->Set(
18291      v8::String::NewFromUtf8(isolate, "s"),
18292      v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18293  v8::TryCatch try_catch;
18294  CompileRun(
18295      "var i = 0;"
18296      "var o = {"
18297      "  toString: function () {"
18298      "    if (i == 10) {"
18299      "      throw 'Hey!';"
18300      "    } else {"
18301      "      i++;"
18302      "      return s(o);"
18303      "    }"
18304      "  }"
18305      "};"
18306      "s(o);");
18307  CHECK(try_catch.HasCaught());
18308  v8::String::Utf8Value value(try_catch.Exception());
18309  CHECK_EQ(0, strcmp(*value, "Hey!"));
18310}
18311
18312
18313TEST(Regress528) {
18314  v8::V8::Initialize();
18315  v8::Isolate* isolate = CcTest::isolate();
18316  v8::HandleScope scope(isolate);
18317  v8::Local<Context> other_context;
18318  int gc_count;
18319
18320  // Create a context used to keep the code from aging in the compilation
18321  // cache.
18322  other_context = Context::New(isolate);
18323
18324  // Context-dependent context data creates reference from the compilation
18325  // cache to the global object.
18326  const char* source_simple = "1";
18327  {
18328    v8::HandleScope scope(isolate);
18329    v8::Local<Context> context = Context::New(isolate);
18330
18331    context->Enter();
18332    Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18333    context->SetEmbedderData(0, obj);
18334    CompileRun(source_simple);
18335    context->Exit();
18336  }
18337  isolate->ContextDisposedNotification();
18338  for (gc_count = 1; gc_count < 10; gc_count++) {
18339    other_context->Enter();
18340    CompileRun(source_simple);
18341    other_context->Exit();
18342    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18343    if (GetGlobalObjectsCount() == 1) break;
18344  }
18345  CHECK_GE(2, gc_count);
18346  CHECK_EQ(1, GetGlobalObjectsCount());
18347
18348  // Eval in a function creates reference from the compilation cache to the
18349  // global object.
18350  const char* source_eval = "function f(){eval('1')}; f()";
18351  {
18352    v8::HandleScope scope(isolate);
18353    v8::Local<Context> context = Context::New(isolate);
18354
18355    context->Enter();
18356    CompileRun(source_eval);
18357    context->Exit();
18358  }
18359  isolate->ContextDisposedNotification();
18360  for (gc_count = 1; gc_count < 10; gc_count++) {
18361    other_context->Enter();
18362    CompileRun(source_eval);
18363    other_context->Exit();
18364    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18365    if (GetGlobalObjectsCount() == 1) break;
18366  }
18367  CHECK_GE(2, gc_count);
18368  CHECK_EQ(1, GetGlobalObjectsCount());
18369
18370  // Looking up the line number for an exception creates reference from the
18371  // compilation cache to the global object.
18372  const char* source_exception = "function f(){throw 1;} f()";
18373  {
18374    v8::HandleScope scope(isolate);
18375    v8::Local<Context> context = Context::New(isolate);
18376
18377    context->Enter();
18378    v8::TryCatch try_catch;
18379    CompileRun(source_exception);
18380    CHECK(try_catch.HasCaught());
18381    v8::Handle<v8::Message> message = try_catch.Message();
18382    CHECK(!message.IsEmpty());
18383    CHECK_EQ(1, message->GetLineNumber());
18384    context->Exit();
18385  }
18386  isolate->ContextDisposedNotification();
18387  for (gc_count = 1; gc_count < 10; gc_count++) {
18388    other_context->Enter();
18389    CompileRun(source_exception);
18390    other_context->Exit();
18391    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18392    if (GetGlobalObjectsCount() == 1) break;
18393  }
18394  CHECK_GE(2, gc_count);
18395  CHECK_EQ(1, GetGlobalObjectsCount());
18396
18397  isolate->ContextDisposedNotification();
18398}
18399
18400
18401THREADED_TEST(ScriptOrigin) {
18402  LocalContext env;
18403  v8::HandleScope scope(env->GetIsolate());
18404  v8::ScriptOrigin origin =
18405      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18406  v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18407      env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18408  v8::Script::Compile(script, &origin)->Run();
18409  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18410      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18411  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18412      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18413
18414  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18415  CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18416  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18417
18418  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18419  CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18420  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18421}
18422
18423
18424THREADED_TEST(FunctionGetInferredName) {
18425  LocalContext env;
18426  v8::HandleScope scope(env->GetIsolate());
18427  v8::ScriptOrigin origin =
18428      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18429  v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18430      env->GetIsolate(),
18431      "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18432  v8::Script::Compile(script, &origin)->Run();
18433  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18434      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18435  CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18436}
18437
18438
18439THREADED_TEST(FunctionGetDisplayName) {
18440  LocalContext env;
18441  v8::HandleScope scope(env->GetIsolate());
18442  const char* code = "var error = false;"
18443                     "function a() { this.x = 1; };"
18444                     "a.displayName = 'display_a';"
18445                     "var b = (function() {"
18446                     "  var f = function() { this.x = 2; };"
18447                     "  f.displayName = 'display_b';"
18448                     "  return f;"
18449                     "})();"
18450                     "var c = function() {};"
18451                     "c.__defineGetter__('displayName', function() {"
18452                     "  error = true;"
18453                     "  throw new Error();"
18454                     "});"
18455                     "function d() {};"
18456                     "d.__defineGetter__('displayName', function() {"
18457                     "  error = true;"
18458                     "  return 'wrong_display_name';"
18459                     "});"
18460                     "function e() {};"
18461                     "e.displayName = 'wrong_display_name';"
18462                     "e.__defineSetter__('displayName', function() {"
18463                     "  error = true;"
18464                     "  throw new Error();"
18465                     "});"
18466                     "function f() {};"
18467                     "f.displayName = { 'foo': 6, toString: function() {"
18468                     "  error = true;"
18469                     "  return 'wrong_display_name';"
18470                     "}};"
18471                     "var g = function() {"
18472                     "  arguments.callee.displayName = 'set_in_runtime';"
18473                     "}; g();"
18474                     ;
18475  v8::ScriptOrigin origin =
18476      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18477  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18478      ->Run();
18479  v8::Local<v8::Value> error =
18480      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18481  v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18482      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18483  v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18484      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18485  v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18486      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18487  v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18488      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18489  v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18490      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18491  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18492      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18493  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18494      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18495  CHECK_EQ(false, error->BooleanValue());
18496  CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18497  CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18498  CHECK(c->GetDisplayName()->IsUndefined());
18499  CHECK(d->GetDisplayName()->IsUndefined());
18500  CHECK(e->GetDisplayName()->IsUndefined());
18501  CHECK(f->GetDisplayName()->IsUndefined());
18502  CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18503}
18504
18505
18506THREADED_TEST(ScriptLineNumber) {
18507  LocalContext env;
18508  v8::HandleScope scope(env->GetIsolate());
18509  v8::ScriptOrigin origin =
18510      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18511  v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18512      env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18513  v8::Script::Compile(script, &origin)->Run();
18514  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18515      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18516  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18517      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18518  CHECK_EQ(0, f->GetScriptLineNumber());
18519  CHECK_EQ(2, g->GetScriptLineNumber());
18520}
18521
18522
18523THREADED_TEST(ScriptColumnNumber) {
18524  LocalContext env;
18525  v8::Isolate* isolate = env->GetIsolate();
18526  v8::HandleScope scope(isolate);
18527  v8::ScriptOrigin origin =
18528      v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18529                       v8::Integer::New(isolate, 3),
18530                       v8::Integer::New(isolate, 2));
18531  v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18532      isolate, "function foo() {}\n\n     function bar() {}");
18533  v8::Script::Compile(script, &origin)->Run();
18534  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18535      env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18536  v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18537      env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18538  CHECK_EQ(14, foo->GetScriptColumnNumber());
18539  CHECK_EQ(17, bar->GetScriptColumnNumber());
18540}
18541
18542
18543THREADED_TEST(FunctionIsBuiltin) {
18544  LocalContext env;
18545  v8::Isolate* isolate = env->GetIsolate();
18546  v8::HandleScope scope(isolate);
18547  v8::Local<v8::Function> f;
18548  f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18549  CHECK(f->IsBuiltin());
18550  f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18551  CHECK(f->IsBuiltin());
18552  f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18553  CHECK(f->IsBuiltin());
18554  f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18555  CHECK(f->IsBuiltin());
18556  f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18557  CHECK(!f->IsBuiltin());
18558}
18559
18560
18561THREADED_TEST(FunctionGetScriptId) {
18562  LocalContext env;
18563  v8::Isolate* isolate = env->GetIsolate();
18564  v8::HandleScope scope(isolate);
18565  v8::ScriptOrigin origin =
18566      v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18567                       v8::Integer::New(isolate, 3),
18568                       v8::Integer::New(isolate, 2));
18569  v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18570      isolate, "function foo() {}\n\n     function bar() {}");
18571  v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18572  script->Run();
18573  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18574      env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18575  v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18576      env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18577  CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
18578  CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
18579}
18580
18581
18582THREADED_TEST(FunctionGetBoundFunction) {
18583  LocalContext env;
18584  v8::HandleScope scope(env->GetIsolate());
18585  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18586      env->GetIsolate(), "test"));
18587  v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18588      env->GetIsolate(),
18589      "var a = new Object();\n"
18590      "a.x = 1;\n"
18591      "function f () { return this.x };\n"
18592      "var g = f.bind(a);\n"
18593      "var b = g();");
18594  v8::Script::Compile(script, &origin)->Run();
18595  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18596      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18597  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18598      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18599  CHECK(g->GetBoundFunction()->IsFunction());
18600  Local<v8::Function> original_function = Local<v8::Function>::Cast(
18601      g->GetBoundFunction());
18602  CHECK_EQ(f->GetName(), original_function->GetName());
18603  CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18604  CHECK_EQ(f->GetScriptColumnNumber(),
18605           original_function->GetScriptColumnNumber());
18606}
18607
18608
18609static void GetterWhichReturns42(
18610    Local<String> name,
18611    const v8::PropertyCallbackInfo<v8::Value>& info) {
18612  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18613  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18614  info.GetReturnValue().Set(v8_num(42));
18615}
18616
18617
18618static void SetterWhichSetsYOnThisTo23(
18619    Local<String> name,
18620    Local<Value> value,
18621    const v8::PropertyCallbackInfo<void>& info) {
18622  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18623  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18624  Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18625}
18626
18627
18628void FooGetInterceptor(Local<String> name,
18629                       const v8::PropertyCallbackInfo<v8::Value>& info) {
18630  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18631  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18632  if (!name->Equals(v8_str("foo"))) return;
18633  info.GetReturnValue().Set(v8_num(42));
18634}
18635
18636
18637void FooSetInterceptor(Local<String> name,
18638                       Local<Value> value,
18639                       const v8::PropertyCallbackInfo<v8::Value>& info) {
18640  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18641  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18642  if (!name->Equals(v8_str("foo"))) return;
18643  Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18644  info.GetReturnValue().Set(v8_num(23));
18645}
18646
18647
18648TEST(SetterOnConstructorPrototype) {
18649  v8::Isolate* isolate = CcTest::isolate();
18650  v8::HandleScope scope(isolate);
18651  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18652  templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18653                     SetterWhichSetsYOnThisTo23);
18654  LocalContext context;
18655  context->Global()->Set(v8_str("P"), templ->NewInstance());
18656  CompileRun("function C1() {"
18657             "  this.x = 23;"
18658             "};"
18659             "C1.prototype = P;"
18660             "function C2() {"
18661             "  this.x = 23"
18662             "};"
18663             "C2.prototype = { };"
18664             "C2.prototype.__proto__ = P;");
18665
18666  v8::Local<v8::Script> script;
18667  script = v8_compile("new C1();");
18668  for (int i = 0; i < 10; i++) {
18669    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18670    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18671    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18672  }
18673
18674script = v8_compile("new C2();");
18675  for (int i = 0; i < 10; i++) {
18676    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18677    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18678    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18679  }
18680}
18681
18682
18683static void NamedPropertyGetterWhichReturns42(
18684    Local<String> name,
18685    const v8::PropertyCallbackInfo<v8::Value>& info) {
18686  info.GetReturnValue().Set(v8_num(42));
18687}
18688
18689
18690static void NamedPropertySetterWhichSetsYOnThisTo23(
18691    Local<String> name,
18692    Local<Value> value,
18693    const v8::PropertyCallbackInfo<v8::Value>& info) {
18694  if (name->Equals(v8_str("x"))) {
18695    Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18696  }
18697}
18698
18699
18700THREADED_TEST(InterceptorOnConstructorPrototype) {
18701  v8::Isolate* isolate = CcTest::isolate();
18702  v8::HandleScope scope(isolate);
18703  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18704  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18705                                 NamedPropertySetterWhichSetsYOnThisTo23);
18706  LocalContext context;
18707  context->Global()->Set(v8_str("P"), templ->NewInstance());
18708  CompileRun("function C1() {"
18709             "  this.x = 23;"
18710             "};"
18711             "C1.prototype = P;"
18712             "function C2() {"
18713             "  this.x = 23"
18714             "};"
18715             "C2.prototype = { };"
18716             "C2.prototype.__proto__ = P;");
18717
18718  v8::Local<v8::Script> script;
18719  script = v8_compile("new C1();");
18720  for (int i = 0; i < 10; i++) {
18721    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18722    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18723    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18724  }
18725
18726  script = v8_compile("new C2();");
18727  for (int i = 0; i < 10; i++) {
18728    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18729    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18730    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18731  }
18732}
18733
18734
18735TEST(Regress618) {
18736  const char* source = "function C1() {"
18737                       "  this.x = 23;"
18738                       "};"
18739                       "C1.prototype = P;";
18740
18741  LocalContext context;
18742  v8::Isolate* isolate = context->GetIsolate();
18743  v8::HandleScope scope(isolate);
18744  v8::Local<v8::Script> script;
18745
18746  // Use a simple object as prototype.
18747  v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18748  prototype->Set(v8_str("y"), v8_num(42));
18749  context->Global()->Set(v8_str("P"), prototype);
18750
18751  // This compile will add the code to the compilation cache.
18752  CompileRun(source);
18753
18754  script = v8_compile("new C1();");
18755  // Allow enough iterations for the inobject slack tracking logic
18756  // to finalize instance size and install the fast construct stub.
18757  for (int i = 0; i < 256; i++) {
18758    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18759    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18760    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18761  }
18762
18763  // Use an API object with accessors as prototype.
18764  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18765  templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18766                     SetterWhichSetsYOnThisTo23);
18767  context->Global()->Set(v8_str("P"), templ->NewInstance());
18768
18769  // This compile will get the code from the compilation cache.
18770  CompileRun(source);
18771
18772  script = v8_compile("new C1();");
18773  for (int i = 0; i < 10; i++) {
18774    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18775    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18776    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18777  }
18778}
18779
18780v8::Isolate* gc_callbacks_isolate = NULL;
18781int prologue_call_count = 0;
18782int epilogue_call_count = 0;
18783int prologue_call_count_second = 0;
18784int epilogue_call_count_second = 0;
18785int prologue_call_count_alloc = 0;
18786int epilogue_call_count_alloc = 0;
18787
18788void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18789  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18790  ++prologue_call_count;
18791}
18792
18793
18794void PrologueCallback(v8::Isolate* isolate,
18795                      v8::GCType,
18796                      v8::GCCallbackFlags flags) {
18797  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18798  CHECK_EQ(gc_callbacks_isolate, isolate);
18799  ++prologue_call_count;
18800}
18801
18802
18803void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18804  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18805  ++epilogue_call_count;
18806}
18807
18808
18809void EpilogueCallback(v8::Isolate* isolate,
18810                      v8::GCType,
18811                      v8::GCCallbackFlags flags) {
18812  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18813  CHECK_EQ(gc_callbacks_isolate, isolate);
18814  ++epilogue_call_count;
18815}
18816
18817
18818void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18819  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18820  ++prologue_call_count_second;
18821}
18822
18823
18824void PrologueCallbackSecond(v8::Isolate* isolate,
18825                            v8::GCType,
18826                            v8::GCCallbackFlags flags) {
18827  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18828  CHECK_EQ(gc_callbacks_isolate, isolate);
18829  ++prologue_call_count_second;
18830}
18831
18832
18833void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18834  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18835  ++epilogue_call_count_second;
18836}
18837
18838
18839void EpilogueCallbackSecond(v8::Isolate* isolate,
18840                            v8::GCType,
18841                            v8::GCCallbackFlags flags) {
18842  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18843  CHECK_EQ(gc_callbacks_isolate, isolate);
18844  ++epilogue_call_count_second;
18845}
18846
18847
18848void PrologueCallbackAlloc(v8::Isolate* isolate,
18849                           v8::GCType,
18850                           v8::GCCallbackFlags flags) {
18851  v8::HandleScope scope(isolate);
18852
18853  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18854  CHECK_EQ(gc_callbacks_isolate, isolate);
18855  ++prologue_call_count_alloc;
18856
18857  // Simulate full heap to see if we will reenter this callback
18858  SimulateFullSpace(CcTest::heap()->new_space());
18859
18860  Local<Object> obj = Object::New(isolate);
18861  CHECK(!obj.IsEmpty());
18862
18863  CcTest::heap()->CollectAllGarbage(
18864      i::Heap::kAbortIncrementalMarkingMask);
18865}
18866
18867
18868void EpilogueCallbackAlloc(v8::Isolate* isolate,
18869                           v8::GCType,
18870                           v8::GCCallbackFlags flags) {
18871  v8::HandleScope scope(isolate);
18872
18873  CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18874  CHECK_EQ(gc_callbacks_isolate, isolate);
18875  ++epilogue_call_count_alloc;
18876
18877  // Simulate full heap to see if we will reenter this callback
18878  SimulateFullSpace(CcTest::heap()->new_space());
18879
18880  Local<Object> obj = Object::New(isolate);
18881  CHECK(!obj.IsEmpty());
18882
18883  CcTest::heap()->CollectAllGarbage(
18884      i::Heap::kAbortIncrementalMarkingMask);
18885}
18886
18887
18888TEST(GCCallbacksOld) {
18889  LocalContext context;
18890
18891  v8::V8::AddGCPrologueCallback(PrologueCallback);
18892  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18893  CHECK_EQ(0, prologue_call_count);
18894  CHECK_EQ(0, epilogue_call_count);
18895  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18896  CHECK_EQ(1, prologue_call_count);
18897  CHECK_EQ(1, epilogue_call_count);
18898  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18899  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18900  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18901  CHECK_EQ(2, prologue_call_count);
18902  CHECK_EQ(2, epilogue_call_count);
18903  CHECK_EQ(1, prologue_call_count_second);
18904  CHECK_EQ(1, epilogue_call_count_second);
18905  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18906  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18907  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18908  CHECK_EQ(2, prologue_call_count);
18909  CHECK_EQ(2, epilogue_call_count);
18910  CHECK_EQ(2, prologue_call_count_second);
18911  CHECK_EQ(2, epilogue_call_count_second);
18912  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18913  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18914  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18915  CHECK_EQ(2, prologue_call_count);
18916  CHECK_EQ(2, epilogue_call_count);
18917  CHECK_EQ(2, prologue_call_count_second);
18918  CHECK_EQ(2, epilogue_call_count_second);
18919}
18920
18921
18922TEST(GCCallbacks) {
18923  LocalContext context;
18924  v8::Isolate* isolate = context->GetIsolate();
18925  gc_callbacks_isolate = isolate;
18926  isolate->AddGCPrologueCallback(PrologueCallback);
18927  isolate->AddGCEpilogueCallback(EpilogueCallback);
18928  CHECK_EQ(0, prologue_call_count);
18929  CHECK_EQ(0, epilogue_call_count);
18930  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18931  CHECK_EQ(1, prologue_call_count);
18932  CHECK_EQ(1, epilogue_call_count);
18933  isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18934  isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18935  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18936  CHECK_EQ(2, prologue_call_count);
18937  CHECK_EQ(2, epilogue_call_count);
18938  CHECK_EQ(1, prologue_call_count_second);
18939  CHECK_EQ(1, epilogue_call_count_second);
18940  isolate->RemoveGCPrologueCallback(PrologueCallback);
18941  isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18942  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18943  CHECK_EQ(2, prologue_call_count);
18944  CHECK_EQ(2, epilogue_call_count);
18945  CHECK_EQ(2, prologue_call_count_second);
18946  CHECK_EQ(2, epilogue_call_count_second);
18947  isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18948  isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18949  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18950  CHECK_EQ(2, prologue_call_count);
18951  CHECK_EQ(2, epilogue_call_count);
18952  CHECK_EQ(2, prologue_call_count_second);
18953  CHECK_EQ(2, epilogue_call_count_second);
18954
18955  CHECK_EQ(0, prologue_call_count_alloc);
18956  CHECK_EQ(0, epilogue_call_count_alloc);
18957  isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
18958  isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
18959  CcTest::heap()->CollectAllGarbage(
18960      i::Heap::kAbortIncrementalMarkingMask);
18961  CHECK_EQ(1, prologue_call_count_alloc);
18962  CHECK_EQ(1, epilogue_call_count_alloc);
18963  isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
18964  isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
18965}
18966
18967
18968THREADED_TEST(AddToJSFunctionResultCache) {
18969  i::FLAG_stress_compaction = false;
18970  i::FLAG_allow_natives_syntax = true;
18971  v8::HandleScope scope(CcTest::isolate());
18972
18973  LocalContext context;
18974
18975  const char* code =
18976      "(function() {"
18977      "  var key0 = 'a';"
18978      "  var key1 = 'b';"
18979      "  var r0 = %_GetFromCache(0, key0);"
18980      "  var r1 = %_GetFromCache(0, key1);"
18981      "  var r0_ = %_GetFromCache(0, key0);"
18982      "  if (r0 !== r0_)"
18983      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18984      "  var r1_ = %_GetFromCache(0, key1);"
18985      "  if (r1 !== r1_)"
18986      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18987      "  return 'PASSED';"
18988      "})()";
18989  CcTest::heap()->ClearJSFunctionResultCaches();
18990  ExpectString(code, "PASSED");
18991}
18992
18993
18994THREADED_TEST(FillJSFunctionResultCache) {
18995  i::FLAG_allow_natives_syntax = true;
18996  LocalContext context;
18997  v8::HandleScope scope(context->GetIsolate());
18998
18999  const char* code =
19000      "(function() {"
19001      "  var k = 'a';"
19002      "  var r = %_GetFromCache(0, k);"
19003      "  for (var i = 0; i < 16; i++) {"
19004      "    %_GetFromCache(0, 'a' + i);"
19005      "  };"
19006      "  if (r === %_GetFromCache(0, k))"
19007      "    return 'FAILED: k0CacheSize is too small';"
19008      "  return 'PASSED';"
19009      "})()";
19010  CcTest::heap()->ClearJSFunctionResultCaches();
19011  ExpectString(code, "PASSED");
19012}
19013
19014
19015THREADED_TEST(RoundRobinGetFromCache) {
19016  i::FLAG_allow_natives_syntax = true;
19017  LocalContext context;
19018  v8::HandleScope scope(context->GetIsolate());
19019
19020  const char* code =
19021      "(function() {"
19022      "  var keys = [];"
19023      "  for (var i = 0; i < 16; i++) keys.push(i);"
19024      "  var values = [];"
19025      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19026      "  for (var i = 0; i < 16; i++) {"
19027      "    var v = %_GetFromCache(0, keys[i]);"
19028      "    if (v.toString() !== values[i].toString())"
19029      "      return 'Wrong value for ' + "
19030      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
19031      "  };"
19032      "  return 'PASSED';"
19033      "})()";
19034  CcTest::heap()->ClearJSFunctionResultCaches();
19035  ExpectString(code, "PASSED");
19036}
19037
19038
19039THREADED_TEST(ReverseGetFromCache) {
19040  i::FLAG_allow_natives_syntax = true;
19041  LocalContext context;
19042  v8::HandleScope scope(context->GetIsolate());
19043
19044  const char* code =
19045      "(function() {"
19046      "  var keys = [];"
19047      "  for (var i = 0; i < 16; i++) keys.push(i);"
19048      "  var values = [];"
19049      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19050      "  for (var i = 15; i >= 16; i--) {"
19051      "    var v = %_GetFromCache(0, keys[i]);"
19052      "    if (v !== values[i])"
19053      "      return 'Wrong value for ' + "
19054      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
19055      "  };"
19056      "  return 'PASSED';"
19057      "})()";
19058  CcTest::heap()->ClearJSFunctionResultCaches();
19059  ExpectString(code, "PASSED");
19060}
19061
19062
19063THREADED_TEST(TestEviction) {
19064  i::FLAG_allow_natives_syntax = true;
19065  LocalContext context;
19066  v8::HandleScope scope(context->GetIsolate());
19067
19068  const char* code =
19069      "(function() {"
19070      "  for (var i = 0; i < 2*16; i++) {"
19071      "    %_GetFromCache(0, 'a' + i);"
19072      "  };"
19073      "  return 'PASSED';"
19074      "})()";
19075  CcTest::heap()->ClearJSFunctionResultCaches();
19076  ExpectString(code, "PASSED");
19077}
19078
19079
19080THREADED_TEST(TwoByteStringInOneByteCons) {
19081  // See Chromium issue 47824.
19082  LocalContext context;
19083  v8::HandleScope scope(context->GetIsolate());
19084
19085  const char* init_code =
19086      "var str1 = 'abelspendabel';"
19087      "var str2 = str1 + str1 + str1;"
19088      "str2;";
19089  Local<Value> result = CompileRun(init_code);
19090
19091  Local<Value> indexof = CompileRun("str2.indexOf('els')");
19092  Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19093
19094  CHECK(result->IsString());
19095  i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19096  int length = string->length();
19097  CHECK(string->IsOneByteRepresentation());
19098
19099  i::Handle<i::String> flat_string = i::String::Flatten(string);
19100
19101  CHECK(string->IsOneByteRepresentation());
19102  CHECK(flat_string->IsOneByteRepresentation());
19103
19104  // Create external resource.
19105  uint16_t* uc16_buffer = new uint16_t[length + 1];
19106
19107  i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19108  uc16_buffer[length] = 0;
19109
19110  TestResource resource(uc16_buffer);
19111
19112  flat_string->MakeExternal(&resource);
19113
19114  CHECK(flat_string->IsTwoByteRepresentation());
19115
19116  // If the cons string has been short-circuited, skip the following checks.
19117  if (!string.is_identical_to(flat_string)) {
19118    // At this point, we should have a Cons string which is flat and one-byte,
19119    // with a first half that is a two-byte string (although it only contains
19120    // one-byte characters). This is a valid sequence of steps, and it can
19121    // happen in real pages.
19122    CHECK(string->IsOneByteRepresentation());
19123    i::ConsString* cons = i::ConsString::cast(*string);
19124    CHECK_EQ(0, cons->second()->length());
19125    CHECK(cons->first()->IsTwoByteRepresentation());
19126  }
19127
19128  // Check that some string operations work.
19129
19130  // Atom RegExp.
19131  Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19132  CHECK_EQ(6, reresult->Int32Value());
19133
19134  // Nonatom RegExp.
19135  reresult = CompileRun("str2.match(/abe./g).length;");
19136  CHECK_EQ(6, reresult->Int32Value());
19137
19138  reresult = CompileRun("str2.search(/bel/g);");
19139  CHECK_EQ(1, reresult->Int32Value());
19140
19141  reresult = CompileRun("str2.search(/be./g);");
19142  CHECK_EQ(1, reresult->Int32Value());
19143
19144  ExpectTrue("/bel/g.test(str2);");
19145
19146  ExpectTrue("/be./g.test(str2);");
19147
19148  reresult = CompileRun("/bel/g.exec(str2);");
19149  CHECK(!reresult->IsNull());
19150
19151  reresult = CompileRun("/be./g.exec(str2);");
19152  CHECK(!reresult->IsNull());
19153
19154  ExpectString("str2.substring(2, 10);", "elspenda");
19155
19156  ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19157
19158  ExpectString("str2.charAt(2);", "e");
19159
19160  ExpectObject("str2.indexOf('els');", indexof);
19161
19162  ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19163
19164  reresult = CompileRun("str2.charCodeAt(2);");
19165  CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19166}
19167
19168
19169TEST(ContainsOnlyOneByte) {
19170  v8::V8::Initialize();
19171  v8::Isolate* isolate = CcTest::isolate();
19172  v8::HandleScope scope(isolate);
19173  // Make a buffer long enough that it won't automatically be converted.
19174  const int length = 512;
19175  // Ensure word aligned assignment.
19176  const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19177  i::SmartArrayPointer<uintptr_t>
19178  aligned_contents(new uintptr_t[aligned_length]);
19179  uint16_t* string_contents =
19180      reinterpret_cast<uint16_t*>(aligned_contents.get());
19181  // Set to contain only one byte.
19182  for (int i = 0; i < length-1; i++) {
19183    string_contents[i] = 0x41;
19184  }
19185  string_contents[length-1] = 0;
19186  // Simple case.
19187  Handle<String> string =
19188      String::NewExternal(isolate,
19189                          new TestResource(string_contents, NULL, false));
19190  CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19191  // Counter example.
19192  string = String::NewFromTwoByte(isolate, string_contents);
19193  CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19194  // Test left right and balanced cons strings.
19195  Handle<String> base = String::NewFromUtf8(isolate, "a");
19196  Handle<String> left = base;
19197  Handle<String> right = base;
19198  for (int i = 0; i < 1000; i++) {
19199    left = String::Concat(base, left);
19200    right = String::Concat(right, base);
19201  }
19202  Handle<String> balanced = String::Concat(left, base);
19203  balanced = String::Concat(balanced, right);
19204  Handle<String> cons_strings[] = {left, balanced, right};
19205  Handle<String> two_byte =
19206      String::NewExternal(isolate,
19207                          new TestResource(string_contents, NULL, false));
19208  USE(two_byte); USE(cons_strings);
19209  for (size_t i = 0; i < arraysize(cons_strings); i++) {
19210    // Base assumptions.
19211    string = cons_strings[i];
19212    CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19213    // Test left and right concatentation.
19214    string = String::Concat(two_byte, cons_strings[i]);
19215    CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19216    string = String::Concat(cons_strings[i], two_byte);
19217    CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19218  }
19219  // Set bits in different positions
19220  // for strings of different lengths and alignments.
19221  for (int alignment = 0; alignment < 7; alignment++) {
19222    for (int size = 2; alignment + size < length; size *= 2) {
19223      int zero_offset = size + alignment;
19224      string_contents[zero_offset] = 0;
19225      for (int i = 0; i < size; i++) {
19226        int shift = 8 + (i % 7);
19227        string_contents[alignment + i] = 1 << shift;
19228        string = String::NewExternal(
19229            isolate,
19230            new TestResource(string_contents + alignment, NULL, false));
19231        CHECK_EQ(size, string->Length());
19232        CHECK(!string->ContainsOnlyOneByte());
19233        string_contents[alignment + i] = 0x41;
19234      }
19235      string_contents[zero_offset] = 0x41;
19236    }
19237  }
19238}
19239
19240
19241// Failed access check callback that performs a GC on each invocation.
19242void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19243                                 v8::AccessType type,
19244                                 Local<v8::Value> data) {
19245  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19246}
19247
19248
19249TEST(GCInFailedAccessCheckCallback) {
19250  // Install a failed access check callback that performs a GC on each
19251  // invocation. Then force the callback to be called from va
19252
19253  v8::V8::Initialize();
19254  v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19255
19256  v8::Isolate* isolate = CcTest::isolate();
19257  v8::HandleScope scope(isolate);
19258
19259  // Create an ObjectTemplate for global objects and install access
19260  // check callbacks that will block access.
19261  v8::Handle<v8::ObjectTemplate> global_template =
19262      v8::ObjectTemplate::New(isolate);
19263  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19264                                           IndexedGetAccessBlocker,
19265                                           v8::Handle<v8::Value>(),
19266                                           false);
19267
19268  // Create a context and set an x property on it's global object.
19269  LocalContext context0(NULL, global_template);
19270  context0->Global()->Set(v8_str("x"), v8_num(42));
19271  v8::Handle<v8::Object> global0 = context0->Global();
19272
19273  // Create a context with a different security token so that the
19274  // failed access check callback will be called on each access.
19275  LocalContext context1(NULL, global_template);
19276  context1->Global()->Set(v8_str("other"), global0);
19277
19278  // Get property with failed access check.
19279  ExpectUndefined("other.x");
19280
19281  // Get element with failed access check.
19282  ExpectUndefined("other[0]");
19283
19284  // Set property with failed access check.
19285  v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19286  CHECK(result->IsObject());
19287
19288  // Set element with failed access check.
19289  result = CompileRun("other[0] = new Object()");
19290  CHECK(result->IsObject());
19291
19292  // Get property attribute with failed access check.
19293  ExpectFalse("\'x\' in other");
19294
19295  // Get property attribute for element with failed access check.
19296  ExpectFalse("0 in other");
19297
19298  // Delete property.
19299  ExpectFalse("delete other.x");
19300
19301  // Delete element.
19302  CHECK_EQ(false, global0->Delete(0));
19303
19304  // DefineAccessor.
19305  CHECK_EQ(false,
19306           global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19307
19308  // Define JavaScript accessor.
19309  ExpectUndefined("Object.prototype.__defineGetter__.call("
19310                  "    other, \'x\', function() { return 42; })");
19311
19312  // LookupAccessor.
19313  ExpectUndefined("Object.prototype.__lookupGetter__.call("
19314                  "    other, \'x\')");
19315
19316  // HasOwnElement.
19317  ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19318
19319  CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19320  CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19321  CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19322
19323  // Reset the failed access check callback so it does not influence
19324  // the other tests.
19325  v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19326}
19327
19328
19329TEST(IsolateNewDispose) {
19330  v8::Isolate* current_isolate = CcTest::isolate();
19331  v8::Isolate* isolate = v8::Isolate::New();
19332  CHECK(isolate != NULL);
19333  CHECK(current_isolate != isolate);
19334  CHECK(current_isolate == CcTest::isolate());
19335
19336  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19337  last_location = last_message = NULL;
19338  isolate->Dispose();
19339  CHECK_EQ(last_location, NULL);
19340  CHECK_EQ(last_message, NULL);
19341}
19342
19343
19344UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19345  v8::Isolate* isolate = v8::Isolate::New();
19346  {
19347    v8::Isolate::Scope i_scope(isolate);
19348    v8::HandleScope scope(isolate);
19349    LocalContext context(isolate);
19350    // Run something in this isolate.
19351    ExpectTrue("true");
19352    v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19353    last_location = last_message = NULL;
19354    // Still entered, should fail.
19355    isolate->Dispose();
19356    CHECK_NE(last_location, NULL);
19357    CHECK_NE(last_message, NULL);
19358  }
19359  isolate->Dispose();
19360}
19361
19362
19363TEST(RunTwoIsolatesOnSingleThread) {
19364  // Run isolate 1.
19365  v8::Isolate* isolate1 = v8::Isolate::New();
19366  isolate1->Enter();
19367  v8::Persistent<v8::Context> context1;
19368  {
19369    v8::HandleScope scope(isolate1);
19370    context1.Reset(isolate1, Context::New(isolate1));
19371  }
19372
19373  {
19374    v8::HandleScope scope(isolate1);
19375    v8::Local<v8::Context> context =
19376        v8::Local<v8::Context>::New(isolate1, context1);
19377    v8::Context::Scope context_scope(context);
19378    // Run something in new isolate.
19379    CompileRun("var foo = 'isolate 1';");
19380    ExpectString("function f() { return foo; }; f()", "isolate 1");
19381  }
19382
19383  // Run isolate 2.
19384  v8::Isolate* isolate2 = v8::Isolate::New();
19385  v8::Persistent<v8::Context> context2;
19386
19387  {
19388    v8::Isolate::Scope iscope(isolate2);
19389    v8::HandleScope scope(isolate2);
19390    context2.Reset(isolate2, Context::New(isolate2));
19391    v8::Local<v8::Context> context =
19392        v8::Local<v8::Context>::New(isolate2, context2);
19393    v8::Context::Scope context_scope(context);
19394
19395    // Run something in new isolate.
19396    CompileRun("var foo = 'isolate 2';");
19397    ExpectString("function f() { return foo; }; f()", "isolate 2");
19398  }
19399
19400  {
19401    v8::HandleScope scope(isolate1);
19402    v8::Local<v8::Context> context =
19403        v8::Local<v8::Context>::New(isolate1, context1);
19404    v8::Context::Scope context_scope(context);
19405    // Now again in isolate 1
19406    ExpectString("function f() { return foo; }; f()", "isolate 1");
19407  }
19408
19409  isolate1->Exit();
19410
19411  // Run some stuff in default isolate.
19412  v8::Persistent<v8::Context> context_default;
19413  {
19414    v8::Isolate* isolate = CcTest::isolate();
19415    v8::Isolate::Scope iscope(isolate);
19416    v8::HandleScope scope(isolate);
19417    context_default.Reset(isolate, Context::New(isolate));
19418  }
19419
19420  {
19421    v8::HandleScope scope(CcTest::isolate());
19422    v8::Local<v8::Context> context =
19423        v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19424    v8::Context::Scope context_scope(context);
19425    // Variables in other isolates should be not available, verify there
19426    // is an exception.
19427    ExpectTrue("function f() {"
19428               "  try {"
19429               "    foo;"
19430               "    return false;"
19431               "  } catch(e) {"
19432               "    return true;"
19433               "  }"
19434               "};"
19435               "var isDefaultIsolate = true;"
19436               "f()");
19437  }
19438
19439  isolate1->Enter();
19440
19441  {
19442    v8::Isolate::Scope iscope(isolate2);
19443    v8::HandleScope scope(isolate2);
19444    v8::Local<v8::Context> context =
19445        v8::Local<v8::Context>::New(isolate2, context2);
19446    v8::Context::Scope context_scope(context);
19447    ExpectString("function f() { return foo; }; f()", "isolate 2");
19448  }
19449
19450  {
19451    v8::HandleScope scope(v8::Isolate::GetCurrent());
19452    v8::Local<v8::Context> context =
19453        v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19454    v8::Context::Scope context_scope(context);
19455    ExpectString("function f() { return foo; }; f()", "isolate 1");
19456  }
19457
19458  {
19459    v8::Isolate::Scope iscope(isolate2);
19460    context2.Reset();
19461  }
19462
19463  context1.Reset();
19464  isolate1->Exit();
19465
19466  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19467  last_location = last_message = NULL;
19468
19469  isolate1->Dispose();
19470  CHECK_EQ(last_location, NULL);
19471  CHECK_EQ(last_message, NULL);
19472
19473  isolate2->Dispose();
19474  CHECK_EQ(last_location, NULL);
19475  CHECK_EQ(last_message, NULL);
19476
19477  // Check that default isolate still runs.
19478  {
19479    v8::HandleScope scope(CcTest::isolate());
19480    v8::Local<v8::Context> context =
19481        v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19482    v8::Context::Scope context_scope(context);
19483    ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19484  }
19485}
19486
19487
19488static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19489  v8::Isolate::Scope isolate_scope(isolate);
19490  v8::HandleScope scope(isolate);
19491  LocalContext context(isolate);
19492  i::ScopedVector<char> code(1024);
19493  i::SNPrintF(code, "function fib(n) {"
19494                    "  if (n <= 2) return 1;"
19495                    "  return fib(n-1) + fib(n-2);"
19496                    "}"
19497                    "fib(%d)", limit);
19498  Local<Value> value = CompileRun(code.start());
19499  CHECK(value->IsNumber());
19500  return static_cast<int>(value->NumberValue());
19501}
19502
19503class IsolateThread : public v8::base::Thread {
19504 public:
19505  explicit IsolateThread(int fib_limit)
19506      : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
19507
19508  void Run() {
19509    v8::Isolate* isolate = v8::Isolate::New();
19510    result_ = CalcFibonacci(isolate, fib_limit_);
19511    isolate->Dispose();
19512  }
19513
19514  int result() { return result_; }
19515
19516 private:
19517  int fib_limit_;
19518  int result_;
19519};
19520
19521
19522TEST(MultipleIsolatesOnIndividualThreads) {
19523  IsolateThread thread1(21);
19524  IsolateThread thread2(12);
19525
19526  // Compute some fibonacci numbers on 3 threads in 3 isolates.
19527  thread1.Start();
19528  thread2.Start();
19529
19530  int result1 = CalcFibonacci(CcTest::isolate(), 21);
19531  int result2 = CalcFibonacci(CcTest::isolate(), 12);
19532
19533  thread1.Join();
19534  thread2.Join();
19535
19536  // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19537  // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19538  CHECK_EQ(result1, 10946);
19539  CHECK_EQ(result2, 144);
19540  CHECK_EQ(result1, thread1.result());
19541  CHECK_EQ(result2, thread2.result());
19542}
19543
19544
19545TEST(IsolateDifferentContexts) {
19546  v8::Isolate* isolate = v8::Isolate::New();
19547  Local<v8::Context> context;
19548  {
19549    v8::Isolate::Scope isolate_scope(isolate);
19550    v8::HandleScope handle_scope(isolate);
19551    context = v8::Context::New(isolate);
19552    v8::Context::Scope context_scope(context);
19553    Local<Value> v = CompileRun("2");
19554    CHECK(v->IsNumber());
19555    CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19556  }
19557  {
19558    v8::Isolate::Scope isolate_scope(isolate);
19559    v8::HandleScope handle_scope(isolate);
19560    context = v8::Context::New(isolate);
19561    v8::Context::Scope context_scope(context);
19562    Local<Value> v = CompileRun("22");
19563    CHECK(v->IsNumber());
19564    CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19565  }
19566  isolate->Dispose();
19567}
19568
19569class InitDefaultIsolateThread : public v8::base::Thread {
19570 public:
19571  enum TestCase {
19572    SetResourceConstraints,
19573    SetFatalHandler,
19574    SetCounterFunction,
19575    SetCreateHistogramFunction,
19576    SetAddHistogramSampleFunction
19577  };
19578
19579  explicit InitDefaultIsolateThread(TestCase testCase)
19580      : Thread(Options("InitDefaultIsolateThread")),
19581        testCase_(testCase),
19582        result_(false) {}
19583
19584  void Run() {
19585    v8::Isolate::CreateParams create_params;
19586    switch (testCase_) {
19587      case SetResourceConstraints: {
19588        create_params.constraints.set_max_semi_space_size(1);
19589        create_params.constraints.set_max_old_space_size(4);
19590        break;
19591      }
19592      default:
19593        break;
19594    }
19595    v8::Isolate* isolate = v8::Isolate::New(create_params);
19596    isolate->Enter();
19597    switch (testCase_) {
19598      case SetResourceConstraints:
19599        // Already handled in pre-Isolate-creation block.
19600        break;
19601
19602      case SetFatalHandler:
19603        v8::V8::SetFatalErrorHandler(NULL);
19604        break;
19605
19606      case SetCounterFunction:
19607        CcTest::isolate()->SetCounterFunction(NULL);
19608        break;
19609
19610      case SetCreateHistogramFunction:
19611        CcTest::isolate()->SetCreateHistogramFunction(NULL);
19612        break;
19613
19614      case SetAddHistogramSampleFunction:
19615        CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
19616        break;
19617    }
19618    isolate->Exit();
19619    isolate->Dispose();
19620    result_ = true;
19621  }
19622
19623  bool result() { return result_; }
19624
19625 private:
19626  TestCase testCase_;
19627  bool result_;
19628};
19629
19630
19631static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19632  InitDefaultIsolateThread thread(testCase);
19633  thread.Start();
19634  thread.Join();
19635  CHECK_EQ(thread.result(), true);
19636}
19637
19638
19639TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19640  InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19641}
19642
19643
19644TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19645  InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19646}
19647
19648
19649TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19650  InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19651}
19652
19653
19654TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19655  InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19656}
19657
19658
19659TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19660  InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19661}
19662
19663
19664TEST(StringCheckMultipleContexts) {
19665  const char* code =
19666      "(function() { return \"a\".charAt(0); })()";
19667
19668  {
19669    // Run the code twice in the first context to initialize the call IC.
19670    LocalContext context1;
19671    v8::HandleScope scope(context1->GetIsolate());
19672    ExpectString(code, "a");
19673    ExpectString(code, "a");
19674  }
19675
19676  {
19677    // Change the String.prototype in the second context and check
19678    // that the right function gets called.
19679    LocalContext context2;
19680    v8::HandleScope scope(context2->GetIsolate());
19681    CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19682    ExpectString(code, "not a");
19683  }
19684}
19685
19686
19687TEST(NumberCheckMultipleContexts) {
19688  const char* code =
19689      "(function() { return (42).toString(); })()";
19690
19691  {
19692    // Run the code twice in the first context to initialize the call IC.
19693    LocalContext context1;
19694    v8::HandleScope scope(context1->GetIsolate());
19695    ExpectString(code, "42");
19696    ExpectString(code, "42");
19697  }
19698
19699  {
19700    // Change the Number.prototype in the second context and check
19701    // that the right function gets called.
19702    LocalContext context2;
19703    v8::HandleScope scope(context2->GetIsolate());
19704    CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19705    ExpectString(code, "not 42");
19706  }
19707}
19708
19709
19710TEST(BooleanCheckMultipleContexts) {
19711  const char* code =
19712      "(function() { return true.toString(); })()";
19713
19714  {
19715    // Run the code twice in the first context to initialize the call IC.
19716    LocalContext context1;
19717    v8::HandleScope scope(context1->GetIsolate());
19718    ExpectString(code, "true");
19719    ExpectString(code, "true");
19720  }
19721
19722  {
19723    // Change the Boolean.prototype in the second context and check
19724    // that the right function gets called.
19725    LocalContext context2;
19726    v8::HandleScope scope(context2->GetIsolate());
19727    CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19728    ExpectString(code, "");
19729  }
19730}
19731
19732
19733TEST(DontDeleteCellLoadIC) {
19734  const char* function_code =
19735      "function readCell() { while (true) { return cell; } }";
19736
19737  {
19738    // Run the code twice in the first context to initialize the load
19739    // IC for a don't delete cell.
19740    LocalContext context1;
19741    v8::HandleScope scope(context1->GetIsolate());
19742    CompileRun("var cell = \"first\";");
19743    ExpectBoolean("delete cell", false);
19744    CompileRun(function_code);
19745    ExpectString("readCell()", "first");
19746    ExpectString("readCell()", "first");
19747  }
19748
19749  {
19750    // Use a deletable cell in the second context.
19751    LocalContext context2;
19752    v8::HandleScope scope(context2->GetIsolate());
19753    CompileRun("cell = \"second\";");
19754    CompileRun(function_code);
19755    ExpectString("readCell()", "second");
19756    ExpectBoolean("delete cell", true);
19757    ExpectString("(function() {"
19758                 "  try {"
19759                 "    return readCell();"
19760                 "  } catch(e) {"
19761                 "    return e.toString();"
19762                 "  }"
19763                 "})()",
19764                 "ReferenceError: cell is not defined");
19765    CompileRun("cell = \"new_second\";");
19766    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19767    ExpectString("readCell()", "new_second");
19768    ExpectString("readCell()", "new_second");
19769  }
19770}
19771
19772
19773TEST(DontDeleteCellLoadICForceDelete) {
19774  const char* function_code =
19775      "function readCell() { while (true) { return cell; } }";
19776
19777  // Run the code twice to initialize the load IC for a don't delete
19778  // cell.
19779  LocalContext context;
19780  v8::HandleScope scope(context->GetIsolate());
19781  CompileRun("var cell = \"value\";");
19782  ExpectBoolean("delete cell", false);
19783  CompileRun(function_code);
19784  ExpectString("readCell()", "value");
19785  ExpectString("readCell()", "value");
19786
19787  // Delete the cell using the API and check the inlined code works
19788  // correctly.
19789  CHECK(context->Global()->ForceDelete(v8_str("cell")));
19790  ExpectString("(function() {"
19791               "  try {"
19792               "    return readCell();"
19793               "  } catch(e) {"
19794               "    return e.toString();"
19795               "  }"
19796               "})()",
19797               "ReferenceError: cell is not defined");
19798}
19799
19800
19801TEST(DontDeleteCellLoadICAPI) {
19802  const char* function_code =
19803      "function readCell() { while (true) { return cell; } }";
19804
19805  // Run the code twice to initialize the load IC for a don't delete
19806  // cell created using the API.
19807  LocalContext context;
19808  v8::HandleScope scope(context->GetIsolate());
19809  context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
19810  ExpectBoolean("delete cell", false);
19811  CompileRun(function_code);
19812  ExpectString("readCell()", "value");
19813  ExpectString("readCell()", "value");
19814
19815  // Delete the cell using the API and check the inlined code works
19816  // correctly.
19817  CHECK(context->Global()->ForceDelete(v8_str("cell")));
19818  ExpectString("(function() {"
19819               "  try {"
19820               "    return readCell();"
19821               "  } catch(e) {"
19822               "    return e.toString();"
19823               "  }"
19824               "})()",
19825               "ReferenceError: cell is not defined");
19826}
19827
19828
19829class Visitor42 : public v8::PersistentHandleVisitor {
19830 public:
19831  explicit Visitor42(v8::Persistent<v8::Object>* object)
19832      : counter_(0), object_(object) { }
19833
19834  virtual void VisitPersistentHandle(Persistent<Value>* value,
19835                                     uint16_t class_id) {
19836    if (class_id != 42) return;
19837    CHECK_EQ(42, value->WrapperClassId());
19838    v8::Isolate* isolate = CcTest::isolate();
19839    v8::HandleScope handle_scope(isolate);
19840    v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19841    v8::Handle<v8::Value> object =
19842        v8::Local<v8::Object>::New(isolate, *object_);
19843    CHECK(handle->IsObject());
19844    CHECK_EQ(Handle<Object>::Cast(handle), object);
19845    ++counter_;
19846  }
19847
19848  int counter_;
19849  v8::Persistent<v8::Object>* object_;
19850};
19851
19852
19853TEST(PersistentHandleVisitor) {
19854  LocalContext context;
19855  v8::Isolate* isolate = context->GetIsolate();
19856  v8::HandleScope scope(isolate);
19857  v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19858  CHECK_EQ(0, object.WrapperClassId());
19859  object.SetWrapperClassId(42);
19860  CHECK_EQ(42, object.WrapperClassId());
19861
19862  Visitor42 visitor(&object);
19863  v8::V8::VisitHandlesWithClassIds(&visitor);
19864  CHECK_EQ(1, visitor.counter_);
19865
19866  object.Reset();
19867}
19868
19869
19870TEST(WrapperClassId) {
19871  LocalContext context;
19872  v8::Isolate* isolate = context->GetIsolate();
19873  v8::HandleScope scope(isolate);
19874  v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19875  CHECK_EQ(0, object.WrapperClassId());
19876  object.SetWrapperClassId(65535);
19877  CHECK_EQ(65535, object.WrapperClassId());
19878  object.Reset();
19879}
19880
19881
19882TEST(PersistentHandleInNewSpaceVisitor) {
19883  LocalContext context;
19884  v8::Isolate* isolate = context->GetIsolate();
19885  v8::HandleScope scope(isolate);
19886  v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19887  CHECK_EQ(0, object1.WrapperClassId());
19888  object1.SetWrapperClassId(42);
19889  CHECK_EQ(42, object1.WrapperClassId());
19890
19891  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19892  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19893
19894  v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19895  CHECK_EQ(0, object2.WrapperClassId());
19896  object2.SetWrapperClassId(42);
19897  CHECK_EQ(42, object2.WrapperClassId());
19898
19899  Visitor42 visitor(&object2);
19900  v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19901  CHECK_EQ(1, visitor.counter_);
19902
19903  object1.Reset();
19904  object2.Reset();
19905}
19906
19907
19908TEST(RegExp) {
19909  LocalContext context;
19910  v8::HandleScope scope(context->GetIsolate());
19911
19912  v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19913  CHECK(re->IsRegExp());
19914  CHECK(re->GetSource()->Equals(v8_str("foo")));
19915  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19916
19917  re = v8::RegExp::New(v8_str("bar"),
19918                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19919                                                      v8::RegExp::kGlobal));
19920  CHECK(re->IsRegExp());
19921  CHECK(re->GetSource()->Equals(v8_str("bar")));
19922  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19923           static_cast<int>(re->GetFlags()));
19924
19925  re = v8::RegExp::New(v8_str("baz"),
19926                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19927                                                      v8::RegExp::kMultiline));
19928  CHECK(re->IsRegExp());
19929  CHECK(re->GetSource()->Equals(v8_str("baz")));
19930  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19931           static_cast<int>(re->GetFlags()));
19932
19933  re = CompileRun("/quux/").As<v8::RegExp>();
19934  CHECK(re->IsRegExp());
19935  CHECK(re->GetSource()->Equals(v8_str("quux")));
19936  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19937
19938  re = CompileRun("/quux/gm").As<v8::RegExp>();
19939  CHECK(re->IsRegExp());
19940  CHECK(re->GetSource()->Equals(v8_str("quux")));
19941  CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19942           static_cast<int>(re->GetFlags()));
19943
19944  // Override the RegExp constructor and check the API constructor
19945  // still works.
19946  CompileRun("RegExp = function() {}");
19947
19948  re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19949  CHECK(re->IsRegExp());
19950  CHECK(re->GetSource()->Equals(v8_str("foobar")));
19951  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19952
19953  re = v8::RegExp::New(v8_str("foobarbaz"),
19954                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19955                                                      v8::RegExp::kMultiline));
19956  CHECK(re->IsRegExp());
19957  CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19958  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19959           static_cast<int>(re->GetFlags()));
19960
19961  context->Global()->Set(v8_str("re"), re);
19962  ExpectTrue("re.test('FoobarbaZ')");
19963
19964  // RegExps are objects on which you can set properties.
19965  re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19966  v8::Handle<v8::Value> value(CompileRun("re.property"));
19967  CHECK_EQ(32, value->Int32Value());
19968
19969  v8::TryCatch try_catch;
19970  re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19971  CHECK(re.IsEmpty());
19972  CHECK(try_catch.HasCaught());
19973  context->Global()->Set(v8_str("ex"), try_catch.Exception());
19974  ExpectTrue("ex instanceof SyntaxError");
19975}
19976
19977
19978THREADED_TEST(Equals) {
19979  LocalContext localContext;
19980  v8::HandleScope handleScope(localContext->GetIsolate());
19981
19982  v8::Handle<v8::Object> globalProxy = localContext->Global();
19983  v8::Handle<Value> global = globalProxy->GetPrototype();
19984
19985  CHECK(global->StrictEquals(global));
19986  CHECK(!global->StrictEquals(globalProxy));
19987  CHECK(!globalProxy->StrictEquals(global));
19988  CHECK(globalProxy->StrictEquals(globalProxy));
19989
19990  CHECK(global->Equals(global));
19991  CHECK(!global->Equals(globalProxy));
19992  CHECK(!globalProxy->Equals(global));
19993  CHECK(globalProxy->Equals(globalProxy));
19994}
19995
19996
19997static void Getter(v8::Local<v8::String> property,
19998                   const v8::PropertyCallbackInfo<v8::Value>& info ) {
19999  info.GetReturnValue().Set(v8_str("42!"));
20000}
20001
20002
20003static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20004  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
20005  result->Set(0, v8_str("universalAnswer"));
20006  info.GetReturnValue().Set(result);
20007}
20008
20009
20010TEST(NamedEnumeratorAndForIn) {
20011  LocalContext context;
20012  v8::Isolate* isolate = context->GetIsolate();
20013  v8::HandleScope handle_scope(isolate);
20014  v8::Context::Scope context_scope(context.local());
20015
20016  v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
20017  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
20018  context->Global()->Set(v8_str("o"), tmpl->NewInstance());
20019  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
20020        "var result = []; for (var k in o) result.push(k); result"));
20021  CHECK_EQ(1, result->Length());
20022  CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
20023}
20024
20025
20026TEST(DefinePropertyPostDetach) {
20027  LocalContext context;
20028  v8::HandleScope scope(context->GetIsolate());
20029  v8::Handle<v8::Object> proxy = context->Global();
20030  v8::Handle<v8::Function> define_property =
20031      CompileRun("(function() {"
20032                 "  Object.defineProperty("
20033                 "    this,"
20034                 "    1,"
20035                 "    { configurable: true, enumerable: true, value: 3 });"
20036                 "})").As<Function>();
20037  context->DetachGlobal();
20038  define_property->Call(proxy, 0, NULL);
20039}
20040
20041
20042static void InstallContextId(v8::Handle<Context> context, int id) {
20043  Context::Scope scope(context);
20044  CompileRun("Object.prototype").As<Object>()->
20045      Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
20046}
20047
20048
20049static void CheckContextId(v8::Handle<Object> object, int expected) {
20050  CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
20051}
20052
20053
20054THREADED_TEST(CreationContext) {
20055  v8::Isolate* isolate = CcTest::isolate();
20056  HandleScope handle_scope(isolate);
20057  Handle<Context> context1 = Context::New(isolate);
20058  InstallContextId(context1, 1);
20059  Handle<Context> context2 = Context::New(isolate);
20060  InstallContextId(context2, 2);
20061  Handle<Context> context3 = Context::New(isolate);
20062  InstallContextId(context3, 3);
20063
20064  Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20065
20066  Local<Object> object1;
20067  Local<Function> func1;
20068  {
20069    Context::Scope scope(context1);
20070    object1 = Object::New(isolate);
20071    func1 = tmpl->GetFunction();
20072  }
20073
20074  Local<Object> object2;
20075  Local<Function> func2;
20076  {
20077    Context::Scope scope(context2);
20078    object2 = Object::New(isolate);
20079    func2 = tmpl->GetFunction();
20080  }
20081
20082  Local<Object> instance1;
20083  Local<Object> instance2;
20084
20085  {
20086    Context::Scope scope(context3);
20087    instance1 = func1->NewInstance();
20088    instance2 = func2->NewInstance();
20089  }
20090
20091  CHECK(object1->CreationContext() == context1);
20092  CheckContextId(object1, 1);
20093  CHECK(func1->CreationContext() == context1);
20094  CheckContextId(func1, 1);
20095  CHECK(instance1->CreationContext() == context1);
20096  CheckContextId(instance1, 1);
20097  CHECK(object2->CreationContext() == context2);
20098  CheckContextId(object2, 2);
20099  CHECK(func2->CreationContext() == context2);
20100  CheckContextId(func2, 2);
20101  CHECK(instance2->CreationContext() == context2);
20102  CheckContextId(instance2, 2);
20103
20104  {
20105    Context::Scope scope(context1);
20106    CHECK(object1->CreationContext() == context1);
20107    CheckContextId(object1, 1);
20108    CHECK(func1->CreationContext() == context1);
20109    CheckContextId(func1, 1);
20110    CHECK(instance1->CreationContext() == context1);
20111    CheckContextId(instance1, 1);
20112    CHECK(object2->CreationContext() == context2);
20113    CheckContextId(object2, 2);
20114    CHECK(func2->CreationContext() == context2);
20115    CheckContextId(func2, 2);
20116    CHECK(instance2->CreationContext() == context2);
20117    CheckContextId(instance2, 2);
20118  }
20119
20120  {
20121    Context::Scope scope(context2);
20122    CHECK(object1->CreationContext() == context1);
20123    CheckContextId(object1, 1);
20124    CHECK(func1->CreationContext() == context1);
20125    CheckContextId(func1, 1);
20126    CHECK(instance1->CreationContext() == context1);
20127    CheckContextId(instance1, 1);
20128    CHECK(object2->CreationContext() == context2);
20129    CheckContextId(object2, 2);
20130    CHECK(func2->CreationContext() == context2);
20131    CheckContextId(func2, 2);
20132    CHECK(instance2->CreationContext() == context2);
20133    CheckContextId(instance2, 2);
20134  }
20135}
20136
20137
20138THREADED_TEST(CreationContextOfJsFunction) {
20139  HandleScope handle_scope(CcTest::isolate());
20140  Handle<Context> context = Context::New(CcTest::isolate());
20141  InstallContextId(context, 1);
20142
20143  Local<Object> function;
20144  {
20145    Context::Scope scope(context);
20146    function = CompileRun("function foo() {}; foo").As<Object>();
20147  }
20148
20149  CHECK(function->CreationContext() == context);
20150  CheckContextId(function, 1);
20151}
20152
20153
20154void HasOwnPropertyIndexedPropertyGetter(
20155    uint32_t index,
20156    const v8::PropertyCallbackInfo<v8::Value>& info) {
20157  if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20158}
20159
20160
20161void HasOwnPropertyNamedPropertyGetter(
20162    Local<String> property,
20163    const v8::PropertyCallbackInfo<v8::Value>& info) {
20164  if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20165}
20166
20167
20168void HasOwnPropertyIndexedPropertyQuery(
20169    uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20170  if (index == 42) info.GetReturnValue().Set(1);
20171}
20172
20173
20174void HasOwnPropertyNamedPropertyQuery(
20175    Local<String> property,
20176    const v8::PropertyCallbackInfo<v8::Integer>& info) {
20177  if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20178}
20179
20180
20181void HasOwnPropertyNamedPropertyQuery2(
20182    Local<String> property,
20183    const v8::PropertyCallbackInfo<v8::Integer>& info) {
20184  if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20185}
20186
20187
20188void HasOwnPropertyAccessorGetter(
20189    Local<String> property,
20190    const v8::PropertyCallbackInfo<v8::Value>& info) {
20191  info.GetReturnValue().Set(v8_str("yes"));
20192}
20193
20194
20195TEST(HasOwnProperty) {
20196  LocalContext env;
20197  v8::Isolate* isolate = env->GetIsolate();
20198  v8::HandleScope scope(isolate);
20199  { // Check normal properties and defined getters.
20200    Handle<Value> value = CompileRun(
20201        "function Foo() {"
20202        "    this.foo = 11;"
20203        "    this.__defineGetter__('baz', function() { return 1; });"
20204        "};"
20205        "function Bar() { "
20206        "    this.bar = 13;"
20207        "    this.__defineGetter__('bla', function() { return 2; });"
20208        "};"
20209        "Bar.prototype = new Foo();"
20210        "new Bar();");
20211    CHECK(value->IsObject());
20212    Handle<Object> object = value->ToObject();
20213    CHECK(object->Has(v8_str("foo")));
20214    CHECK(!object->HasOwnProperty(v8_str("foo")));
20215    CHECK(object->HasOwnProperty(v8_str("bar")));
20216    CHECK(object->Has(v8_str("baz")));
20217    CHECK(!object->HasOwnProperty(v8_str("baz")));
20218    CHECK(object->HasOwnProperty(v8_str("bla")));
20219  }
20220  { // Check named getter interceptors.
20221    Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20222    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20223    Handle<Object> instance = templ->NewInstance();
20224    CHECK(!instance->HasOwnProperty(v8_str("42")));
20225    CHECK(instance->HasOwnProperty(v8_str("foo")));
20226    CHECK(!instance->HasOwnProperty(v8_str("bar")));
20227  }
20228  { // Check indexed getter interceptors.
20229    Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20230    templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20231    Handle<Object> instance = templ->NewInstance();
20232    CHECK(instance->HasOwnProperty(v8_str("42")));
20233    CHECK(!instance->HasOwnProperty(v8_str("43")));
20234    CHECK(!instance->HasOwnProperty(v8_str("foo")));
20235  }
20236  { // Check named query interceptors.
20237    Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20238    templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20239    Handle<Object> instance = templ->NewInstance();
20240    CHECK(instance->HasOwnProperty(v8_str("foo")));
20241    CHECK(!instance->HasOwnProperty(v8_str("bar")));
20242  }
20243  { // Check indexed query interceptors.
20244    Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20245    templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20246    Handle<Object> instance = templ->NewInstance();
20247    CHECK(instance->HasOwnProperty(v8_str("42")));
20248    CHECK(!instance->HasOwnProperty(v8_str("41")));
20249  }
20250  { // Check callbacks.
20251    Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20252    templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20253    Handle<Object> instance = templ->NewInstance();
20254    CHECK(instance->HasOwnProperty(v8_str("foo")));
20255    CHECK(!instance->HasOwnProperty(v8_str("bar")));
20256  }
20257  { // Check that query wins on disagreement.
20258    Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20259    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20260                                   0,
20261                                   HasOwnPropertyNamedPropertyQuery2);
20262    Handle<Object> instance = templ->NewInstance();
20263    CHECK(!instance->HasOwnProperty(v8_str("foo")));
20264    CHECK(instance->HasOwnProperty(v8_str("bar")));
20265  }
20266}
20267
20268
20269TEST(IndexedInterceptorWithStringProto) {
20270  v8::Isolate* isolate = CcTest::isolate();
20271  v8::HandleScope scope(isolate);
20272  Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20273  templ->SetIndexedPropertyHandler(NULL,
20274                                   NULL,
20275                                   HasOwnPropertyIndexedPropertyQuery);
20276  LocalContext context;
20277  context->Global()->Set(v8_str("obj"), templ->NewInstance());
20278  CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20279  // These should be intercepted.
20280  CHECK(CompileRun("42 in obj")->BooleanValue());
20281  CHECK(CompileRun("'42' in obj")->BooleanValue());
20282  // These should fall through to the String prototype.
20283  CHECK(CompileRun("0 in obj")->BooleanValue());
20284  CHECK(CompileRun("'0' in obj")->BooleanValue());
20285  // And these should both fail.
20286  CHECK(!CompileRun("32 in obj")->BooleanValue());
20287  CHECK(!CompileRun("'32' in obj")->BooleanValue());
20288}
20289
20290
20291void CheckCodeGenerationAllowed() {
20292  Handle<Value> result = CompileRun("eval('42')");
20293  CHECK_EQ(42, result->Int32Value());
20294  result = CompileRun("(function(e) { return e('42'); })(eval)");
20295  CHECK_EQ(42, result->Int32Value());
20296  result = CompileRun("var f = new Function('return 42'); f()");
20297  CHECK_EQ(42, result->Int32Value());
20298}
20299
20300
20301void CheckCodeGenerationDisallowed() {
20302  TryCatch try_catch;
20303
20304  Handle<Value> result = CompileRun("eval('42')");
20305  CHECK(result.IsEmpty());
20306  CHECK(try_catch.HasCaught());
20307  try_catch.Reset();
20308
20309  result = CompileRun("(function(e) { return e('42'); })(eval)");
20310  CHECK(result.IsEmpty());
20311  CHECK(try_catch.HasCaught());
20312  try_catch.Reset();
20313
20314  result = CompileRun("var f = new Function('return 42'); f()");
20315  CHECK(result.IsEmpty());
20316  CHECK(try_catch.HasCaught());
20317}
20318
20319
20320bool CodeGenerationAllowed(Local<Context> context) {
20321  ApiTestFuzzer::Fuzz();
20322  return true;
20323}
20324
20325
20326bool CodeGenerationDisallowed(Local<Context> context) {
20327  ApiTestFuzzer::Fuzz();
20328  return false;
20329}
20330
20331
20332THREADED_TEST(AllowCodeGenFromStrings) {
20333  LocalContext context;
20334  v8::HandleScope scope(context->GetIsolate());
20335
20336  // eval and the Function constructor allowed by default.
20337  CHECK(context->IsCodeGenerationFromStringsAllowed());
20338  CheckCodeGenerationAllowed();
20339
20340  // Disallow eval and the Function constructor.
20341  context->AllowCodeGenerationFromStrings(false);
20342  CHECK(!context->IsCodeGenerationFromStringsAllowed());
20343  CheckCodeGenerationDisallowed();
20344
20345  // Allow again.
20346  context->AllowCodeGenerationFromStrings(true);
20347  CheckCodeGenerationAllowed();
20348
20349  // Disallow but setting a global callback that will allow the calls.
20350  context->AllowCodeGenerationFromStrings(false);
20351  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20352  CHECK(!context->IsCodeGenerationFromStringsAllowed());
20353  CheckCodeGenerationAllowed();
20354
20355  // Set a callback that disallows the code generation.
20356  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20357  CHECK(!context->IsCodeGenerationFromStringsAllowed());
20358  CheckCodeGenerationDisallowed();
20359}
20360
20361
20362TEST(SetErrorMessageForCodeGenFromStrings) {
20363  LocalContext context;
20364  v8::HandleScope scope(context->GetIsolate());
20365  TryCatch try_catch;
20366
20367  Handle<String> message = v8_str("Message") ;
20368  Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20369  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20370  context->AllowCodeGenerationFromStrings(false);
20371  context->SetErrorMessageForCodeGenerationFromStrings(message);
20372  Handle<Value> result = CompileRun("eval('42')");
20373  CHECK(result.IsEmpty());
20374  CHECK(try_catch.HasCaught());
20375  Handle<String> actual_message = try_catch.Message()->Get();
20376  CHECK(expected_message->Equals(actual_message));
20377}
20378
20379
20380static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20381}
20382
20383
20384THREADED_TEST(CallAPIFunctionOnNonObject) {
20385  LocalContext context;
20386  v8::Isolate* isolate = context->GetIsolate();
20387  v8::HandleScope scope(isolate);
20388  Handle<FunctionTemplate> templ =
20389      v8::FunctionTemplate::New(isolate, NonObjectThis);
20390  Handle<Function> function = templ->GetFunction();
20391  context->Global()->Set(v8_str("f"), function);
20392  TryCatch try_catch;
20393  CompileRun("f.call(2)");
20394}
20395
20396
20397// Regression test for issue 1470.
20398THREADED_TEST(ReadOnlyIndexedProperties) {
20399  v8::Isolate* isolate = CcTest::isolate();
20400  v8::HandleScope scope(isolate);
20401  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20402
20403  LocalContext context;
20404  Local<v8::Object> obj = templ->NewInstance();
20405  context->Global()->Set(v8_str("obj"), obj);
20406  obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20407  obj->Set(v8_str("1"), v8_str("foobar"));
20408  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20409  obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20410  obj->Set(v8_num(2), v8_str("foobar"));
20411  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20412
20413  // Test non-smi case.
20414  obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20415  obj->Set(v8_str("2000000000"), v8_str("foobar"));
20416  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20417}
20418
20419
20420THREADED_TEST(Regress1516) {
20421  LocalContext context;
20422  v8::HandleScope scope(context->GetIsolate());
20423
20424  { v8::HandleScope temp_scope(context->GetIsolate());
20425    CompileRun("({'a': 0})");
20426  }
20427
20428  int elements;
20429  { i::MapCache* map_cache =
20430        i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20431    elements = map_cache->NumberOfElements();
20432    CHECK_LE(1, elements);
20433  }
20434
20435  CcTest::heap()->CollectAllGarbage(
20436      i::Heap::kAbortIncrementalMarkingMask);
20437  { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20438    if (raw_map_cache != CcTest::heap()->undefined_value()) {
20439      i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20440      CHECK_GT(elements, map_cache->NumberOfElements());
20441    }
20442  }
20443}
20444
20445
20446static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20447                                                Local<Value> name,
20448                                                v8::AccessType type,
20449                                                Local<Value> data) {
20450  // Only block read access to __proto__.
20451  if (type == v8::ACCESS_GET &&
20452      name->IsString() &&
20453      name->ToString()->Length() == 9 &&
20454      name->ToString()->Utf8Length() == 9) {
20455    char buffer[10];
20456    CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20457    return strncmp(buffer, "__proto__", 9) != 0;
20458  }
20459
20460  return true;
20461}
20462
20463
20464THREADED_TEST(Regress93759) {
20465  v8::Isolate* isolate = CcTest::isolate();
20466  HandleScope scope(isolate);
20467
20468  // Template for object with security check.
20469  Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20470  // We don't do indexing, so any callback can be used for that.
20471  no_proto_template->SetAccessCheckCallbacks(
20472      BlockProtoNamedSecurityTestCallback,
20473      IndexedSecurityTestCallback);
20474
20475  // Templates for objects with hidden prototypes and possibly security check.
20476  Local<FunctionTemplate> hidden_proto_template =
20477      v8::FunctionTemplate::New(isolate);
20478  hidden_proto_template->SetHiddenPrototype(true);
20479
20480  Local<FunctionTemplate> protected_hidden_proto_template =
20481      v8::FunctionTemplate::New(isolate);
20482  protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20483      BlockProtoNamedSecurityTestCallback,
20484      IndexedSecurityTestCallback);
20485  protected_hidden_proto_template->SetHiddenPrototype(true);
20486
20487  // Context for "foreign" objects used in test.
20488  Local<Context> context = v8::Context::New(isolate);
20489  context->Enter();
20490
20491  // Plain object, no security check.
20492  Local<Object> simple_object = Object::New(isolate);
20493
20494  // Object with explicit security check.
20495  Local<Object> protected_object =
20496      no_proto_template->NewInstance();
20497
20498  // JSGlobalProxy object, always have security check.
20499  Local<Object> proxy_object =
20500      context->Global();
20501
20502  // Global object, the  prototype of proxy_object. No security checks.
20503  Local<Object> global_object =
20504      proxy_object->GetPrototype()->ToObject();
20505
20506  // Hidden prototype without security check.
20507  Local<Object> hidden_prototype =
20508      hidden_proto_template->GetFunction()->NewInstance();
20509  Local<Object> object_with_hidden =
20510    Object::New(isolate);
20511  object_with_hidden->SetPrototype(hidden_prototype);
20512
20513  // Hidden prototype with security check on the hidden prototype.
20514  Local<Object> protected_hidden_prototype =
20515      protected_hidden_proto_template->GetFunction()->NewInstance();
20516  Local<Object> object_with_protected_hidden =
20517    Object::New(isolate);
20518  object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20519
20520  context->Exit();
20521
20522  // Template for object for second context. Values to test are put on it as
20523  // properties.
20524  Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20525  global_template->Set(v8_str("simple"), simple_object);
20526  global_template->Set(v8_str("protected"), protected_object);
20527  global_template->Set(v8_str("global"), global_object);
20528  global_template->Set(v8_str("proxy"), proxy_object);
20529  global_template->Set(v8_str("hidden"), object_with_hidden);
20530  global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20531
20532  LocalContext context2(NULL, global_template);
20533
20534  Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20535  CHECK(result1->Equals(simple_object->GetPrototype()));
20536
20537  Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20538  CHECK(result2.IsEmpty());
20539
20540  Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20541  CHECK(result3->Equals(global_object->GetPrototype()));
20542
20543  Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20544  CHECK(result4.IsEmpty());
20545
20546  Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20547  CHECK(result5->Equals(
20548      object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20549
20550  Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20551  CHECK(result6.IsEmpty());
20552}
20553
20554
20555THREADED_TEST(Regress125988) {
20556  v8::HandleScope scope(CcTest::isolate());
20557  Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20558  AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20559  LocalContext env;
20560  env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20561  CompileRun("var a = new Object();"
20562             "var b = new Intercept();"
20563             "var c = new Object();"
20564             "c.__proto__ = b;"
20565             "b.__proto__ = a;"
20566             "a.x = 23;"
20567             "for (var i = 0; i < 3; i++) c.x;");
20568  ExpectBoolean("c.hasOwnProperty('x')", false);
20569  ExpectInt32("c.x", 23);
20570  CompileRun("a.y = 42;"
20571             "for (var i = 0; i < 3; i++) c.x;");
20572  ExpectBoolean("c.hasOwnProperty('x')", false);
20573  ExpectInt32("c.x", 23);
20574  ExpectBoolean("c.hasOwnProperty('y')", false);
20575  ExpectInt32("c.y", 42);
20576}
20577
20578
20579static void TestReceiver(Local<Value> expected_result,
20580                         Local<Value> expected_receiver,
20581                         const char* code) {
20582  Local<Value> result = CompileRun(code);
20583  CHECK(result->IsObject());
20584  CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20585  CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20586}
20587
20588
20589THREADED_TEST(ForeignFunctionReceiver) {
20590  v8::Isolate* isolate = CcTest::isolate();
20591  HandleScope scope(isolate);
20592
20593  // Create two contexts with different "id" properties ('i' and 'o').
20594  // Call a function both from its own context and from a the foreign
20595  // context, and see what "this" is bound to (returning both "this"
20596  // and "this.id" for comparison).
20597
20598  Local<Context> foreign_context = v8::Context::New(isolate);
20599  foreign_context->Enter();
20600  Local<Value> foreign_function =
20601    CompileRun("function func() { return { 0: this.id, "
20602               "                           1: this, "
20603               "                           toString: function() { "
20604               "                               return this[0];"
20605               "                           }"
20606               "                         };"
20607               "}"
20608               "var id = 'i';"
20609               "func;");
20610  CHECK(foreign_function->IsFunction());
20611  foreign_context->Exit();
20612
20613  LocalContext context;
20614
20615  Local<String> password = v8_str("Password");
20616  // Don't get hit by security checks when accessing foreign_context's
20617  // global receiver (aka. global proxy).
20618  context->SetSecurityToken(password);
20619  foreign_context->SetSecurityToken(password);
20620
20621  Local<String> i = v8_str("i");
20622  Local<String> o = v8_str("o");
20623  Local<String> id = v8_str("id");
20624
20625  CompileRun("function ownfunc() { return { 0: this.id, "
20626             "                              1: this, "
20627             "                              toString: function() { "
20628             "                                  return this[0];"
20629             "                              }"
20630             "                             };"
20631             "}"
20632             "var id = 'o';"
20633             "ownfunc");
20634  context->Global()->Set(v8_str("func"), foreign_function);
20635
20636  // Sanity check the contexts.
20637  CHECK(i->Equals(foreign_context->Global()->Get(id)));
20638  CHECK(o->Equals(context->Global()->Get(id)));
20639
20640  // Checking local function's receiver.
20641  // Calling function using its call/apply methods.
20642  TestReceiver(o, context->Global(), "ownfunc.call()");
20643  TestReceiver(o, context->Global(), "ownfunc.apply()");
20644  // Making calls through built-in functions.
20645  TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20646  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20647  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20648  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20649  // Calling with environment record as base.
20650  TestReceiver(o, context->Global(), "ownfunc()");
20651  // Calling with no base.
20652  TestReceiver(o, context->Global(), "(1,ownfunc)()");
20653
20654  // Checking foreign function return value.
20655  // Calling function using its call/apply methods.
20656  TestReceiver(i, foreign_context->Global(), "func.call()");
20657  TestReceiver(i, foreign_context->Global(), "func.apply()");
20658  // Calling function using another context's call/apply methods.
20659  TestReceiver(i, foreign_context->Global(),
20660               "Function.prototype.call.call(func)");
20661  TestReceiver(i, foreign_context->Global(),
20662               "Function.prototype.call.apply(func)");
20663  TestReceiver(i, foreign_context->Global(),
20664               "Function.prototype.apply.call(func)");
20665  TestReceiver(i, foreign_context->Global(),
20666               "Function.prototype.apply.apply(func)");
20667  // Making calls through built-in functions.
20668  TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20669  // ToString(func()) is func()[0], i.e., the returned this.id.
20670  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20671  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20672  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20673
20674  // Calling with environment record as base.
20675  TestReceiver(i, foreign_context->Global(), "func()");
20676  // Calling with no base.
20677  TestReceiver(i, foreign_context->Global(), "(1,func)()");
20678}
20679
20680
20681uint8_t callback_fired = 0;
20682
20683
20684void CallCompletedCallback1() {
20685  v8::base::OS::Print("Firing callback 1.\n");
20686  callback_fired ^= 1;  // Toggle first bit.
20687}
20688
20689
20690void CallCompletedCallback2() {
20691  v8::base::OS::Print("Firing callback 2.\n");
20692  callback_fired ^= 2;  // Toggle second bit.
20693}
20694
20695
20696void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20697  int32_t level = args[0]->Int32Value();
20698  if (level < 3) {
20699    level++;
20700    v8::base::OS::Print("Entering recursion level %d.\n", level);
20701    char script[64];
20702    i::Vector<char> script_vector(script, sizeof(script));
20703    i::SNPrintF(script_vector, "recursion(%d)", level);
20704    CompileRun(script_vector.start());
20705    v8::base::OS::Print("Leaving recursion level %d.\n", level);
20706    CHECK_EQ(0, callback_fired);
20707  } else {
20708    v8::base::OS::Print("Recursion ends.\n");
20709    CHECK_EQ(0, callback_fired);
20710  }
20711}
20712
20713
20714TEST(CallCompletedCallback) {
20715  LocalContext env;
20716  v8::HandleScope scope(env->GetIsolate());
20717  v8::Handle<v8::FunctionTemplate> recursive_runtime =
20718      v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20719  env->Global()->Set(v8_str("recursion"),
20720                     recursive_runtime->GetFunction());
20721  // Adding the same callback a second time has no effect.
20722  env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20723  env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20724  env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20725  v8::base::OS::Print("--- Script (1) ---\n");
20726  Local<Script> script = v8::Script::Compile(
20727      v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20728  script->Run();
20729  CHECK_EQ(3, callback_fired);
20730
20731  v8::base::OS::Print("\n--- Script (2) ---\n");
20732  callback_fired = 0;
20733  env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20734  script->Run();
20735  CHECK_EQ(2, callback_fired);
20736
20737  v8::base::OS::Print("\n--- Function ---\n");
20738  callback_fired = 0;
20739  Local<Function> recursive_function =
20740      Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20741  v8::Handle<Value> args[] = { v8_num(0) };
20742  recursive_function->Call(env->Global(), 1, args);
20743  CHECK_EQ(2, callback_fired);
20744}
20745
20746
20747void CallCompletedCallbackNoException() {
20748  v8::HandleScope scope(CcTest::isolate());
20749  CompileRun("1+1;");
20750}
20751
20752
20753void CallCompletedCallbackException() {
20754  v8::HandleScope scope(CcTest::isolate());
20755  CompileRun("throw 'second exception';");
20756}
20757
20758
20759TEST(CallCompletedCallbackOneException) {
20760  LocalContext env;
20761  v8::HandleScope scope(env->GetIsolate());
20762  env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20763  CompileRun("throw 'exception';");
20764}
20765
20766
20767TEST(CallCompletedCallbackTwoExceptions) {
20768  LocalContext env;
20769  v8::HandleScope scope(env->GetIsolate());
20770  env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20771  CompileRun("throw 'first exception';");
20772}
20773
20774
20775static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20776  v8::HandleScope scope(info.GetIsolate());
20777  CompileRun("ext1Calls++;");
20778}
20779
20780
20781static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20782  v8::HandleScope scope(info.GetIsolate());
20783  CompileRun("ext2Calls++;");
20784}
20785
20786
20787void* g_passed_to_three = NULL;
20788
20789
20790static void MicrotaskThree(void* data) {
20791  g_passed_to_three = data;
20792}
20793
20794
20795TEST(EnqueueMicrotask) {
20796  LocalContext env;
20797  v8::HandleScope scope(env->GetIsolate());
20798  CompileRun(
20799      "var ext1Calls = 0;"
20800      "var ext2Calls = 0;");
20801  CompileRun("1+1;");
20802  CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20803  CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20804
20805  env->GetIsolate()->EnqueueMicrotask(
20806      Function::New(env->GetIsolate(), MicrotaskOne));
20807  CompileRun("1+1;");
20808  CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20809  CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20810
20811  env->GetIsolate()->EnqueueMicrotask(
20812      Function::New(env->GetIsolate(), MicrotaskOne));
20813  env->GetIsolate()->EnqueueMicrotask(
20814      Function::New(env->GetIsolate(), MicrotaskTwo));
20815  CompileRun("1+1;");
20816  CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20817  CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20818
20819  env->GetIsolate()->EnqueueMicrotask(
20820      Function::New(env->GetIsolate(), MicrotaskTwo));
20821  CompileRun("1+1;");
20822  CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20823  CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20824
20825  CompileRun("1+1;");
20826  CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20827  CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20828
20829  g_passed_to_three = NULL;
20830  env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
20831  CompileRun("1+1;");
20832  CHECK_EQ(NULL, g_passed_to_three);
20833  CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20834  CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20835
20836  int dummy;
20837  env->GetIsolate()->EnqueueMicrotask(
20838      Function::New(env->GetIsolate(), MicrotaskOne));
20839  env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
20840  env->GetIsolate()->EnqueueMicrotask(
20841      Function::New(env->GetIsolate(), MicrotaskTwo));
20842  CompileRun("1+1;");
20843  CHECK_EQ(&dummy, g_passed_to_three);
20844  CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
20845  CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20846  g_passed_to_three = NULL;
20847}
20848
20849
20850static void MicrotaskExceptionOne(
20851    const v8::FunctionCallbackInfo<Value>& info) {
20852  v8::HandleScope scope(info.GetIsolate());
20853  CompileRun("exception1Calls++;");
20854  info.GetIsolate()->ThrowException(
20855      v8::Exception::Error(v8_str("first")));
20856}
20857
20858
20859static void MicrotaskExceptionTwo(
20860    const v8::FunctionCallbackInfo<Value>& info) {
20861  v8::HandleScope scope(info.GetIsolate());
20862  CompileRun("exception2Calls++;");
20863  info.GetIsolate()->ThrowException(
20864      v8::Exception::Error(v8_str("second")));
20865}
20866
20867
20868TEST(RunMicrotasksIgnoresThrownExceptions) {
20869  LocalContext env;
20870  v8::Isolate* isolate = env->GetIsolate();
20871  v8::HandleScope scope(isolate);
20872  CompileRun(
20873      "var exception1Calls = 0;"
20874      "var exception2Calls = 0;");
20875  isolate->EnqueueMicrotask(
20876      Function::New(isolate, MicrotaskExceptionOne));
20877  isolate->EnqueueMicrotask(
20878      Function::New(isolate, MicrotaskExceptionTwo));
20879  TryCatch try_catch;
20880  CompileRun("1+1;");
20881  CHECK(!try_catch.HasCaught());
20882  CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
20883  CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
20884}
20885
20886
20887TEST(SetAutorunMicrotasks) {
20888  LocalContext env;
20889  v8::HandleScope scope(env->GetIsolate());
20890  CompileRun(
20891      "var ext1Calls = 0;"
20892      "var ext2Calls = 0;");
20893  CompileRun("1+1;");
20894  CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20895  CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20896
20897  env->GetIsolate()->EnqueueMicrotask(
20898      Function::New(env->GetIsolate(), MicrotaskOne));
20899  CompileRun("1+1;");
20900  CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20901  CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20902
20903  env->GetIsolate()->SetAutorunMicrotasks(false);
20904  env->GetIsolate()->EnqueueMicrotask(
20905      Function::New(env->GetIsolate(), MicrotaskOne));
20906  env->GetIsolate()->EnqueueMicrotask(
20907      Function::New(env->GetIsolate(), MicrotaskTwo));
20908  CompileRun("1+1;");
20909  CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20910  CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20911
20912  env->GetIsolate()->RunMicrotasks();
20913  CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20914  CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20915
20916  env->GetIsolate()->EnqueueMicrotask(
20917      Function::New(env->GetIsolate(), MicrotaskTwo));
20918  CompileRun("1+1;");
20919  CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20920  CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20921
20922  env->GetIsolate()->RunMicrotasks();
20923  CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20924  CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20925
20926  env->GetIsolate()->SetAutorunMicrotasks(true);
20927  env->GetIsolate()->EnqueueMicrotask(
20928      Function::New(env->GetIsolate(), MicrotaskTwo));
20929  CompileRun("1+1;");
20930  CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20931  CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20932
20933  env->GetIsolate()->EnqueueMicrotask(
20934      Function::New(env->GetIsolate(), MicrotaskTwo));
20935  {
20936    v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
20937    CompileRun("1+1;");
20938    CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20939    CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20940  }
20941
20942  CompileRun("1+1;");
20943  CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20944  CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
20945}
20946
20947
20948TEST(RunMicrotasksWithoutEnteringContext) {
20949  v8::Isolate* isolate = CcTest::isolate();
20950  HandleScope handle_scope(isolate);
20951  isolate->SetAutorunMicrotasks(false);
20952  Handle<Context> context = Context::New(isolate);
20953  {
20954    Context::Scope context_scope(context);
20955    CompileRun("var ext1Calls = 0;");
20956    isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
20957  }
20958  isolate->RunMicrotasks();
20959  {
20960    Context::Scope context_scope(context);
20961    CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20962  }
20963  isolate->SetAutorunMicrotasks(true);
20964}
20965
20966
20967static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
20968  v8::DebugEvent event = event_details.GetEvent();
20969  if (event != v8::Break) return;
20970  Handle<Object> exec_state = event_details.GetExecutionState();
20971  Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
20972  CompileRun("function f(id) { new FrameDetails(id, 0); }");
20973  Handle<Function> fun = Handle<Function>::Cast(
20974      CcTest::global()->Get(v8_str("f"))->ToObject());
20975  fun->Call(CcTest::global(), 1, &break_id);
20976}
20977
20978
20979TEST(Regress385349) {
20980  i::FLAG_allow_natives_syntax = true;
20981  v8::Isolate* isolate = CcTest::isolate();
20982  HandleScope handle_scope(isolate);
20983  isolate->SetAutorunMicrotasks(false);
20984  Handle<Context> context = Context::New(isolate);
20985  v8::Debug::SetDebugEventListener(DebugEventInObserver);
20986  {
20987    Context::Scope context_scope(context);
20988    CompileRun("var obj = {};"
20989               "Object.observe(obj, function(changes) { debugger; });"
20990               "obj.a = 0;");
20991  }
20992  isolate->RunMicrotasks();
20993  isolate->SetAutorunMicrotasks(true);
20994  v8::Debug::SetDebugEventListener(NULL);
20995}
20996
20997
20998#ifdef DEBUG
20999static int probes_counter = 0;
21000static int misses_counter = 0;
21001static int updates_counter = 0;
21002
21003
21004static int* LookupCounter(const char* name) {
21005  if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
21006    return &probes_counter;
21007  } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
21008    return &misses_counter;
21009  } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
21010    return &updates_counter;
21011  }
21012  return NULL;
21013}
21014
21015
21016static const char* kMegamorphicTestProgram =
21017    "function ClassA() { };"
21018    "function ClassB() { };"
21019    "ClassA.prototype.foo = function() { };"
21020    "ClassB.prototype.foo = function() { };"
21021    "function fooify(obj) { obj.foo(); };"
21022    "var a = new ClassA();"
21023    "var b = new ClassB();"
21024    "for (var i = 0; i < 10000; i++) {"
21025    "  fooify(a);"
21026    "  fooify(b);"
21027    "}";
21028#endif
21029
21030
21031static void StubCacheHelper(bool primary) {
21032#ifdef DEBUG
21033  i::FLAG_native_code_counters = true;
21034  if (primary) {
21035    i::FLAG_test_primary_stub_cache = true;
21036  } else {
21037    i::FLAG_test_secondary_stub_cache = true;
21038  }
21039  i::FLAG_crankshaft = false;
21040  LocalContext env;
21041  env->GetIsolate()->SetCounterFunction(LookupCounter);
21042  v8::HandleScope scope(env->GetIsolate());
21043  int initial_probes = probes_counter;
21044  int initial_misses = misses_counter;
21045  int initial_updates = updates_counter;
21046  CompileRun(kMegamorphicTestProgram);
21047  int probes = probes_counter - initial_probes;
21048  int misses = misses_counter - initial_misses;
21049  int updates = updates_counter - initial_updates;
21050  CHECK_LT(updates, 10);
21051  CHECK_LT(misses, 10);
21052  // TODO(verwaest): Update this test to overflow the degree of polymorphism
21053  // before megamorphism. The number of probes will only work once we teach the
21054  // serializer to embed references to counters in the stubs, given that the
21055  // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
21056  CHECK_GE(probes, 0);
21057#endif
21058}
21059
21060
21061TEST(SecondaryStubCache) {
21062  StubCacheHelper(true);
21063}
21064
21065
21066TEST(PrimaryStubCache) {
21067  StubCacheHelper(false);
21068}
21069
21070
21071#ifdef DEBUG
21072static int cow_arrays_created_runtime = 0;
21073
21074
21075static int* LookupCounterCOWArrays(const char* name) {
21076  if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
21077    return &cow_arrays_created_runtime;
21078  }
21079  return NULL;
21080}
21081#endif
21082
21083
21084TEST(CheckCOWArraysCreatedRuntimeCounter) {
21085#ifdef DEBUG
21086  i::FLAG_native_code_counters = true;
21087  LocalContext env;
21088  env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
21089  v8::HandleScope scope(env->GetIsolate());
21090  int initial_cow_arrays = cow_arrays_created_runtime;
21091  CompileRun("var o = [1, 2, 3];");
21092  CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
21093  CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
21094  CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
21095  CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
21096  CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
21097#endif
21098}
21099
21100
21101TEST(StaticGetters) {
21102  LocalContext context;
21103  i::Factory* factory = CcTest::i_isolate()->factory();
21104  v8::Isolate* isolate = CcTest::isolate();
21105  v8::HandleScope scope(isolate);
21106  i::Handle<i::Object> undefined_value = factory->undefined_value();
21107  CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21108  i::Handle<i::Object> null_value = factory->null_value();
21109  CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21110  i::Handle<i::Object> true_value = factory->true_value();
21111  CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21112  i::Handle<i::Object> false_value = factory->false_value();
21113  CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21114}
21115
21116
21117UNINITIALIZED_TEST(IsolateEmbedderData) {
21118  CcTest::DisableAutomaticDispose();
21119  v8::Isolate* isolate = v8::Isolate::New();
21120  isolate->Enter();
21121  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21122  for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21123    CHECK_EQ(NULL, isolate->GetData(slot));
21124    CHECK_EQ(NULL, i_isolate->GetData(slot));
21125  }
21126  for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21127    void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21128    isolate->SetData(slot, data);
21129  }
21130  for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21131    void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21132    CHECK_EQ(data, isolate->GetData(slot));
21133    CHECK_EQ(data, i_isolate->GetData(slot));
21134  }
21135  for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21136    void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21137    isolate->SetData(slot, data);
21138  }
21139  for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21140    void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21141    CHECK_EQ(data, isolate->GetData(slot));
21142    CHECK_EQ(data, i_isolate->GetData(slot));
21143  }
21144  isolate->Exit();
21145  isolate->Dispose();
21146}
21147
21148
21149TEST(StringEmpty) {
21150  LocalContext context;
21151  i::Factory* factory = CcTest::i_isolate()->factory();
21152  v8::Isolate* isolate = CcTest::isolate();
21153  v8::HandleScope scope(isolate);
21154  i::Handle<i::Object> empty_string = factory->empty_string();
21155  CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21156}
21157
21158
21159static int instance_checked_getter_count = 0;
21160static void InstanceCheckedGetter(
21161    Local<String> name,
21162    const v8::PropertyCallbackInfo<v8::Value>& info) {
21163  CHECK_EQ(name, v8_str("foo"));
21164  instance_checked_getter_count++;
21165  info.GetReturnValue().Set(v8_num(11));
21166}
21167
21168
21169static int instance_checked_setter_count = 0;
21170static void InstanceCheckedSetter(Local<String> name,
21171                      Local<Value> value,
21172                      const v8::PropertyCallbackInfo<void>& info) {
21173  CHECK_EQ(name, v8_str("foo"));
21174  CHECK_EQ(value, v8_num(23));
21175  instance_checked_setter_count++;
21176}
21177
21178
21179static void CheckInstanceCheckedResult(int getters, int setters,
21180                                       bool expects_callbacks,
21181                                       TryCatch* try_catch) {
21182  if (expects_callbacks) {
21183    CHECK(!try_catch->HasCaught());
21184    CHECK_EQ(getters, instance_checked_getter_count);
21185    CHECK_EQ(setters, instance_checked_setter_count);
21186  } else {
21187    CHECK(try_catch->HasCaught());
21188    CHECK_EQ(0, instance_checked_getter_count);
21189    CHECK_EQ(0, instance_checked_setter_count);
21190  }
21191  try_catch->Reset();
21192}
21193
21194
21195static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21196  instance_checked_getter_count = 0;
21197  instance_checked_setter_count = 0;
21198  TryCatch try_catch;
21199
21200  // Test path through generic runtime code.
21201  CompileRun("obj.foo");
21202  CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21203  CompileRun("obj.foo = 23");
21204  CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21205
21206  // Test path through generated LoadIC and StoredIC.
21207  CompileRun("function test_get(o) { o.foo; }"
21208             "test_get(obj);");
21209  CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21210  CompileRun("test_get(obj);");
21211  CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21212  CompileRun("test_get(obj);");
21213  CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21214  CompileRun("function test_set(o) { o.foo = 23; }"
21215             "test_set(obj);");
21216  CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21217  CompileRun("test_set(obj);");
21218  CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21219  CompileRun("test_set(obj);");
21220  CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21221
21222  // Test path through optimized code.
21223  CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21224             "test_get(obj);");
21225  CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21226  CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21227             "test_set(obj);");
21228  CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21229
21230  // Cleanup so that closures start out fresh in next check.
21231  CompileRun("%DeoptimizeFunction(test_get);"
21232             "%ClearFunctionTypeFeedback(test_get);"
21233             "%DeoptimizeFunction(test_set);"
21234             "%ClearFunctionTypeFeedback(test_set);");
21235}
21236
21237
21238THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21239  v8::internal::FLAG_allow_natives_syntax = true;
21240  LocalContext context;
21241  v8::HandleScope scope(context->GetIsolate());
21242
21243  Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21244  Local<ObjectTemplate> inst = templ->InstanceTemplate();
21245  inst->SetAccessor(v8_str("foo"),
21246                    InstanceCheckedGetter, InstanceCheckedSetter,
21247                    Handle<Value>(),
21248                    v8::DEFAULT,
21249                    v8::None,
21250                    v8::AccessorSignature::New(context->GetIsolate(), templ));
21251  context->Global()->Set(v8_str("f"), templ->GetFunction());
21252
21253  printf("Testing positive ...\n");
21254  CompileRun("var obj = new f();");
21255  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21256  CheckInstanceCheckedAccessors(true);
21257
21258  printf("Testing negative ...\n");
21259  CompileRun("var obj = {};"
21260             "obj.__proto__ = new f();");
21261  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21262  CheckInstanceCheckedAccessors(false);
21263}
21264
21265
21266THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21267  v8::internal::FLAG_allow_natives_syntax = true;
21268  LocalContext context;
21269  v8::HandleScope scope(context->GetIsolate());
21270
21271  Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21272  Local<ObjectTemplate> inst = templ->InstanceTemplate();
21273  AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21274  inst->SetAccessor(v8_str("foo"),
21275                    InstanceCheckedGetter, InstanceCheckedSetter,
21276                    Handle<Value>(),
21277                    v8::DEFAULT,
21278                    v8::None,
21279                    v8::AccessorSignature::New(context->GetIsolate(), templ));
21280  context->Global()->Set(v8_str("f"), templ->GetFunction());
21281
21282  printf("Testing positive ...\n");
21283  CompileRun("var obj = new f();");
21284  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21285  CheckInstanceCheckedAccessors(true);
21286
21287  printf("Testing negative ...\n");
21288  CompileRun("var obj = {};"
21289             "obj.__proto__ = new f();");
21290  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21291  CheckInstanceCheckedAccessors(false);
21292}
21293
21294
21295THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21296  v8::internal::FLAG_allow_natives_syntax = true;
21297  LocalContext context;
21298  v8::HandleScope scope(context->GetIsolate());
21299
21300  Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21301  Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21302  proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
21303                     InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
21304                     v8::None,
21305                     v8::AccessorSignature::New(context->GetIsolate(), templ));
21306  context->Global()->Set(v8_str("f"), templ->GetFunction());
21307
21308  printf("Testing positive ...\n");
21309  CompileRun("var obj = new f();");
21310  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21311  CheckInstanceCheckedAccessors(true);
21312
21313  printf("Testing negative ...\n");
21314  CompileRun("var obj = {};"
21315             "obj.__proto__ = new f();");
21316  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21317  CheckInstanceCheckedAccessors(false);
21318
21319  printf("Testing positive with modified prototype chain ...\n");
21320  CompileRun("var obj = new f();"
21321             "var pro = {};"
21322             "pro.__proto__ = obj.__proto__;"
21323             "obj.__proto__ = pro;");
21324  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21325  CheckInstanceCheckedAccessors(true);
21326}
21327
21328
21329TEST(TryFinallyMessage) {
21330  LocalContext context;
21331  v8::HandleScope scope(context->GetIsolate());
21332  {
21333    // Test that the original error message is not lost if there is a
21334    // recursive call into Javascript is done in the finally block, e.g. to
21335    // initialize an IC. (crbug.com/129171)
21336    TryCatch try_catch;
21337    const char* trigger_ic =
21338        "try {                      \n"
21339        "  throw new Error('test'); \n"
21340        "} finally {                \n"
21341        "  var x = 0;               \n"
21342        "  x++;                     \n"  // Trigger an IC initialization here.
21343        "}                          \n";
21344    CompileRun(trigger_ic);
21345    CHECK(try_catch.HasCaught());
21346    Local<Message> message = try_catch.Message();
21347    CHECK(!message.IsEmpty());
21348    CHECK_EQ(2, message->GetLineNumber());
21349  }
21350
21351  {
21352    // Test that the original exception message is indeed overwritten if
21353    // a new error is thrown in the finally block.
21354    TryCatch try_catch;
21355    const char* throw_again =
21356        "try {                       \n"
21357        "  throw new Error('test');  \n"
21358        "} finally {                 \n"
21359        "  var x = 0;                \n"
21360        "  x++;                      \n"
21361        "  throw new Error('again'); \n"  // This is the new uncaught error.
21362        "}                           \n";
21363    CompileRun(throw_again);
21364    CHECK(try_catch.HasCaught());
21365    Local<Message> message = try_catch.Message();
21366    CHECK(!message.IsEmpty());
21367    CHECK_EQ(6, message->GetLineNumber());
21368  }
21369}
21370
21371
21372static void Helper137002(bool do_store,
21373                         bool polymorphic,
21374                         bool remove_accessor,
21375                         bool interceptor) {
21376  LocalContext context;
21377  Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21378  if (interceptor) {
21379    templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21380  } else {
21381    templ->SetAccessor(v8_str("foo"),
21382                       GetterWhichReturns42,
21383                       SetterWhichSetsYOnThisTo23);
21384  }
21385  context->Global()->Set(v8_str("obj"), templ->NewInstance());
21386
21387  // Turn monomorphic on slow object with native accessor, then turn
21388  // polymorphic, finally optimize to create negative lookup and fail.
21389  CompileRun(do_store ?
21390             "function f(x) { x.foo = void 0; }" :
21391             "function f(x) { return x.foo; }");
21392  CompileRun("obj.y = void 0;");
21393  if (!interceptor) {
21394    CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21395  }
21396  CompileRun("obj.__proto__ = null;"
21397             "f(obj); f(obj); f(obj);");
21398  if (polymorphic) {
21399    CompileRun("f({});");
21400  }
21401  CompileRun("obj.y = void 0;"
21402             "%OptimizeFunctionOnNextCall(f);");
21403  if (remove_accessor) {
21404    CompileRun("delete obj.foo;");
21405  }
21406  CompileRun("var result = f(obj);");
21407  if (do_store) {
21408    CompileRun("result = obj.y;");
21409  }
21410  if (remove_accessor && !interceptor) {
21411    CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21412  } else {
21413    CHECK_EQ(do_store ? 23 : 42,
21414             context->Global()->Get(v8_str("result"))->Int32Value());
21415  }
21416}
21417
21418
21419THREADED_TEST(Regress137002a) {
21420  i::FLAG_allow_natives_syntax = true;
21421  i::FLAG_compilation_cache = false;
21422  v8::HandleScope scope(CcTest::isolate());
21423  for (int i = 0; i < 16; i++) {
21424    Helper137002(i & 8, i & 4, i & 2, i & 1);
21425  }
21426}
21427
21428
21429THREADED_TEST(Regress137002b) {
21430  i::FLAG_allow_natives_syntax = true;
21431  LocalContext context;
21432  v8::Isolate* isolate = context->GetIsolate();
21433  v8::HandleScope scope(isolate);
21434  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21435  templ->SetAccessor(v8_str("foo"),
21436                     GetterWhichReturns42,
21437                     SetterWhichSetsYOnThisTo23);
21438  context->Global()->Set(v8_str("obj"), templ->NewInstance());
21439
21440  // Turn monomorphic on slow object with native accessor, then just
21441  // delete the property and fail.
21442  CompileRun("function load(x) { return x.foo; }"
21443             "function store(x) { x.foo = void 0; }"
21444             "function keyed_load(x, key) { return x[key]; }"
21445             // Second version of function has a different source (add void 0)
21446             // so that it does not share code with the first version.  This
21447             // ensures that the ICs are monomorphic.
21448             "function load2(x) { void 0; return x.foo; }"
21449             "function store2(x) { void 0; x.foo = void 0; }"
21450             "function keyed_load2(x, key) { void 0; return x[key]; }"
21451
21452             "obj.y = void 0;"
21453             "obj.__proto__ = null;"
21454             "var subobj = {};"
21455             "subobj.y = void 0;"
21456             "subobj.__proto__ = obj;"
21457             "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21458
21459             // Make the ICs monomorphic.
21460             "load(obj); load(obj);"
21461             "load2(subobj); load2(subobj);"
21462             "store(obj); store(obj);"
21463             "store2(subobj); store2(subobj);"
21464             "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21465             "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21466
21467             // Actually test the shiny new ICs and better not crash. This
21468             // serves as a regression test for issue 142088 as well.
21469             "load(obj);"
21470             "load2(subobj);"
21471             "store(obj);"
21472             "store2(subobj);"
21473             "keyed_load(obj, 'foo');"
21474             "keyed_load2(subobj, 'foo');"
21475
21476             // Delete the accessor.  It better not be called any more now.
21477             "delete obj.foo;"
21478             "obj.y = void 0;"
21479             "subobj.y = void 0;"
21480
21481             "var load_result = load(obj);"
21482             "var load_result2 = load2(subobj);"
21483             "var keyed_load_result = keyed_load(obj, 'foo');"
21484             "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21485             "store(obj);"
21486             "store2(subobj);"
21487             "var y_from_obj = obj.y;"
21488             "var y_from_subobj = subobj.y;");
21489  CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21490  CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21491  CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21492  CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21493  CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21494  CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21495}
21496
21497
21498THREADED_TEST(Regress142088) {
21499  i::FLAG_allow_natives_syntax = true;
21500  LocalContext context;
21501  v8::Isolate* isolate = context->GetIsolate();
21502  v8::HandleScope scope(isolate);
21503  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21504  templ->SetAccessor(v8_str("foo"),
21505                     GetterWhichReturns42,
21506                     SetterWhichSetsYOnThisTo23);
21507  context->Global()->Set(v8_str("obj"), templ->NewInstance());
21508
21509  CompileRun("function load(x) { return x.foo; }"
21510             "var o = Object.create(obj);"
21511             "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21512             "load(o); load(o); load(o); load(o);");
21513}
21514
21515
21516THREADED_TEST(Regress3337) {
21517  LocalContext context;
21518  v8::Isolate* isolate = context->GetIsolate();
21519  v8::HandleScope scope(isolate);
21520  Local<v8::Object> o1 = Object::New(isolate);
21521  Local<v8::Object> o2 = Object::New(isolate);
21522  i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
21523  i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
21524  CHECK(io1->map() == io2->map());
21525  o1->SetIndexedPropertiesToExternalArrayData(
21526      NULL, v8::kExternalUint32Array, 0);
21527  o2->SetIndexedPropertiesToExternalArrayData(
21528      NULL, v8::kExternalUint32Array, 0);
21529  CHECK(io1->map() == io2->map());
21530}
21531
21532
21533THREADED_TEST(Regress137496) {
21534  i::FLAG_expose_gc = true;
21535  LocalContext context;
21536  v8::HandleScope scope(context->GetIsolate());
21537
21538  // Compile a try-finally clause where the finally block causes a GC
21539  // while there still is a message pending for external reporting.
21540  TryCatch try_catch;
21541  try_catch.SetVerbose(true);
21542  CompileRun("try { throw new Error(); } finally { gc(); }");
21543  CHECK(try_catch.HasCaught());
21544}
21545
21546
21547THREADED_TEST(Regress149912) {
21548  LocalContext context;
21549  v8::HandleScope scope(context->GetIsolate());
21550  Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21551  AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21552  context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21553  CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21554}
21555
21556
21557THREADED_TEST(Regress157124) {
21558  LocalContext context;
21559  v8::Isolate* isolate = context->GetIsolate();
21560  v8::HandleScope scope(isolate);
21561  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21562  Local<Object> obj = templ->NewInstance();
21563  obj->GetIdentityHash();
21564  obj->DeleteHiddenValue(v8_str("Bug"));
21565}
21566
21567
21568THREADED_TEST(Regress2535) {
21569  LocalContext context;
21570  v8::HandleScope scope(context->GetIsolate());
21571  Local<Value> set_value = CompileRun("new Set();");
21572  Local<Object> set_object(Local<Object>::Cast(set_value));
21573  CHECK_EQ(0, set_object->InternalFieldCount());
21574  Local<Value> map_value = CompileRun("new Map();");
21575  Local<Object> map_object(Local<Object>::Cast(map_value));
21576  CHECK_EQ(0, map_object->InternalFieldCount());
21577}
21578
21579
21580THREADED_TEST(Regress2746) {
21581  LocalContext context;
21582  v8::Isolate* isolate = context->GetIsolate();
21583  v8::HandleScope scope(isolate);
21584  Local<Object> obj = Object::New(isolate);
21585  Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21586  obj->SetHiddenValue(key, v8::Undefined(isolate));
21587  Local<Value> value = obj->GetHiddenValue(key);
21588  CHECK(!value.IsEmpty());
21589  CHECK(value->IsUndefined());
21590}
21591
21592
21593THREADED_TEST(Regress260106) {
21594  LocalContext context;
21595  v8::Isolate* isolate = context->GetIsolate();
21596  v8::HandleScope scope(isolate);
21597  Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21598                                                        DummyCallHandler);
21599  CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21600  Local<Function> function = templ->GetFunction();
21601  CHECK(!function.IsEmpty());
21602  CHECK(function->IsFunction());
21603}
21604
21605
21606THREADED_TEST(JSONParseObject) {
21607  LocalContext context;
21608  HandleScope scope(context->GetIsolate());
21609  Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21610  Handle<Object> global = context->Global();
21611  global->Set(v8_str("obj"), obj);
21612  ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21613}
21614
21615
21616THREADED_TEST(JSONParseNumber) {
21617  LocalContext context;
21618  HandleScope scope(context->GetIsolate());
21619  Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21620  Handle<Object> global = context->Global();
21621  global->Set(v8_str("obj"), obj);
21622  ExpectString("JSON.stringify(obj)", "42");
21623}
21624
21625
21626#if V8_OS_POSIX && !V8_OS_NACL
21627class ThreadInterruptTest {
21628 public:
21629  ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21630  ~ThreadInterruptTest() {}
21631
21632  void RunTest() {
21633    InterruptThread i_thread(this);
21634    i_thread.Start();
21635
21636    sem_.Wait();
21637    CHECK_EQ(kExpectedValue, sem_value_);
21638  }
21639
21640 private:
21641  static const int kExpectedValue = 1;
21642
21643  class InterruptThread : public v8::base::Thread {
21644   public:
21645    explicit InterruptThread(ThreadInterruptTest* test)
21646        : Thread(Options("InterruptThread")), test_(test) {}
21647
21648    virtual void Run() {
21649      struct sigaction action;
21650
21651      // Ensure that we'll enter waiting condition
21652      v8::base::OS::Sleep(100);
21653
21654      // Setup signal handler
21655      memset(&action, 0, sizeof(action));
21656      action.sa_handler = SignalHandler;
21657      sigaction(SIGCHLD, &action, NULL);
21658
21659      // Send signal
21660      kill(getpid(), SIGCHLD);
21661
21662      // Ensure that if wait has returned because of error
21663      v8::base::OS::Sleep(100);
21664
21665      // Set value and signal semaphore
21666      test_->sem_value_ = 1;
21667      test_->sem_.Signal();
21668    }
21669
21670    static void SignalHandler(int signal) {
21671    }
21672
21673   private:
21674     ThreadInterruptTest* test_;
21675  };
21676
21677  v8::base::Semaphore sem_;
21678  volatile int sem_value_;
21679};
21680
21681
21682THREADED_TEST(SemaphoreInterruption) {
21683  ThreadInterruptTest().RunTest();
21684}
21685
21686
21687#endif  // V8_OS_POSIX
21688
21689
21690static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21691                                     Local<Value> name,
21692                                     v8::AccessType type,
21693                                     Local<Value> data) {
21694  i::PrintF("Named access blocked.\n");
21695  return false;
21696}
21697
21698
21699static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21700                                     uint32_t key,
21701                                     v8::AccessType type,
21702                                     Local<Value> data) {
21703  i::PrintF("Indexed access blocked.\n");
21704  return false;
21705}
21706
21707
21708void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21709  CHECK(false);
21710}
21711
21712
21713TEST(JSONStringifyAccessCheck) {
21714  v8::V8::Initialize();
21715  v8::Isolate* isolate = CcTest::isolate();
21716  v8::HandleScope scope(isolate);
21717
21718  // Create an ObjectTemplate for global objects and install access
21719  // check callbacks that will block access.
21720  v8::Handle<v8::ObjectTemplate> global_template =
21721      v8::ObjectTemplate::New(isolate);
21722  global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21723                                           IndexAccessAlwaysBlocked);
21724
21725  // Create a context and set an x property on it's global object.
21726  LocalContext context0(NULL, global_template);
21727  v8::Handle<v8::Object> global0 = context0->Global();
21728  global0->Set(v8_str("x"), v8_num(42));
21729  ExpectString("JSON.stringify(this)", "{\"x\":42}");
21730
21731  for (int i = 0; i < 2; i++) {
21732    if (i == 1) {
21733      // Install a toJSON function on the second run.
21734      v8::Handle<v8::FunctionTemplate> toJSON =
21735          v8::FunctionTemplate::New(isolate, UnreachableCallback);
21736
21737      global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21738    }
21739    // Create a context with a different security token so that the
21740    // failed access check callback will be called on each access.
21741    LocalContext context1(NULL, global_template);
21742    context1->Global()->Set(v8_str("other"), global0);
21743
21744    CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
21745    CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
21746    CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
21747
21748    v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21749    array->Set(0, v8_str("a"));
21750    array->Set(1, v8_str("b"));
21751    context1->Global()->Set(v8_str("array"), array);
21752    ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21753    array->TurnOnAccessCheck();
21754    CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
21755    CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
21756    CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
21757  }
21758}
21759
21760
21761bool access_check_fail_thrown = false;
21762bool catch_callback_called = false;
21763
21764
21765// Failed access check callback that performs a GC on each invocation.
21766void FailedAccessCheckThrows(Local<v8::Object> target,
21767                             v8::AccessType type,
21768                             Local<v8::Value> data) {
21769  access_check_fail_thrown = true;
21770  i::PrintF("Access check failed. Error thrown.\n");
21771  CcTest::isolate()->ThrowException(
21772      v8::Exception::Error(v8_str("cross context")));
21773}
21774
21775
21776void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21777  for (int i = 0; i < args.Length(); i++) {
21778    i::PrintF("%s\n", *String::Utf8Value(args[i]));
21779  }
21780  catch_callback_called = true;
21781}
21782
21783
21784void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21785  args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21786}
21787
21788
21789void CheckCorrectThrow(const char* script) {
21790  // Test that the script, when wrapped into a try-catch, triggers the catch
21791  // clause due to failed access check throwing an exception.
21792  // The subsequent try-catch should run without any exception.
21793  access_check_fail_thrown = false;
21794  catch_callback_called = false;
21795  i::ScopedVector<char> source(1024);
21796  i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21797  CompileRun(source.start());
21798  CHECK(access_check_fail_thrown);
21799  CHECK(catch_callback_called);
21800
21801  access_check_fail_thrown = false;
21802  catch_callback_called = false;
21803  CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21804  CHECK(!access_check_fail_thrown);
21805  CHECK(!catch_callback_called);
21806}
21807
21808
21809TEST(AccessCheckThrows) {
21810  i::FLAG_allow_natives_syntax = true;
21811  v8::V8::Initialize();
21812  v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21813  v8::Isolate* isolate = CcTest::isolate();
21814  v8::HandleScope scope(isolate);
21815
21816  // Create an ObjectTemplate for global objects and install access
21817  // check callbacks that will block access.
21818  v8::Handle<v8::ObjectTemplate> global_template =
21819      v8::ObjectTemplate::New(isolate);
21820  global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21821                                           IndexAccessAlwaysBlocked);
21822
21823  // Create a context and set an x property on it's global object.
21824  LocalContext context0(NULL, global_template);
21825  v8::Handle<v8::Object> global0 = context0->Global();
21826
21827  // Create a context with a different security token so that the
21828  // failed access check callback will be called on each access.
21829  LocalContext context1(NULL, global_template);
21830  context1->Global()->Set(v8_str("other"), global0);
21831
21832  v8::Handle<v8::FunctionTemplate> catcher_fun =
21833      v8::FunctionTemplate::New(isolate, CatcherCallback);
21834  context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21835
21836  v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21837      v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21838  context1->Global()->Set(v8_str("has_own_property"),
21839                          has_own_property_fun->GetFunction());
21840
21841  { v8::TryCatch try_catch;
21842    access_check_fail_thrown = false;
21843    CompileRun("other.x;");
21844    CHECK(access_check_fail_thrown);
21845    CHECK(try_catch.HasCaught());
21846  }
21847
21848  CheckCorrectThrow("other.x");
21849  CheckCorrectThrow("other[1]");
21850  CheckCorrectThrow("JSON.stringify(other)");
21851  CheckCorrectThrow("has_own_property(other, 'x')");
21852  CheckCorrectThrow("%GetProperty(other, 'x')");
21853  CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
21854  CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
21855  CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21856  CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21857  CheckCorrectThrow("%HasOwnProperty(other, 'x')");
21858  CheckCorrectThrow("%HasProperty(other, 'x')");
21859  CheckCorrectThrow("%HasElement(other, 1)");
21860  CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21861  CheckCorrectThrow("%GetPropertyNames(other)");
21862  // PROPERTY_ATTRIBUTES_NONE = 0
21863  CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
21864  CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
21865                        "other, 'x', null, null, 1)");
21866
21867  // Reset the failed access check callback so it does not influence
21868  // the other tests.
21869  v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21870}
21871
21872
21873THREADED_TEST(Regress256330) {
21874  i::FLAG_allow_natives_syntax = true;
21875  LocalContext context;
21876  v8::HandleScope scope(context->GetIsolate());
21877  Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21878  AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21879  context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21880  CompileRun("\"use strict\"; var o = new Bug;"
21881             "function f(o) { o.x = 10; };"
21882             "f(o); f(o); f(o);"
21883             "%OptimizeFunctionOnNextCall(f);"
21884             "f(o);");
21885  ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21886}
21887
21888
21889THREADED_TEST(CrankshaftInterceptorSetter) {
21890  i::FLAG_allow_natives_syntax = true;
21891  v8::HandleScope scope(CcTest::isolate());
21892  Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21893  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21894  LocalContext env;
21895  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21896  CompileRun("var obj = new Obj;"
21897             // Initialize fields to avoid transitions later.
21898             "obj.age = 0;"
21899             "obj.accessor_age = 42;"
21900             "function setter(i) { this.accessor_age = i; };"
21901             "function getter() { return this.accessor_age; };"
21902             "function setAge(i) { obj.age = i; };"
21903             "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21904             "setAge(1);"
21905             "setAge(2);"
21906             "setAge(3);"
21907             "%OptimizeFunctionOnNextCall(setAge);"
21908             "setAge(4);");
21909  // All stores went through the interceptor.
21910  ExpectInt32("obj.interceptor_age", 4);
21911  ExpectInt32("obj.accessor_age", 42);
21912}
21913
21914
21915THREADED_TEST(CrankshaftInterceptorGetter) {
21916  i::FLAG_allow_natives_syntax = true;
21917  v8::HandleScope scope(CcTest::isolate());
21918  Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21919  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21920  LocalContext env;
21921  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21922  CompileRun("var obj = new Obj;"
21923             // Initialize fields to avoid transitions later.
21924             "obj.age = 1;"
21925             "obj.accessor_age = 42;"
21926             "function getter() { return this.accessor_age; };"
21927             "function getAge() { return obj.interceptor_age; };"
21928             "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21929             "getAge();"
21930             "getAge();"
21931             "getAge();"
21932             "%OptimizeFunctionOnNextCall(getAge);");
21933  // Access through interceptor.
21934  ExpectInt32("getAge()", 1);
21935}
21936
21937
21938THREADED_TEST(CrankshaftInterceptorFieldRead) {
21939  i::FLAG_allow_natives_syntax = true;
21940  v8::HandleScope scope(CcTest::isolate());
21941  Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21942  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21943  LocalContext env;
21944  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21945  CompileRun("var obj = new Obj;"
21946             "obj.__proto__.interceptor_age = 42;"
21947             "obj.age = 100;"
21948             "function getAge() { return obj.interceptor_age; };");
21949  ExpectInt32("getAge();", 100);
21950  ExpectInt32("getAge();", 100);
21951  ExpectInt32("getAge();", 100);
21952  CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21953  // Access through interceptor.
21954  ExpectInt32("getAge();", 100);
21955}
21956
21957
21958THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21959  i::FLAG_allow_natives_syntax = true;
21960  v8::HandleScope scope(CcTest::isolate());
21961  Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21962  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21963  LocalContext env;
21964  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21965  CompileRun("var obj = new Obj;"
21966             "obj.age = 100000;"
21967             "function setAge(i) { obj.age = i };"
21968             "setAge(100);"
21969             "setAge(101);"
21970             "setAge(102);"
21971             "%OptimizeFunctionOnNextCall(setAge);"
21972             "setAge(103);");
21973  ExpectInt32("obj.age", 100000);
21974  ExpectInt32("obj.interceptor_age", 103);
21975}
21976
21977
21978class RequestInterruptTestBase {
21979 public:
21980  RequestInterruptTestBase()
21981      : env_(),
21982        isolate_(env_->GetIsolate()),
21983        sem_(0),
21984        warmup_(20000),
21985        should_continue_(true) {
21986  }
21987
21988  virtual ~RequestInterruptTestBase() { }
21989
21990  virtual void StartInterruptThread() = 0;
21991
21992  virtual void TestBody() = 0;
21993
21994  void RunTest() {
21995    StartInterruptThread();
21996
21997    v8::HandleScope handle_scope(isolate_);
21998
21999    TestBody();
22000
22001    isolate_->ClearInterrupt();
22002
22003    // Verify we arrived here because interruptor was called
22004    // not due to a bug causing us to exit the loop too early.
22005    CHECK(!should_continue());
22006  }
22007
22008  void WakeUpInterruptor() {
22009    sem_.Signal();
22010  }
22011
22012  bool should_continue() const { return should_continue_; }
22013
22014  bool ShouldContinue() {
22015    if (warmup_ > 0) {
22016      if (--warmup_ == 0) {
22017        WakeUpInterruptor();
22018      }
22019    }
22020
22021    return should_continue_;
22022  }
22023
22024  static void ShouldContinueCallback(
22025      const v8::FunctionCallbackInfo<Value>& info) {
22026    RequestInterruptTestBase* test =
22027        reinterpret_cast<RequestInterruptTestBase*>(
22028            info.Data().As<v8::External>()->Value());
22029    info.GetReturnValue().Set(test->ShouldContinue());
22030  }
22031
22032  LocalContext env_;
22033  v8::Isolate* isolate_;
22034  v8::base::Semaphore sem_;
22035  int warmup_;
22036  bool should_continue_;
22037};
22038
22039
22040class RequestInterruptTestBaseWithSimpleInterrupt
22041    : public RequestInterruptTestBase {
22042 public:
22043  RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
22044
22045  virtual void StartInterruptThread() {
22046    i_thread.Start();
22047  }
22048
22049 private:
22050  class InterruptThread : public v8::base::Thread {
22051   public:
22052    explicit InterruptThread(RequestInterruptTestBase* test)
22053        : Thread(Options("RequestInterruptTest")), test_(test) {}
22054
22055    virtual void Run() {
22056      test_->sem_.Wait();
22057      test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22058    }
22059
22060    static void OnInterrupt(v8::Isolate* isolate, void* data) {
22061      reinterpret_cast<RequestInterruptTestBase*>(data)->
22062          should_continue_ = false;
22063    }
22064
22065   private:
22066     RequestInterruptTestBase* test_;
22067  };
22068
22069  InterruptThread i_thread;
22070};
22071
22072
22073class RequestInterruptTestWithFunctionCall
22074    : public RequestInterruptTestBaseWithSimpleInterrupt {
22075 public:
22076  virtual void TestBody() {
22077    Local<Function> func = Function::New(
22078        isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22079    env_->Global()->Set(v8_str("ShouldContinue"), func);
22080
22081    CompileRun("while (ShouldContinue()) { }");
22082  }
22083};
22084
22085
22086class RequestInterruptTestWithMethodCall
22087    : public RequestInterruptTestBaseWithSimpleInterrupt {
22088 public:
22089  virtual void TestBody() {
22090    v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22091    v8::Local<v8::Template> proto = t->PrototypeTemplate();
22092    proto->Set(v8_str("shouldContinue"), Function::New(
22093        isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22094    env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22095
22096    CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22097  }
22098};
22099
22100
22101class RequestInterruptTestWithAccessor
22102    : public RequestInterruptTestBaseWithSimpleInterrupt {
22103 public:
22104  virtual void TestBody() {
22105    v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22106    v8::Local<v8::Template> proto = t->PrototypeTemplate();
22107    proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
22108        isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22109    env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22110
22111    CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22112  }
22113};
22114
22115
22116class RequestInterruptTestWithNativeAccessor
22117    : public RequestInterruptTestBaseWithSimpleInterrupt {
22118 public:
22119  virtual void TestBody() {
22120    v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22121    t->InstanceTemplate()->SetNativeDataProperty(
22122        v8_str("shouldContinue"),
22123        &ShouldContinueNativeGetter,
22124        NULL,
22125        v8::External::New(isolate_, this));
22126    env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22127
22128    CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22129  }
22130
22131 private:
22132  static void ShouldContinueNativeGetter(
22133      Local<String> property,
22134      const v8::PropertyCallbackInfo<v8::Value>& info) {
22135    RequestInterruptTestBase* test =
22136        reinterpret_cast<RequestInterruptTestBase*>(
22137            info.Data().As<v8::External>()->Value());
22138    info.GetReturnValue().Set(test->ShouldContinue());
22139  }
22140};
22141
22142
22143class RequestInterruptTestWithMethodCallAndInterceptor
22144    : public RequestInterruptTestBaseWithSimpleInterrupt {
22145 public:
22146  virtual void TestBody() {
22147    v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22148    v8::Local<v8::Template> proto = t->PrototypeTemplate();
22149    proto->Set(v8_str("shouldContinue"), Function::New(
22150        isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22151    v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
22152    instance_template->SetNamedPropertyHandler(EmptyInterceptor);
22153
22154    env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22155
22156    CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22157  }
22158
22159 private:
22160  static void EmptyInterceptor(
22161      Local<String> property,
22162      const v8::PropertyCallbackInfo<v8::Value>& info) {
22163  }
22164};
22165
22166
22167class RequestInterruptTestWithMathAbs
22168    : public RequestInterruptTestBaseWithSimpleInterrupt {
22169 public:
22170  virtual void TestBody() {
22171    env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
22172        isolate_,
22173        WakeUpInterruptorCallback,
22174        v8::External::New(isolate_, this)));
22175
22176    env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
22177        isolate_,
22178        ShouldContinueCallback,
22179        v8::External::New(isolate_, this)));
22180
22181    i::FLAG_allow_natives_syntax = true;
22182    CompileRun("function loopish(o) {"
22183               "  var pre = 10;"
22184               "  while (o.abs(1) > 0) {"
22185               "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
22186               "    if (pre > 0) {"
22187               "      if (--pre === 0) WakeUpInterruptor(o === Math);"
22188               "    }"
22189               "  }"
22190               "}"
22191               "var i = 50;"
22192               "var obj = {abs: function () { return i-- }, x: null};"
22193               "delete obj.x;"
22194               "loopish(obj);"
22195               "%OptimizeFunctionOnNextCall(loopish);"
22196               "loopish(Math);");
22197
22198    i::FLAG_allow_natives_syntax = false;
22199  }
22200
22201 private:
22202  static void WakeUpInterruptorCallback(
22203      const v8::FunctionCallbackInfo<Value>& info) {
22204    if (!info[0]->BooleanValue()) return;
22205
22206    RequestInterruptTestBase* test =
22207        reinterpret_cast<RequestInterruptTestBase*>(
22208            info.Data().As<v8::External>()->Value());
22209    test->WakeUpInterruptor();
22210  }
22211
22212  static void ShouldContinueCallback(
22213      const v8::FunctionCallbackInfo<Value>& info) {
22214    RequestInterruptTestBase* test =
22215        reinterpret_cast<RequestInterruptTestBase*>(
22216            info.Data().As<v8::External>()->Value());
22217    info.GetReturnValue().Set(test->should_continue());
22218  }
22219};
22220
22221
22222TEST(RequestInterruptTestWithFunctionCall) {
22223  RequestInterruptTestWithFunctionCall().RunTest();
22224}
22225
22226
22227TEST(RequestInterruptTestWithMethodCall) {
22228  RequestInterruptTestWithMethodCall().RunTest();
22229}
22230
22231
22232TEST(RequestInterruptTestWithAccessor) {
22233  RequestInterruptTestWithAccessor().RunTest();
22234}
22235
22236
22237TEST(RequestInterruptTestWithNativeAccessor) {
22238  RequestInterruptTestWithNativeAccessor().RunTest();
22239}
22240
22241
22242TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22243  RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22244}
22245
22246
22247TEST(RequestInterruptTestWithMathAbs) {
22248  RequestInterruptTestWithMathAbs().RunTest();
22249}
22250
22251
22252class ClearInterruptFromAnotherThread
22253    : public RequestInterruptTestBase {
22254 public:
22255  ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
22256
22257  virtual void StartInterruptThread() {
22258    i_thread.Start();
22259  }
22260
22261  virtual void TestBody() {
22262    Local<Function> func = Function::New(
22263        isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22264    env_->Global()->Set(v8_str("ShouldContinue"), func);
22265
22266    CompileRun("while (ShouldContinue()) { }");
22267  }
22268
22269 private:
22270  class InterruptThread : public v8::base::Thread {
22271   public:
22272    explicit InterruptThread(ClearInterruptFromAnotherThread* test)
22273        : Thread(Options("RequestInterruptTest")), test_(test) {}
22274
22275    virtual void Run() {
22276      test_->sem_.Wait();
22277      test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22278      test_->sem_.Wait();
22279      test_->isolate_->ClearInterrupt();
22280      test_->sem2_.Signal();
22281    }
22282
22283    static void OnInterrupt(v8::Isolate* isolate, void* data) {
22284      ClearInterruptFromAnotherThread* test =
22285          reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
22286      test->sem_.Signal();
22287      bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2));
22288      // Crash instead of timeout to make this failure more prominent.
22289      CHECK(success);
22290      test->should_continue_ = false;
22291    }
22292
22293   private:
22294     ClearInterruptFromAnotherThread* test_;
22295  };
22296
22297  InterruptThread i_thread;
22298  v8::base::Semaphore sem2_;
22299};
22300
22301
22302TEST(ClearInterruptFromAnotherThread) {
22303  ClearInterruptFromAnotherThread().RunTest();
22304}
22305
22306
22307static Local<Value> function_new_expected_env;
22308static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22309  CHECK_EQ(function_new_expected_env, info.Data());
22310  info.GetReturnValue().Set(17);
22311}
22312
22313
22314THREADED_TEST(FunctionNew) {
22315  LocalContext env;
22316  v8::Isolate* isolate = env->GetIsolate();
22317  v8::HandleScope scope(isolate);
22318  Local<Object> data = v8::Object::New(isolate);
22319  function_new_expected_env = data;
22320  Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22321  env->Global()->Set(v8_str("func"), func);
22322  Local<Value> result = CompileRun("func();");
22323  CHECK_EQ(v8::Integer::New(isolate, 17), result);
22324  // Verify function not cached
22325  int serial_number =
22326      i::Smi::cast(v8::Utils::OpenHandle(*func)
22327          ->shared()->get_api_func_data()->serial_number())->value();
22328  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22329  i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22330  i::Handle<i::Object> elm =
22331      i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22332  CHECK(elm->IsUndefined());
22333  // Verify that each Function::New creates a new function instance
22334  Local<Object> data2 = v8::Object::New(isolate);
22335  function_new_expected_env = data2;
22336  Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22337  CHECK(!func2->IsNull());
22338  CHECK_NE(func, func2);
22339  env->Global()->Set(v8_str("func2"), func2);
22340  Local<Value> result2 = CompileRun("func2();");
22341  CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22342}
22343
22344
22345TEST(EscapeableHandleScope) {
22346  HandleScope outer_scope(CcTest::isolate());
22347  LocalContext context;
22348  const int runs = 10;
22349  Local<String> values[runs];
22350  for (int i = 0; i < runs; i++) {
22351    v8::EscapableHandleScope inner_scope(CcTest::isolate());
22352    Local<String> value;
22353    if (i != 0) value = v8_str("escape value");
22354    values[i] = inner_scope.Escape(value);
22355  }
22356  for (int i = 0; i < runs; i++) {
22357    Local<String> expected;
22358    if (i != 0) {
22359      CHECK_EQ(v8_str("escape value"), values[i]);
22360    } else {
22361      CHECK(values[i].IsEmpty());
22362    }
22363  }
22364}
22365
22366
22367static void SetterWhichExpectsThisAndHolderToDiffer(
22368    Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22369  CHECK(info.Holder() != info.This());
22370}
22371
22372
22373TEST(Regress239669) {
22374  LocalContext context;
22375  v8::Isolate* isolate = context->GetIsolate();
22376  v8::HandleScope scope(isolate);
22377  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22378  templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22379  context->Global()->Set(v8_str("P"), templ->NewInstance());
22380  CompileRun(
22381      "function C1() {"
22382      "  this.x = 23;"
22383      "};"
22384      "C1.prototype = P;"
22385      "for (var i = 0; i < 4; i++ ) {"
22386      "  new C1();"
22387      "}");
22388}
22389
22390
22391class ApiCallOptimizationChecker {
22392 private:
22393  static Local<Object> data;
22394  static Local<Object> receiver;
22395  static Local<Object> holder;
22396  static Local<Object> callee;
22397  static int count;
22398
22399  static void OptimizationCallback(
22400      const v8::FunctionCallbackInfo<v8::Value>& info) {
22401    CHECK(callee == info.Callee());
22402    CHECK(data == info.Data());
22403    CHECK(receiver == info.This());
22404    if (info.Length() == 1) {
22405      CHECK_EQ(v8_num(1), info[0]);
22406    }
22407    CHECK(holder == info.Holder());
22408    count++;
22409    info.GetReturnValue().Set(v8_str("returned"));
22410  }
22411
22412 public:
22413  enum SignatureType {
22414    kNoSignature,
22415    kSignatureOnReceiver,
22416    kSignatureOnPrototype
22417  };
22418
22419  void RunAll() {
22420    SignatureType signature_types[] =
22421      {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22422    for (unsigned i = 0; i < arraysize(signature_types); i++) {
22423      SignatureType signature_type = signature_types[i];
22424      for (int j = 0; j < 2; j++) {
22425        bool global = j == 0;
22426        int key = signature_type +
22427            arraysize(signature_types) * (global ? 1 : 0);
22428        Run(signature_type, global, key);
22429      }
22430    }
22431  }
22432
22433  void Run(SignatureType signature_type, bool global, int key) {
22434    v8::Isolate* isolate = CcTest::isolate();
22435    v8::HandleScope scope(isolate);
22436    // Build a template for signature checks.
22437    Local<v8::ObjectTemplate> signature_template;
22438    Local<v8::Signature> signature;
22439    {
22440      Local<v8::FunctionTemplate> parent_template =
22441        FunctionTemplate::New(isolate);
22442      parent_template->SetHiddenPrototype(true);
22443      Local<v8::FunctionTemplate> function_template
22444          = FunctionTemplate::New(isolate);
22445      function_template->Inherit(parent_template);
22446      switch (signature_type) {
22447        case kNoSignature:
22448          break;
22449        case kSignatureOnReceiver:
22450          signature = v8::Signature::New(isolate, function_template);
22451          break;
22452        case kSignatureOnPrototype:
22453          signature = v8::Signature::New(isolate, parent_template);
22454          break;
22455      }
22456      signature_template = function_template->InstanceTemplate();
22457    }
22458    // Global object must pass checks.
22459    Local<v8::Context> context =
22460        v8::Context::New(isolate, NULL, signature_template);
22461    v8::Context::Scope context_scope(context);
22462    // Install regular object that can pass signature checks.
22463    Local<Object> function_receiver = signature_template->NewInstance();
22464    context->Global()->Set(v8_str("function_receiver"), function_receiver);
22465    // Get the holder objects.
22466    Local<Object> inner_global =
22467        Local<Object>::Cast(context->Global()->GetPrototype());
22468    // Install functions on hidden prototype object if there is one.
22469    data = Object::New(isolate);
22470    Local<FunctionTemplate> function_template = FunctionTemplate::New(
22471        isolate, OptimizationCallback, data, signature);
22472    Local<Function> function = function_template->GetFunction();
22473    Local<Object> global_holder = inner_global;
22474    Local<Object> function_holder = function_receiver;
22475    if (signature_type == kSignatureOnPrototype) {
22476      function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22477      global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22478    }
22479    global_holder->Set(v8_str("g_f"), function);
22480    global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22481    function_holder->Set(v8_str("f"), function);
22482    function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22483    // Initialize expected values.
22484    callee = function;
22485    count = 0;
22486    if (global) {
22487      receiver = context->Global();
22488      holder = inner_global;
22489    } else {
22490      holder = function_receiver;
22491      // If not using a signature, add something else to the prototype chain
22492      // to test the case that holder != receiver
22493      if (signature_type == kNoSignature) {
22494        receiver = Local<Object>::Cast(CompileRun(
22495            "var receiver_subclass = {};\n"
22496            "receiver_subclass.__proto__ = function_receiver;\n"
22497            "receiver_subclass"));
22498      } else {
22499        receiver = Local<Object>::Cast(CompileRun(
22500          "var receiver_subclass = function_receiver;\n"
22501          "receiver_subclass"));
22502      }
22503    }
22504    // With no signature, the holder is not set.
22505    if (signature_type == kNoSignature) holder = receiver;
22506    // build wrap_function
22507    i::ScopedVector<char> wrap_function(200);
22508    if (global) {
22509      i::SNPrintF(
22510          wrap_function,
22511          "function wrap_f_%d() { var f = g_f; return f(); }\n"
22512          "function wrap_get_%d() { return this.g_acc; }\n"
22513          "function wrap_set_%d() { return this.g_acc = 1; }\n",
22514          key, key, key);
22515    } else {
22516      i::SNPrintF(
22517          wrap_function,
22518          "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22519          "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22520          "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22521          key, key, key);
22522    }
22523    // build source string
22524    i::ScopedVector<char> source(1000);
22525    i::SNPrintF(
22526        source,
22527        "%s\n"  // wrap functions
22528        "function wrap_f() { return wrap_f_%d(); }\n"
22529        "function wrap_get() { return wrap_get_%d(); }\n"
22530        "function wrap_set() { return wrap_set_%d(); }\n"
22531        "check = function(returned) {\n"
22532        "  if (returned !== 'returned') { throw returned; }\n"
22533        "}\n"
22534        "\n"
22535        "check(wrap_f());\n"
22536        "check(wrap_f());\n"
22537        "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22538        "check(wrap_f());\n"
22539        "\n"
22540        "check(wrap_get());\n"
22541        "check(wrap_get());\n"
22542        "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22543        "check(wrap_get());\n"
22544        "\n"
22545        "check = function(returned) {\n"
22546        "  if (returned !== 1) { throw returned; }\n"
22547        "}\n"
22548        "check(wrap_set());\n"
22549        "check(wrap_set());\n"
22550        "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22551        "check(wrap_set());\n",
22552        wrap_function.start(), key, key, key, key, key, key);
22553    v8::TryCatch try_catch;
22554    CompileRun(source.start());
22555    DCHECK(!try_catch.HasCaught());
22556    CHECK_EQ(9, count);
22557  }
22558};
22559
22560
22561Local<Object> ApiCallOptimizationChecker::data;
22562Local<Object> ApiCallOptimizationChecker::receiver;
22563Local<Object> ApiCallOptimizationChecker::holder;
22564Local<Object> ApiCallOptimizationChecker::callee;
22565int ApiCallOptimizationChecker::count = 0;
22566
22567
22568TEST(TestFunctionCallOptimization) {
22569  i::FLAG_allow_natives_syntax = true;
22570  ApiCallOptimizationChecker checker;
22571  checker.RunAll();
22572}
22573
22574
22575static const char* last_event_message;
22576static int last_event_status;
22577void StoringEventLoggerCallback(const char* message, int status) {
22578    last_event_message = message;
22579    last_event_status = status;
22580}
22581
22582
22583TEST(EventLogging) {
22584  v8::Isolate* isolate = CcTest::isolate();
22585  isolate->SetEventLogger(StoringEventLoggerCallback);
22586  v8::internal::HistogramTimer histogramTimer(
22587      "V8.Test", 0, 10000, 50,
22588      reinterpret_cast<v8::internal::Isolate*>(isolate));
22589  histogramTimer.Start();
22590  CHECK_EQ("V8.Test", last_event_message);
22591  CHECK_EQ(0, last_event_status);
22592  histogramTimer.Stop();
22593  CHECK_EQ("V8.Test", last_event_message);
22594  CHECK_EQ(1, last_event_status);
22595}
22596
22597
22598TEST(Promises) {
22599  LocalContext context;
22600  v8::Isolate* isolate = context->GetIsolate();
22601  v8::HandleScope scope(isolate);
22602  Handle<Object> global = context->Global();
22603
22604  // Creation.
22605  Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22606  Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22607  Handle<v8::Promise> p = pr->GetPromise();
22608  Handle<v8::Promise> r = rr->GetPromise();
22609
22610  // IsPromise predicate.
22611  CHECK(p->IsPromise());
22612  CHECK(r->IsPromise());
22613  Handle<Value> o = v8::Object::New(isolate);
22614  CHECK(!o->IsPromise());
22615
22616  // Resolution and rejection.
22617  pr->Resolve(v8::Integer::New(isolate, 1));
22618  CHECK(p->IsPromise());
22619  rr->Reject(v8::Integer::New(isolate, 2));
22620  CHECK(r->IsPromise());
22621
22622  // Chaining non-pending promises.
22623  CompileRun(
22624      "var x1 = 0;\n"
22625      "var x2 = 0;\n"
22626      "function f1(x) { x1 = x; return x+1 };\n"
22627      "function f2(x) { x2 = x; return x+1 };\n");
22628  Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22629  Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22630
22631  p->Chain(f1);
22632  CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22633  isolate->RunMicrotasks();
22634  CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22635
22636  p->Catch(f2);
22637  isolate->RunMicrotasks();
22638  CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22639
22640  r->Catch(f2);
22641  CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22642  isolate->RunMicrotasks();
22643  CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22644
22645  r->Chain(f1);
22646  isolate->RunMicrotasks();
22647  CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22648
22649  // Chaining pending promises.
22650  CompileRun("x1 = x2 = 0;");
22651  pr = v8::Promise::Resolver::New(isolate);
22652  rr = v8::Promise::Resolver::New(isolate);
22653
22654  pr->GetPromise()->Chain(f1);
22655  rr->GetPromise()->Catch(f2);
22656  isolate->RunMicrotasks();
22657  CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22658  CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22659
22660  pr->Resolve(v8::Integer::New(isolate, 1));
22661  rr->Reject(v8::Integer::New(isolate, 2));
22662  CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22663  CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22664
22665  isolate->RunMicrotasks();
22666  CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22667  CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22668
22669  // Multi-chaining.
22670  CompileRun("x1 = x2 = 0;");
22671  pr = v8::Promise::Resolver::New(isolate);
22672  pr->GetPromise()->Chain(f1)->Chain(f2);
22673  pr->Resolve(v8::Integer::New(isolate, 3));
22674  CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22675  CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22676  isolate->RunMicrotasks();
22677  CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22678  CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22679
22680  CompileRun("x1 = x2 = 0;");
22681  rr = v8::Promise::Resolver::New(isolate);
22682  rr->GetPromise()->Catch(f1)->Chain(f2);
22683  rr->Reject(v8::Integer::New(isolate, 3));
22684  CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22685  CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22686  isolate->RunMicrotasks();
22687  CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22688  CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22689}
22690
22691
22692TEST(PromiseThen) {
22693  LocalContext context;
22694  v8::Isolate* isolate = context->GetIsolate();
22695  v8::HandleScope scope(isolate);
22696  Handle<Object> global = context->Global();
22697
22698  // Creation.
22699  Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22700  Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
22701  Handle<v8::Promise> p = pr->GetPromise();
22702  Handle<v8::Promise> q = qr->GetPromise();
22703
22704  CHECK(p->IsPromise());
22705  CHECK(q->IsPromise());
22706
22707  pr->Resolve(v8::Integer::New(isolate, 1));
22708  qr->Resolve(p);
22709
22710  // Chaining non-pending promises.
22711  CompileRun(
22712      "var x1 = 0;\n"
22713      "var x2 = 0;\n"
22714      "function f1(x) { x1 = x; return x+1 };\n"
22715      "function f2(x) { x2 = x; return x+1 };\n");
22716  Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22717  Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22718
22719  // Chain
22720  q->Chain(f1);
22721  CHECK(global->Get(v8_str("x1"))->IsNumber());
22722  CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22723  isolate->RunMicrotasks();
22724  CHECK(!global->Get(v8_str("x1"))->IsNumber());
22725  CHECK_EQ(p, global->Get(v8_str("x1")));
22726
22727  // Then
22728  CompileRun("x1 = x2 = 0;");
22729  q->Then(f1);
22730  CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22731  isolate->RunMicrotasks();
22732  CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22733
22734  // Then
22735  CompileRun("x1 = x2 = 0;");
22736  pr = v8::Promise::Resolver::New(isolate);
22737  qr = v8::Promise::Resolver::New(isolate);
22738
22739  qr->Resolve(pr);
22740  qr->GetPromise()->Then(f1)->Then(f2);
22741
22742  CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22743  CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22744  isolate->RunMicrotasks();
22745  CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22746  CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22747
22748  pr->Resolve(v8::Integer::New(isolate, 3));
22749
22750  CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22751  CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22752  isolate->RunMicrotasks();
22753  CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22754  CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22755}
22756
22757
22758TEST(DisallowJavascriptExecutionScope) {
22759  LocalContext context;
22760  v8::Isolate* isolate = context->GetIsolate();
22761  v8::HandleScope scope(isolate);
22762  v8::Isolate::DisallowJavascriptExecutionScope no_js(
22763      isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22764  CompileRun("2+2");
22765}
22766
22767
22768TEST(AllowJavascriptExecutionScope) {
22769  LocalContext context;
22770  v8::Isolate* isolate = context->GetIsolate();
22771  v8::HandleScope scope(isolate);
22772  v8::Isolate::DisallowJavascriptExecutionScope no_js(
22773      isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22774  v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22775      isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22776  { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22777    CompileRun("1+1");
22778  }
22779}
22780
22781
22782TEST(ThrowOnJavascriptExecution) {
22783  LocalContext context;
22784  v8::Isolate* isolate = context->GetIsolate();
22785  v8::HandleScope scope(isolate);
22786  v8::TryCatch try_catch;
22787  v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22788      isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22789  CompileRun("1+1");
22790  CHECK(try_catch.HasCaught());
22791}
22792
22793
22794TEST(Regress354123) {
22795  LocalContext current;
22796  v8::Isolate* isolate = current->GetIsolate();
22797  v8::HandleScope scope(isolate);
22798
22799  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22800  templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22801  current->Global()->Set(v8_str("friend"), templ->NewInstance());
22802
22803  // Test access using __proto__ from the prototype chain.
22804  named_access_count = 0;
22805  CompileRun("friend.__proto__ = {};");
22806  CHECK_EQ(2, named_access_count);
22807  CompileRun("friend.__proto__;");
22808  CHECK_EQ(4, named_access_count);
22809
22810  // Test access using __proto__ as a hijacked function (A).
22811  named_access_count = 0;
22812  CompileRun("var p = Object.prototype;"
22813             "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22814             "f.call(friend, {});");
22815  CHECK_EQ(1, named_access_count);
22816  CompileRun("var p = Object.prototype;"
22817             "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22818             "f.call(friend);");
22819  CHECK_EQ(2, named_access_count);
22820
22821  // Test access using __proto__ as a hijacked function (B).
22822  named_access_count = 0;
22823  CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22824             "f.call(friend, {});");
22825  CHECK_EQ(1, named_access_count);
22826  CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22827             "f.call(friend);");
22828  CHECK_EQ(2, named_access_count);
22829
22830  // Test access using Object.setPrototypeOf reflective method.
22831  named_access_count = 0;
22832  CompileRun("Object.setPrototypeOf(friend, {});");
22833  CHECK_EQ(1, named_access_count);
22834  CompileRun("Object.getPrototypeOf(friend);");
22835  CHECK_EQ(2, named_access_count);
22836}
22837
22838
22839TEST(CaptureStackTraceForStackOverflow) {
22840  v8::internal::FLAG_stack_size = 150;
22841  LocalContext current;
22842  v8::Isolate* isolate = current->GetIsolate();
22843  v8::HandleScope scope(isolate);
22844  V8::SetCaptureStackTraceForUncaughtExceptions(
22845      true, 10, v8::StackTrace::kDetailed);
22846  v8::TryCatch try_catch;
22847  CompileRun("(function f(x) { f(x+1); })(0)");
22848  CHECK(try_catch.HasCaught());
22849}
22850
22851
22852TEST(ScriptNameAndLineNumber) {
22853  LocalContext env;
22854  v8::Isolate* isolate = env->GetIsolate();
22855  v8::HandleScope scope(isolate);
22856  const char* url = "http://www.foo.com/foo.js";
22857  v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
22858  v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
22859  Local<Script> script = v8::ScriptCompiler::Compile(
22860      isolate, &script_source);
22861  Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
22862  CHECK(!script_name.IsEmpty());
22863  CHECK(script_name->IsString());
22864  String::Utf8Value utf8_name(script_name);
22865  CHECK_EQ(url, *utf8_name);
22866  int line_number = script->GetUnboundScript()->GetLineNumber(0);
22867  CHECK_EQ(13, line_number);
22868}
22869
22870
22871void SourceURLHelper(const char* source, const char* expected_source_url,
22872                     const char* expected_source_mapping_url) {
22873  Local<Script> script = v8_compile(source);
22874  if (expected_source_url != NULL) {
22875    v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
22876    CHECK_EQ(expected_source_url, *url);
22877  } else {
22878    CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
22879  }
22880  if (expected_source_mapping_url != NULL) {
22881    v8::String::Utf8Value url(
22882        script->GetUnboundScript()->GetSourceMappingURL());
22883    CHECK_EQ(expected_source_mapping_url, *url);
22884  } else {
22885    CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
22886  }
22887}
22888
22889
22890TEST(ScriptSourceURLAndSourceMappingURL) {
22891  LocalContext env;
22892  v8::Isolate* isolate = env->GetIsolate();
22893  v8::HandleScope scope(isolate);
22894  SourceURLHelper("function foo() {}\n"
22895                  "//# sourceURL=bar1.js\n", "bar1.js", NULL);
22896  SourceURLHelper("function foo() {}\n"
22897                  "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
22898
22899  // Both sourceURL and sourceMappingURL.
22900  SourceURLHelper("function foo() {}\n"
22901                  "//# sourceURL=bar3.js\n"
22902                  "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
22903
22904  // Two source URLs; the first one is ignored.
22905  SourceURLHelper("function foo() {}\n"
22906                  "//# sourceURL=ignoreme.js\n"
22907                  "//# sourceURL=bar5.js\n", "bar5.js", NULL);
22908  SourceURLHelper("function foo() {}\n"
22909                  "//# sourceMappingURL=ignoreme.js\n"
22910                  "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
22911
22912  // SourceURL or sourceMappingURL in the middle of the script.
22913  SourceURLHelper("function foo() {}\n"
22914                  "//# sourceURL=bar7.js\n"
22915                  "function baz() {}\n", "bar7.js", NULL);
22916  SourceURLHelper("function foo() {}\n"
22917                  "//# sourceMappingURL=bar8.js\n"
22918                  "function baz() {}\n", NULL, "bar8.js");
22919
22920  // Too much whitespace.
22921  SourceURLHelper("function foo() {}\n"
22922                  "//#  sourceURL=bar9.js\n"
22923                  "//#  sourceMappingURL=bar10.js\n", NULL, NULL);
22924  SourceURLHelper("function foo() {}\n"
22925                  "//# sourceURL =bar11.js\n"
22926                  "//# sourceMappingURL =bar12.js\n", NULL, NULL);
22927
22928  // Disallowed characters in value.
22929  SourceURLHelper("function foo() {}\n"
22930                  "//# sourceURL=bar13 .js   \n"
22931                  "//# sourceMappingURL=bar14 .js \n",
22932                  NULL, NULL);
22933  SourceURLHelper("function foo() {}\n"
22934                  "//# sourceURL=bar15\t.js   \n"
22935                  "//# sourceMappingURL=bar16\t.js \n",
22936                  NULL, NULL);
22937  SourceURLHelper("function foo() {}\n"
22938                  "//# sourceURL=bar17'.js   \n"
22939                  "//# sourceMappingURL=bar18'.js \n",
22940                  NULL, NULL);
22941  SourceURLHelper("function foo() {}\n"
22942                  "//# sourceURL=bar19\".js   \n"
22943                  "//# sourceMappingURL=bar20\".js \n",
22944                  NULL, NULL);
22945
22946  // Not too much whitespace.
22947  SourceURLHelper("function foo() {}\n"
22948                  "//# sourceURL=  bar21.js   \n"
22949                  "//# sourceMappingURL=  bar22.js \n", "bar21.js", "bar22.js");
22950}
22951
22952
22953TEST(GetOwnPropertyDescriptor) {
22954  LocalContext env;
22955  v8::Isolate* isolate = env->GetIsolate();
22956  v8::HandleScope scope(isolate);
22957  CompileRun(
22958    "var x = { value : 13};"
22959    "Object.defineProperty(x, 'p0', {value : 12});"
22960    "Object.defineProperty(x, 'p1', {"
22961    "  set : function(value) { this.value = value; },"
22962    "  get : function() { return this.value; },"
22963    "});");
22964  Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
22965  Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
22966  CHECK(desc->IsUndefined());
22967  desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
22968  CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value")));
22969  desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
22970  Local<Function> set =
22971    Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
22972  Local<Function> get =
22973    Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
22974  CHECK_EQ(v8_num(13), get->Call(x, 0, NULL));
22975  Handle<Value> args[] = { v8_num(14) };
22976  set->Call(x, 1, args);
22977  CHECK_EQ(v8_num(14), get->Call(x, 0, NULL));
22978}
22979
22980
22981TEST(Regress411877) {
22982  v8::Isolate* isolate = CcTest::isolate();
22983  v8::HandleScope handle_scope(isolate);
22984  v8::Handle<v8::ObjectTemplate> object_template =
22985      v8::ObjectTemplate::New(isolate);
22986  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
22987                                           IndexedAccessCounter);
22988
22989  v8::Handle<Context> context = Context::New(isolate);
22990  v8::Context::Scope context_scope(context);
22991
22992  context->Global()->Set(v8_str("o"), object_template->NewInstance());
22993  CompileRun("Object.getOwnPropertyNames(o)");
22994}
22995
22996
22997TEST(GetHiddenPropertyTableAfterAccessCheck) {
22998  v8::Isolate* isolate = CcTest::isolate();
22999  v8::HandleScope handle_scope(isolate);
23000  v8::Handle<v8::ObjectTemplate> object_template =
23001      v8::ObjectTemplate::New(isolate);
23002  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23003                                           IndexedAccessCounter);
23004
23005  v8::Handle<Context> context = Context::New(isolate);
23006  v8::Context::Scope context_scope(context);
23007
23008  v8::Handle<v8::Object> obj = object_template->NewInstance();
23009  obj->Set(v8_str("key"), v8_str("value"));
23010  obj->Delete(v8_str("key"));
23011
23012  obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
23013}
23014
23015
23016TEST(Regress411793) {
23017  v8::Isolate* isolate = CcTest::isolate();
23018  v8::HandleScope handle_scope(isolate);
23019  v8::Handle<v8::ObjectTemplate> object_template =
23020      v8::ObjectTemplate::New(isolate);
23021  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23022                                           IndexedAccessCounter);
23023
23024  v8::Handle<Context> context = Context::New(isolate);
23025  v8::Context::Scope context_scope(context);
23026
23027  context->Global()->Set(v8_str("o"), object_template->NewInstance());
23028  CompileRun(
23029      "Object.defineProperty(o, 'key', "
23030      "    { get: function() {}, set: function() {} });");
23031}
23032
23033class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
23034 public:
23035  explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
23036
23037  virtual size_t GetMoreData(const uint8_t** src) {
23038    // Unlike in real use cases, this function will never block.
23039    if (chunks_[index_] == NULL) {
23040      return 0;
23041    }
23042    // Copy the data, since the caller takes ownership of it.
23043    size_t len = strlen(chunks_[index_]);
23044    // We don't need to zero-terminate since we return the length.
23045    uint8_t* copy = new uint8_t[len];
23046    memcpy(copy, chunks_[index_], len);
23047    *src = copy;
23048    ++index_;
23049    return len;
23050  }
23051
23052  // Helper for constructing a string from chunks (the compilation needs it
23053  // too).
23054  static char* FullSourceString(const char** chunks) {
23055    size_t total_len = 0;
23056    for (size_t i = 0; chunks[i] != NULL; ++i) {
23057      total_len += strlen(chunks[i]);
23058    }
23059    char* full_string = new char[total_len + 1];
23060    size_t offset = 0;
23061    for (size_t i = 0; chunks[i] != NULL; ++i) {
23062      size_t len = strlen(chunks[i]);
23063      memcpy(full_string + offset, chunks[i], len);
23064      offset += len;
23065    }
23066    full_string[total_len] = 0;
23067    return full_string;
23068  }
23069
23070 private:
23071  const char** chunks_;
23072  unsigned index_;
23073};
23074
23075
23076// Helper function for running streaming tests.
23077void RunStreamingTest(const char** chunks,
23078                      v8::ScriptCompiler::StreamedSource::Encoding encoding =
23079                          v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23080                      bool expected_success = true) {
23081  LocalContext env;
23082  v8::Isolate* isolate = env->GetIsolate();
23083  v8::HandleScope scope(isolate);
23084  v8::TryCatch try_catch;
23085
23086  v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
23087                                            encoding);
23088  v8::ScriptCompiler::ScriptStreamingTask* task =
23089      v8::ScriptCompiler::StartStreamingScript(isolate, &source);
23090
23091  // TestSourceStream::GetMoreData won't block, so it's OK to just run the
23092  // task here in the main thread.
23093  task->Run();
23094  delete task;
23095
23096  v8::ScriptOrigin origin(v8_str("http://foo.com"));
23097  char* full_source = TestSourceStream::FullSourceString(chunks);
23098
23099  // The possible errors are only produced while compiling.
23100  CHECK_EQ(false, try_catch.HasCaught());
23101
23102  v8::Handle<Script> script = v8::ScriptCompiler::Compile(
23103      isolate, &source, v8_str(full_source), origin);
23104  if (expected_success) {
23105    CHECK(!script.IsEmpty());
23106    v8::Handle<Value> result(script->Run());
23107    // All scripts are supposed to return the fixed value 13 when ran.
23108    CHECK_EQ(13, result->Int32Value());
23109  } else {
23110    CHECK(script.IsEmpty());
23111    CHECK(try_catch.HasCaught());
23112  }
23113  delete[] full_source;
23114}
23115
23116
23117TEST(StreamingSimpleScript) {
23118  // This script is unrealistically small, since no one chunk is enough to fill
23119  // the backing buffer of Scanner, let alone overflow it.
23120  const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
23121                          NULL};
23122  RunStreamingTest(chunks);
23123}
23124
23125
23126TEST(StreamingBiggerScript) {
23127  const char* chunk1 =
23128      "function foo() {\n"
23129      "  // Make this chunk sufficiently long so that it will overflow the\n"
23130      "  // backing buffer of the Scanner.\n"
23131      "  var i = 0;\n"
23132      "  var result = 0;\n"
23133      "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23134      "  result = 0;\n"
23135      "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23136      "  result = 0;\n"
23137      "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23138      "  result = 0;\n"
23139      "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23140      "  return result;\n"
23141      "}\n";
23142  const char* chunks[] = {chunk1, "foo(); ", NULL};
23143  RunStreamingTest(chunks);
23144}
23145
23146
23147TEST(StreamingScriptWithParseError) {
23148  // Test that parse errors from streamed scripts are propagated correctly.
23149  {
23150    char chunk1[] =
23151        "  // This will result in a parse error.\n"
23152        "  var if else then foo";
23153    char chunk2[] = "  13\n";
23154    const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23155
23156    RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23157                     false);
23158  }
23159  // Test that the next script succeeds normally.
23160  {
23161    char chunk1[] =
23162        "  // This will be parsed successfully.\n"
23163        "  function foo() { return ";
23164    char chunk2[] = "  13; }\n";
23165    const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23166
23167    RunStreamingTest(chunks);
23168  }
23169}
23170
23171
23172TEST(StreamingUtf8Script) {
23173  // We'd want to write \uc481 instead of \xeb\x91\x80, but Windows compilers
23174  // don't like it.
23175  const char* chunk1 =
23176      "function foo() {\n"
23177      "  // This function will contain an UTF-8 character which is not in\n"
23178      "  // ASCII.\n"
23179      "  var foob\xeb\x91\x80r = 13;\n"
23180      "  return foob\xeb\x91\x80r;\n"
23181      "}\n";
23182  const char* chunks[] = {chunk1, "foo(); ", NULL};
23183  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23184}
23185
23186
23187TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
23188  // A sanity check to prove that the approach of splitting UTF-8
23189  // characters is correct. Here is an UTF-8 character which will take three
23190  // bytes.
23191  const char* reference = "\xeb\x91\x80";
23192  CHECK(3u == strlen(reference));  // NOLINT - no CHECK_EQ for unsigned.
23193
23194  char chunk1[] =
23195      "function foo() {\n"
23196      "  // This function will contain an UTF-8 character which is not in\n"
23197      "  // ASCII.\n"
23198      "  var foob";
23199  char chunk2[] =
23200      "XXXr = 13;\n"
23201      "  return foob\xeb\x91\x80r;\n"
23202      "}\n";
23203  for (int i = 0; i < 3; ++i) {
23204    chunk2[i] = reference[i];
23205  }
23206  const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23207  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23208}
23209
23210
23211TEST(StreamingUtf8ScriptWithSplitCharacters) {
23212  // Stream data where a multi-byte UTF-8 character is split between two data
23213  // chunks.
23214  const char* reference = "\xeb\x91\x80";
23215  char chunk1[] =
23216      "function foo() {\n"
23217      "  // This function will contain an UTF-8 character which is not in\n"
23218      "  // ASCII.\n"
23219      "  var foobX";
23220  char chunk2[] =
23221      "XXr = 13;\n"
23222      "  return foob\xeb\x91\x80r;\n"
23223      "}\n";
23224  chunk1[strlen(chunk1) - 1] = reference[0];
23225  chunk2[0] = reference[1];
23226  chunk2[1] = reference[2];
23227  const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23228  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23229}
23230
23231
23232TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
23233  // Tests edge cases which should still be decoded correctly.
23234
23235  // Case 1: a chunk contains only bytes for a split character (and no other
23236  // data). This kind of a chunk would be exceptionally small, but we should
23237  // still decode it correctly.
23238  const char* reference = "\xeb\x91\x80";
23239  // The small chunk is at the beginning of the split character
23240  {
23241    char chunk1[] =
23242        "function foo() {\n"
23243        "  // This function will contain an UTF-8 character which is not in\n"
23244        "  // ASCII.\n"
23245        "  var foob";
23246    char chunk2[] = "XX";
23247    char chunk3[] =
23248        "Xr = 13;\n"
23249        "  return foob\xeb\x91\x80r;\n"
23250        "}\n";
23251    chunk2[0] = reference[0];
23252    chunk2[1] = reference[1];
23253    chunk3[0] = reference[2];
23254    const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23255    RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23256  }
23257  // The small chunk is at the end of a character
23258  {
23259    char chunk1[] =
23260        "function foo() {\n"
23261        "  // This function will contain an UTF-8 character which is not in\n"
23262        "  // ASCII.\n"
23263        "  var foobX";
23264    char chunk2[] = "XX";
23265    char chunk3[] =
23266        "r = 13;\n"
23267        "  return foob\xeb\x91\x80r;\n"
23268        "}\n";
23269    chunk1[strlen(chunk1) - 1] = reference[0];
23270    chunk2[0] = reference[1];
23271    chunk2[1] = reference[2];
23272    const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23273    RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23274  }
23275  // Case 2: the script ends with a multi-byte character. Make sure that it's
23276  // decoded correctly and not just ignored.
23277  {
23278    char chunk1[] =
23279        "var foob\xeb\x91\x80 = 13;\n"
23280        "foob\xeb\x91\x80";
23281    const char* chunks[] = {chunk1, NULL};
23282    RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23283  }
23284}
23285
23286
23287TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
23288  // Test cases where a UTF-8 character is split over several chunks. Those
23289  // cases are not supported (the embedder should give the data in big enough
23290  // chunks), but we shouldn't crash, just produce a parse error.
23291  const char* reference = "\xeb\x91\x80";
23292  char chunk1[] =
23293      "function foo() {\n"
23294      "  // This function will contain an UTF-8 character which is not in\n"
23295      "  // ASCII.\n"
23296      "  var foobX";
23297  char chunk2[] = "X";
23298  char chunk3[] =
23299      "Xr = 13;\n"
23300      "  return foob\xeb\x91\x80r;\n"
23301      "}\n";
23302  chunk1[strlen(chunk1) - 1] = reference[0];
23303  chunk2[0] = reference[1];
23304  chunk3[0] = reference[2];
23305  const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23306
23307  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
23308}
23309
23310
23311TEST(StreamingProducesParserCache) {
23312  i::FLAG_min_preparse_length = 0;
23313  const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
23314                          NULL};
23315
23316  LocalContext env;
23317  v8::Isolate* isolate = env->GetIsolate();
23318  v8::HandleScope scope(isolate);
23319
23320  v8::ScriptCompiler::StreamedSource source(
23321      new TestSourceStream(chunks),
23322      v8::ScriptCompiler::StreamedSource::ONE_BYTE);
23323  v8::ScriptCompiler::ScriptStreamingTask* task =
23324      v8::ScriptCompiler::StartStreamingScript(
23325          isolate, &source, v8::ScriptCompiler::kProduceParserCache);
23326
23327  // TestSourceStream::GetMoreData won't block, so it's OK to just run the
23328  // task here in the main thread.
23329  task->Run();
23330  delete task;
23331
23332  const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
23333  CHECK(cached_data != NULL);
23334  CHECK(cached_data->data != NULL);
23335  CHECK_GT(cached_data->length, 0);
23336}
23337
23338
23339TEST(StreamingScriptWithInvalidUtf8) {
23340  // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
23341  // chunk don't produce a crash.
23342  const char* reference = "\xeb\x91\x80\x80\x80";
23343  char chunk1[] =
23344      "function foo() {\n"
23345      "  // This function will contain an UTF-8 character which is not in\n"
23346      "  // ASCII.\n"
23347      "  var foobXXXXX";  // Too many bytes which look like incomplete chars!
23348  char chunk2[] =
23349      "r = 13;\n"
23350      "  return foob\xeb\x91\x80\x80\x80r;\n"
23351      "}\n";
23352  for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
23353
23354  const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23355  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
23356}
23357