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(