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
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.
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.
36 #include <unistd.h> // NOLINT
40 #include "arguments.h"
42 #include "compilation-cache.h"
43 #include "cpu-profiler.h"
44 #include "execution.h"
50 #include "unicode-inl.h"
54 static const bool kLogThreading = false;
57 using ::v8::BooleanObject;
59 using ::v8::Extension;
61 using ::v8::FunctionTemplate;
63 using ::v8::HandleScope;
66 using ::v8::MessageCallback;
68 using ::v8::ObjectTemplate;
69 using ::v8::Persistent;
71 using ::v8::StackTrace;
74 using ::v8::Undefined;
80 #define THREADED_PROFILED_TEST(Name) \
81 static void Test##Name(); \
82 TEST(Name##WithProfiler) { \
83 RunWithProfiler(&Test##Name); \
87 void RunWithProfiler(void (*test)()) {
89 v8::HandleScope scope(env->GetIsolate());
90 v8::Local<v8::String> profile_name = v8::String::New("my_profile1");
91 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
93 cpu_profiler->StartCpuProfiling(profile_name);
95 cpu_profiler->DeleteAllCpuProfiles();
99 static void ExpectString(const char* code, const char* expected) {
100 Local<Value> result = CompileRun(code);
101 CHECK(result->IsString());
102 String::Utf8Value utf8(result);
103 CHECK_EQ(expected, *utf8);
107 static void ExpectInt32(const char* code, int expected) {
108 Local<Value> result = CompileRun(code);
109 CHECK(result->IsInt32());
110 CHECK_EQ(expected, result->Int32Value());
114 static void ExpectBoolean(const char* code, bool expected) {
115 Local<Value> result = CompileRun(code);
116 CHECK(result->IsBoolean());
117 CHECK_EQ(expected, result->BooleanValue());
121 static void ExpectTrue(const char* code) {
122 ExpectBoolean(code, true);
126 static void ExpectFalse(const char* code) {
127 ExpectBoolean(code, false);
131 static void ExpectObject(const char* code, Local<Value> expected) {
132 Local<Value> result = CompileRun(code);
133 CHECK(result->Equals(expected));
137 static void ExpectUndefined(const char* code) {
138 Local<Value> result = CompileRun(code);
139 CHECK(result->IsUndefined());
143 static int signature_callback_count;
144 static Local<Value> signature_expected_receiver;
145 static void IncrementingSignatureCallback(
146 const v8::FunctionCallbackInfo<v8::Value>& args) {
147 ApiTestFuzzer::Fuzz();
148 signature_callback_count++;
149 CHECK_EQ(signature_expected_receiver, args.Holder());
150 CHECK_EQ(signature_expected_receiver, args.This());
151 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
152 for (int i = 0; i < args.Length(); i++)
153 result->Set(v8::Integer::New(i), args[i]);
154 args.GetReturnValue().Set(result);
158 static void SignatureCallback(
159 const v8::FunctionCallbackInfo<v8::Value>& args) {
160 ApiTestFuzzer::Fuzz();
161 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
162 for (int i = 0; i < args.Length(); i++) {
163 result->Set(v8::Integer::New(i), args[i]);
165 args.GetReturnValue().Set(result);
169 // Tests that call v8::V8::Dispose() cannot be threaded.
170 TEST(InitializeAndDisposeOnce) {
171 CHECK(v8::V8::Initialize());
172 CHECK(v8::V8::Dispose());
176 // Tests that call v8::V8::Dispose() cannot be threaded.
177 TEST(InitializeAndDisposeMultiple) {
178 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
179 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
180 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
181 // TODO(mstarzinger): This should fail gracefully instead of asserting.
182 // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
183 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
187 THREADED_TEST(Handles) {
188 v8::HandleScope scope(v8::Isolate::GetCurrent());
189 Local<Context> local_env;
192 local_env = env.local();
195 // Local context should still be live.
196 CHECK(!local_env.IsEmpty());
199 v8::Handle<v8::Primitive> undef = v8::Undefined();
200 CHECK(!undef.IsEmpty());
201 CHECK(undef->IsUndefined());
203 const char* c_source = "1 + 2 + 3";
204 Local<String> source = String::New(c_source);
205 Local<Script> script = Script::Compile(source);
206 CHECK_EQ(6, script->Run()->Int32Value());
212 THREADED_TEST(IsolateOfContext) {
213 v8::HandleScope scope(v8::Isolate::GetCurrent());
214 v8::Handle<Context> env = Context::New(v8::Isolate::GetCurrent());
216 CHECK(!env->InContext());
217 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
219 CHECK(env->InContext());
220 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
222 CHECK(!env->InContext());
223 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
227 static void TestSignature(const char* loop_js, Local<Value> receiver) {
228 i::ScopedVector<char> source(200);
229 i::OS::SNPrintF(source,
230 "for (var i = 0; i < 10; i++) {"
234 signature_callback_count = 0;
235 signature_expected_receiver = receiver;
236 bool expected_to_throw = receiver.IsEmpty();
237 v8::TryCatch try_catch;
238 CompileRun(source.start());
239 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
240 if (!expected_to_throw) {
241 CHECK_EQ(10, signature_callback_count);
243 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
244 try_catch.Exception()->ToString());
249 THREADED_TEST(ReceiverSignature) {
251 v8::HandleScope scope(env->GetIsolate());
253 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
254 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
255 v8::Handle<v8::FunctionTemplate> callback_sig =
256 v8::FunctionTemplate::New(
257 IncrementingSignatureCallback, Local<Value>(), sig);
258 v8::Handle<v8::FunctionTemplate> callback =
259 v8::FunctionTemplate::New(IncrementingSignatureCallback);
260 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
261 sub_fun->Inherit(fun);
262 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
263 // Install properties.
264 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
265 fun_proto->Set(v8_str("prop_sig"), callback_sig);
266 fun_proto->Set(v8_str("prop"), callback);
267 fun_proto->SetAccessorProperty(
268 v8_str("accessor_sig"), callback_sig, callback_sig);
269 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
270 // Instantiate templates.
271 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
272 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
273 // Setup global variables.
274 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
275 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
276 env->Global()->Set(v8_str("fun_instance"), fun_instance);
277 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
279 "var accessor_sig_key = 'accessor_sig';"
280 "var accessor_key = 'accessor';"
281 "var prop_sig_key = 'prop_sig';"
282 "var prop_key = 'prop';"
284 "function copy_props(obj) {"
285 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
286 " var source = Fun.prototype;"
287 " for (var i in keys) {"
288 " var key = keys[i];"
289 " var desc = Object.getOwnPropertyDescriptor(source, key);"
290 " Object.defineProperty(obj, key, desc);"
296 "var unrel = new UnrelFun();"
297 "copy_props(unrel);");
298 // Test with and without ICs
299 const char* test_objects[] = {
300 "fun_instance", "sub_fun_instance", "obj", "unrel" };
301 unsigned bad_signature_start_offset = 2;
302 for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
303 i::ScopedVector<char> source(200);
305 source, "var test_object = %s; test_object", test_objects[i]);
306 Local<Value> test_object = CompileRun(source.start());
307 TestSignature("test_object.prop();", test_object);
308 TestSignature("test_object.accessor;", test_object);
309 TestSignature("test_object[accessor_key];", test_object);
310 TestSignature("test_object.accessor = 1;", test_object);
311 TestSignature("test_object[accessor_key] = 1;", test_object);
312 if (i >= bad_signature_start_offset) test_object = Local<Value>();
313 TestSignature("test_object.prop_sig();", test_object);
314 TestSignature("test_object.accessor_sig;", test_object);
315 TestSignature("test_object[accessor_sig_key];", test_object);
316 TestSignature("test_object.accessor_sig = 1;", test_object);
317 TestSignature("test_object[accessor_sig_key] = 1;", test_object);
322 THREADED_TEST(ArgumentSignature) {
324 v8::HandleScope scope(env->GetIsolate());
325 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
326 cons->SetClassName(v8_str("Cons"));
327 v8::Handle<v8::Signature> sig =
328 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
329 v8::Handle<v8::FunctionTemplate> fun =
330 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
331 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
332 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
334 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
335 CHECK(value1->IsTrue());
337 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
338 CHECK(value2->IsTrue());
340 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
341 CHECK(value3->IsTrue());
343 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
344 cons1->SetClassName(v8_str("Cons1"));
345 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
346 cons2->SetClassName(v8_str("Cons2"));
347 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
348 cons3->SetClassName(v8_str("Cons3"));
350 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
351 v8::Handle<v8::Signature> wsig =
352 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
353 v8::Handle<v8::FunctionTemplate> fun2 =
354 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
356 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
357 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
358 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
359 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
360 v8::Handle<Value> value4 = CompileRun(
361 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
362 "'[object Cons1],[object Cons2],[object Cons3]'");
363 CHECK(value4->IsTrue());
365 v8::Handle<Value> value5 = CompileRun(
366 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
367 CHECK(value5->IsTrue());
369 v8::Handle<Value> value6 = CompileRun(
370 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
371 CHECK(value6->IsTrue());
373 v8::Handle<Value> value7 = CompileRun(
374 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
375 "'[object Cons1],[object Cons2],[object Cons3],d';");
376 CHECK(value7->IsTrue());
378 v8::Handle<Value> value8 = CompileRun(
379 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
380 CHECK(value8->IsTrue());
384 THREADED_TEST(HulIgennem) {
386 v8::HandleScope scope(env->GetIsolate());
387 v8::Handle<v8::Primitive> undef = v8::Undefined();
388 Local<String> undef_str = undef->ToString();
389 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
390 undef_str->WriteUtf8(value);
391 CHECK_EQ(0, strcmp(value, "undefined"));
392 i::DeleteArray(value);
396 THREADED_TEST(Access) {
398 v8::HandleScope scope(env->GetIsolate());
399 Local<v8::Object> obj = v8::Object::New();
400 Local<Value> foo_before = obj->Get(v8_str("foo"));
401 CHECK(foo_before->IsUndefined());
402 Local<String> bar_str = v8_str("bar");
403 obj->Set(v8_str("foo"), bar_str);
404 Local<Value> foo_after = obj->Get(v8_str("foo"));
405 CHECK(!foo_after->IsUndefined());
406 CHECK(foo_after->IsString());
407 CHECK_EQ(bar_str, foo_after);
411 THREADED_TEST(AccessElement) {
413 v8::HandleScope scope(env->GetIsolate());
414 Local<v8::Object> obj = v8::Object::New();
415 Local<Value> before = obj->Get(1);
416 CHECK(before->IsUndefined());
417 Local<String> bar_str = v8_str("bar");
418 obj->Set(1, bar_str);
419 Local<Value> after = obj->Get(1);
420 CHECK(!after->IsUndefined());
421 CHECK(after->IsString());
422 CHECK_EQ(bar_str, after);
424 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
425 CHECK_EQ(v8_str("a"), value->Get(0));
426 CHECK_EQ(v8_str("b"), value->Get(1));
430 THREADED_TEST(Script) {
432 v8::HandleScope scope(env->GetIsolate());
433 const char* c_source = "1 + 2 + 3";
434 Local<String> source = String::New(c_source);
435 Local<Script> script = Script::Compile(source);
436 CHECK_EQ(6, script->Run()->Int32Value());
440 static uint16_t* AsciiToTwoByteString(const char* source) {
441 int array_length = i::StrLength(source) + 1;
442 uint16_t* converted = i::NewArray<uint16_t>(array_length);
443 for (int i = 0; i < array_length; i++) converted[i] = source[i];
448 class TestResource: public String::ExternalStringResource {
450 explicit TestResource(uint16_t* data, int* counter = NULL)
451 : data_(data), length_(0), counter_(counter) {
452 while (data[length_]) ++length_;
456 i::DeleteArray(data_);
457 if (counter_ != NULL) ++*counter_;
460 const uint16_t* data() const {
464 size_t length() const {
474 class TestAsciiResource: public String::ExternalAsciiStringResource {
476 explicit TestAsciiResource(const char* data, int* counter = NULL)
477 : data_(data), length_(strlen(data)), counter_(counter) { }
479 ~TestAsciiResource() {
480 i::DeleteArray(data_);
481 if (counter_ != NULL) ++*counter_;
484 const char* data() const {
488 size_t length() const {
498 THREADED_TEST(ScriptUsingStringResource) {
499 int dispose_count = 0;
500 const char* c_source = "1 + 2 * 3";
501 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
504 v8::HandleScope scope(env->GetIsolate());
505 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
506 Local<String> source = String::NewExternal(resource);
507 Local<Script> script = Script::Compile(source);
508 Local<Value> value = script->Run();
509 CHECK(value->IsNumber());
510 CHECK_EQ(7, value->Int32Value());
511 CHECK(source->IsExternal());
513 static_cast<TestResource*>(source->GetExternalStringResource()));
514 String::Encoding encoding = String::UNKNOWN_ENCODING;
515 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
516 source->GetExternalStringResourceBase(&encoding));
517 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
518 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
519 CHECK_EQ(0, dispose_count);
521 v8::internal::Isolate::Current()->compilation_cache()->Clear();
522 HEAP->CollectAllAvailableGarbage();
523 CHECK_EQ(1, dispose_count);
527 THREADED_TEST(ScriptUsingAsciiStringResource) {
528 int dispose_count = 0;
529 const char* c_source = "1 + 2 * 3";
532 v8::HandleScope scope(env->GetIsolate());
533 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
535 Local<String> source = String::NewExternal(resource);
536 CHECK(source->IsExternalAscii());
537 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
538 source->GetExternalAsciiStringResource());
539 String::Encoding encoding = String::UNKNOWN_ENCODING;
540 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
541 source->GetExternalStringResourceBase(&encoding));
542 CHECK_EQ(String::ASCII_ENCODING, encoding);
543 Local<Script> script = Script::Compile(source);
544 Local<Value> value = script->Run();
545 CHECK(value->IsNumber());
546 CHECK_EQ(7, value->Int32Value());
547 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
548 CHECK_EQ(0, dispose_count);
550 i::Isolate::Current()->compilation_cache()->Clear();
551 HEAP->CollectAllAvailableGarbage();
552 CHECK_EQ(1, dispose_count);
556 THREADED_TEST(ScriptMakingExternalString) {
557 int dispose_count = 0;
558 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
561 v8::HandleScope scope(env->GetIsolate());
562 Local<String> source = String::New(two_byte_source);
563 // Trigger GCs so that the newly allocated string moves to old gen.
564 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
565 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
566 CHECK_EQ(source->IsExternal(), false);
567 CHECK_EQ(source->IsExternalAscii(), false);
568 String::Encoding encoding = String::UNKNOWN_ENCODING;
569 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
570 CHECK_EQ(String::ASCII_ENCODING, encoding);
571 bool success = source->MakeExternal(new TestResource(two_byte_source,
574 Local<Script> script = Script::Compile(source);
575 Local<Value> value = script->Run();
576 CHECK(value->IsNumber());
577 CHECK_EQ(7, value->Int32Value());
578 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
579 CHECK_EQ(0, dispose_count);
581 i::Isolate::Current()->compilation_cache()->Clear();
582 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
583 CHECK_EQ(1, dispose_count);
587 THREADED_TEST(ScriptMakingExternalAsciiString) {
588 int dispose_count = 0;
589 const char* c_source = "1 + 2 * 3";
592 v8::HandleScope scope(env->GetIsolate());
593 Local<String> source = v8_str(c_source);
594 // Trigger GCs so that the newly allocated string moves to old gen.
595 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
596 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
597 bool success = source->MakeExternal(
598 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
600 Local<Script> script = Script::Compile(source);
601 Local<Value> value = script->Run();
602 CHECK(value->IsNumber());
603 CHECK_EQ(7, value->Int32Value());
604 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
605 CHECK_EQ(0, dispose_count);
607 i::Isolate::Current()->compilation_cache()->Clear();
608 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
609 CHECK_EQ(1, dispose_count);
613 TEST(MakingExternalStringConditions) {
615 v8::HandleScope scope(env->GetIsolate());
617 // Free some space in the new space so that we can check freshness.
618 HEAP->CollectGarbage(i::NEW_SPACE);
619 HEAP->CollectGarbage(i::NEW_SPACE);
621 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
622 Local<String> small_string = String::New(two_byte_string);
623 i::DeleteArray(two_byte_string);
625 // We should refuse to externalize newly created small string.
626 CHECK(!small_string->CanMakeExternal());
627 // Trigger GCs so that the newly allocated string moves to old gen.
628 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
629 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
630 // Old space strings should be accepted.
631 CHECK(small_string->CanMakeExternal());
633 two_byte_string = AsciiToTwoByteString("small string 2");
634 small_string = String::New(two_byte_string);
635 i::DeleteArray(two_byte_string);
637 // We should refuse externalizing newly created small string.
638 CHECK(!small_string->CanMakeExternal());
639 for (int i = 0; i < 100; i++) {
640 String::Value value(small_string);
642 // Frequently used strings should be accepted.
643 CHECK(small_string->CanMakeExternal());
645 const int buf_size = 10 * 1024;
646 char* buf = i::NewArray<char>(buf_size);
647 memset(buf, 'a', buf_size);
648 buf[buf_size - 1] = '\0';
650 two_byte_string = AsciiToTwoByteString(buf);
651 Local<String> large_string = String::New(two_byte_string);
653 i::DeleteArray(two_byte_string);
654 // Large strings should be immediately accepted.
655 CHECK(large_string->CanMakeExternal());
659 TEST(MakingExternalAsciiStringConditions) {
661 v8::HandleScope scope(env->GetIsolate());
663 // Free some space in the new space so that we can check freshness.
664 HEAP->CollectGarbage(i::NEW_SPACE);
665 HEAP->CollectGarbage(i::NEW_SPACE);
667 Local<String> small_string = String::New("s1");
668 // We should refuse to externalize newly created small string.
669 CHECK(!small_string->CanMakeExternal());
670 // Trigger GCs so that the newly allocated string moves to old gen.
671 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
672 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
673 // Old space strings should be accepted.
674 CHECK(small_string->CanMakeExternal());
676 small_string = String::New("small string 2");
677 // We should refuse externalizing newly created small string.
678 CHECK(!small_string->CanMakeExternal());
679 for (int i = 0; i < 100; i++) {
680 String::Value value(small_string);
682 // Frequently used strings should be accepted.
683 CHECK(small_string->CanMakeExternal());
685 const int buf_size = 10 * 1024;
686 char* buf = i::NewArray<char>(buf_size);
687 memset(buf, 'a', buf_size);
688 buf[buf_size - 1] = '\0';
689 Local<String> large_string = String::New(buf);
691 // Large strings should be immediately accepted.
692 CHECK(large_string->CanMakeExternal());
696 TEST(MakingExternalUnalignedAsciiString) {
698 v8::HandleScope scope(env->GetIsolate());
700 CompileRun("function cons(a, b) { return a + b; }"
701 "function slice(a) { return a.substring(1); }");
702 // Create a cons string that will land in old pointer space.
703 Local<String> cons = Local<String>::Cast(CompileRun(
704 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
705 // Create a sliced string that will land in old pointer space.
706 Local<String> slice = Local<String>::Cast(CompileRun(
707 "slice('abcdefghijklmnopqrstuvwxyz');"));
709 // Trigger GCs so that the newly allocated string moves to old gen.
710 SimulateFullSpace(HEAP->old_pointer_space());
711 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
712 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
714 // Turn into external string with unaligned resource data.
715 int dispose_count = 0;
716 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
717 bool success = cons->MakeExternal(
718 new TestAsciiResource(i::StrDup(c_cons) + 1, &dispose_count));
720 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
721 success = slice->MakeExternal(
722 new TestAsciiResource(i::StrDup(c_slice) + 1, &dispose_count));
725 // Trigger GCs and force evacuation.
726 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
727 HEAP->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
731 THREADED_TEST(UsingExternalString) {
732 i::Factory* factory = i::Isolate::Current()->factory();
734 v8::HandleScope scope(v8::Isolate::GetCurrent());
735 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
736 Local<String> string =
737 String::NewExternal(new TestResource(two_byte_string));
738 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
739 // Trigger GCs so that the newly allocated string moves to old gen.
740 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
741 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
742 i::Handle<i::String> isymbol =
743 factory->InternalizedStringFromString(istring);
744 CHECK(isymbol->IsInternalizedString());
746 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
747 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
751 THREADED_TEST(UsingExternalAsciiString) {
752 i::Factory* factory = i::Isolate::Current()->factory();
754 v8::HandleScope scope(v8::Isolate::GetCurrent());
755 const char* one_byte_string = "test string";
756 Local<String> string = String::NewExternal(
757 new TestAsciiResource(i::StrDup(one_byte_string)));
758 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
759 // Trigger GCs so that the newly allocated string moves to old gen.
760 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
761 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
762 i::Handle<i::String> isymbol =
763 factory->InternalizedStringFromString(istring);
764 CHECK(isymbol->IsInternalizedString());
766 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
767 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
771 THREADED_TEST(ScavengeExternalString) {
772 i::FLAG_stress_compaction = false;
773 i::FLAG_gc_global = false;
774 int dispose_count = 0;
775 bool in_new_space = false;
777 v8::HandleScope scope(v8::Isolate::GetCurrent());
778 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
779 Local<String> string =
780 String::NewExternal(new TestResource(two_byte_string,
782 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
783 HEAP->CollectGarbage(i::NEW_SPACE);
784 in_new_space = HEAP->InNewSpace(*istring);
785 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
786 CHECK_EQ(0, dispose_count);
788 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
789 CHECK_EQ(1, dispose_count);
793 THREADED_TEST(ScavengeExternalAsciiString) {
794 i::FLAG_stress_compaction = false;
795 i::FLAG_gc_global = false;
796 int dispose_count = 0;
797 bool in_new_space = false;
799 v8::HandleScope scope(v8::Isolate::GetCurrent());
800 const char* one_byte_string = "test string";
801 Local<String> string = String::NewExternal(
802 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
803 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
804 HEAP->CollectGarbage(i::NEW_SPACE);
805 in_new_space = HEAP->InNewSpace(*istring);
806 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
807 CHECK_EQ(0, dispose_count);
809 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
810 CHECK_EQ(1, dispose_count);
814 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
816 // Only used by non-threaded tests, so it can use static fields.
817 static int dispose_calls;
818 static int dispose_count;
820 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
821 : TestAsciiResource(data, &dispose_count),
822 dispose_(dispose) { }
826 if (dispose_) delete this;
833 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
834 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
837 TEST(ExternalStringWithDisposeHandling) {
838 const char* c_source = "1 + 2 * 3";
840 // Use a stack allocated external string resource allocated object.
841 TestAsciiResourceWithDisposeControl::dispose_count = 0;
842 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
843 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
846 v8::HandleScope scope(env->GetIsolate());
847 Local<String> source = String::NewExternal(&res_stack);
848 Local<Script> script = Script::Compile(source);
849 Local<Value> value = script->Run();
850 CHECK(value->IsNumber());
851 CHECK_EQ(7, value->Int32Value());
852 HEAP->CollectAllAvailableGarbage();
853 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
855 i::Isolate::Current()->compilation_cache()->Clear();
856 HEAP->CollectAllAvailableGarbage();
857 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
858 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
860 // Use a heap allocated external string resource allocated object.
861 TestAsciiResourceWithDisposeControl::dispose_count = 0;
862 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
863 TestAsciiResource* res_heap =
864 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
867 v8::HandleScope scope(env->GetIsolate());
868 Local<String> source = String::NewExternal(res_heap);
869 Local<Script> script = Script::Compile(source);
870 Local<Value> value = script->Run();
871 CHECK(value->IsNumber());
872 CHECK_EQ(7, value->Int32Value());
873 HEAP->CollectAllAvailableGarbage();
874 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
876 i::Isolate::Current()->compilation_cache()->Clear();
877 HEAP->CollectAllAvailableGarbage();
878 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
879 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
883 THREADED_TEST(StringConcat) {
886 v8::HandleScope scope(env->GetIsolate());
887 const char* one_byte_string_1 = "function a_times_t";
888 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
889 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
890 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
891 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
892 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
893 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
894 Local<String> left = v8_str(one_byte_string_1);
896 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
897 Local<String> right = String::New(two_byte_source);
898 i::DeleteArray(two_byte_source);
900 Local<String> source = String::Concat(left, right);
901 right = String::NewExternal(
902 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
903 source = String::Concat(source, right);
904 right = String::NewExternal(
905 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
906 source = String::Concat(source, right);
907 right = v8_str(one_byte_string_2);
908 source = String::Concat(source, right);
910 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
911 right = String::New(two_byte_source);
912 i::DeleteArray(two_byte_source);
914 source = String::Concat(source, right);
915 right = String::NewExternal(
916 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
917 source = String::Concat(source, right);
918 Local<Script> script = Script::Compile(source);
919 Local<Value> value = script->Run();
920 CHECK(value->IsNumber());
921 CHECK_EQ(68, value->Int32Value());
923 i::Isolate::Current()->compilation_cache()->Clear();
924 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
925 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
929 THREADED_TEST(GlobalProperties) {
931 v8::HandleScope scope(env->GetIsolate());
932 v8::Handle<v8::Object> global = env->Global();
933 global->Set(v8_str("pi"), v8_num(3.1415926));
934 Local<Value> pi = global->Get(v8_str("pi"));
935 CHECK_EQ(3.1415926, pi->NumberValue());
940 static void CheckReturnValue(const T& t, i::Address callback) {
941 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
942 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
943 CHECK_EQ(v8::Isolate::GetCurrent(), t.GetIsolate());
944 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
945 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
947 bool is_runtime = (*o)->IsTheHole();
949 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
950 rv.Set(v8::Handle<v8::Object>());
951 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
952 CHECK_EQ(is_runtime, (*o)->IsTheHole());
954 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
955 // If CPU profiler is active check that when API callback is invoked
956 // VMState is set to EXTERNAL.
957 if (isolate->cpu_profiler()->is_profiling()) {
958 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
959 CHECK(isolate->external_callback_scope());
960 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
965 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
966 i::Address callback) {
967 ApiTestFuzzer::Fuzz();
968 CheckReturnValue(info, callback);
969 info.GetReturnValue().Set(v8_str("bad value"));
970 info.GetReturnValue().Set(v8_num(102));
974 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
975 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
979 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
980 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
983 static void construct_callback(
984 const v8::FunctionCallbackInfo<Value>& info) {
985 ApiTestFuzzer::Fuzz();
986 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
987 info.This()->Set(v8_str("x"), v8_num(1));
988 info.This()->Set(v8_str("y"), v8_num(2));
989 info.GetReturnValue().Set(v8_str("bad value"));
990 info.GetReturnValue().Set(info.This());
994 static void Return239Callback(
995 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
996 ApiTestFuzzer::Fuzz();
997 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
998 info.GetReturnValue().Set(v8_str("bad value"));
999 info.GetReturnValue().Set(v8_num(239));
1003 template<typename Handler>
1004 static void TestFunctionTemplateInitializer(Handler handler,
1005 Handler handler_2) {
1006 // Test constructor calls.
1009 v8::HandleScope scope(env->GetIsolate());
1011 Local<v8::FunctionTemplate> fun_templ =
1012 v8::FunctionTemplate::New(handler);
1013 Local<Function> fun = fun_templ->GetFunction();
1014 env->Global()->Set(v8_str("obj"), fun);
1015 Local<Script> script = v8_compile("obj()");
1016 for (int i = 0; i < 30; i++) {
1017 CHECK_EQ(102, script->Run()->Int32Value());
1020 // Use SetCallHandler to initialize a function template, should work like
1021 // the previous one.
1024 v8::HandleScope scope(env->GetIsolate());
1026 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1027 fun_templ->SetCallHandler(handler_2);
1028 Local<Function> fun = fun_templ->GetFunction();
1029 env->Global()->Set(v8_str("obj"), fun);
1030 Local<Script> script = v8_compile("obj()");
1031 for (int i = 0; i < 30; i++) {
1032 CHECK_EQ(102, script->Run()->Int32Value());
1038 template<typename Constructor, typename Accessor>
1039 static void TestFunctionTemplateAccessor(Constructor constructor,
1040 Accessor accessor) {
1042 v8::HandleScope scope(env->GetIsolate());
1044 Local<v8::FunctionTemplate> fun_templ =
1045 v8::FunctionTemplate::New(constructor);
1046 fun_templ->SetClassName(v8_str("funky"));
1047 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1048 Local<Function> fun = fun_templ->GetFunction();
1049 env->Global()->Set(v8_str("obj"), fun);
1050 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1051 CHECK_EQ(v8_str("[object funky]"), result);
1052 CompileRun("var obj_instance = new obj();");
1053 Local<Script> script;
1054 script = v8_compile("obj_instance.x");
1055 for (int i = 0; i < 30; i++) {
1056 CHECK_EQ(1, script->Run()->Int32Value());
1058 script = v8_compile("obj_instance.m");
1059 for (int i = 0; i < 30; i++) {
1060 CHECK_EQ(239, script->Run()->Int32Value());
1065 THREADED_PROFILED_TEST(FunctionTemplate) {
1066 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1067 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1071 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1072 ApiTestFuzzer::Fuzz();
1073 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1074 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1078 template<typename Callback>
1079 static void TestSimpleCallback(Callback callback) {
1081 v8::HandleScope scope(env->GetIsolate());
1083 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
1084 object_template->Set("callback", v8::FunctionTemplate::New(callback));
1085 v8::Local<v8::Object> object = object_template->NewInstance();
1086 (*env)->Global()->Set(v8_str("callback_object"), object);
1087 v8::Handle<v8::Script> script;
1088 script = v8_compile("callback_object.callback(17)");
1089 for (int i = 0; i < 30; i++) {
1090 CHECK_EQ(51424, script->Run()->Int32Value());
1092 script = v8_compile("callback_object.callback(17, 24)");
1093 for (int i = 0; i < 30; i++) {
1094 CHECK_EQ(51425, script->Run()->Int32Value());
1099 THREADED_PROFILED_TEST(SimpleCallback) {
1100 TestSimpleCallback(SimpleCallback);
1104 template<typename T>
1105 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1107 // constant return values
1108 static int32_t fast_return_value_int32 = 471;
1109 static uint32_t fast_return_value_uint32 = 571;
1110 static const double kFastReturnValueDouble = 2.7;
1111 // variable return values
1112 static bool fast_return_value_bool = false;
1113 enum ReturnValueOddball {
1115 kUndefinedReturnValue,
1116 kEmptyStringReturnValue
1118 static ReturnValueOddball fast_return_value_void;
1119 static bool fast_return_value_object_is_empty = false;
1121 // Helper function to avoid compiler error: insufficient contextual information
1122 // to determine type when applying FUNCTION_ADDR to a template function.
1123 static i::Address address_of(v8::FunctionCallback callback) {
1124 return FUNCTION_ADDR(callback);
1128 void FastReturnValueCallback<int32_t>(
1129 const v8::FunctionCallbackInfo<v8::Value>& info) {
1130 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1131 info.GetReturnValue().Set(fast_return_value_int32);
1135 void FastReturnValueCallback<uint32_t>(
1136 const v8::FunctionCallbackInfo<v8::Value>& info) {
1137 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1138 info.GetReturnValue().Set(fast_return_value_uint32);
1142 void FastReturnValueCallback<double>(
1143 const v8::FunctionCallbackInfo<v8::Value>& info) {
1144 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1145 info.GetReturnValue().Set(kFastReturnValueDouble);
1149 void FastReturnValueCallback<bool>(
1150 const v8::FunctionCallbackInfo<v8::Value>& info) {
1151 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1152 info.GetReturnValue().Set(fast_return_value_bool);
1156 void FastReturnValueCallback<void>(
1157 const v8::FunctionCallbackInfo<v8::Value>& info) {
1158 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1159 switch (fast_return_value_void) {
1160 case kNullReturnValue:
1161 info.GetReturnValue().SetNull();
1163 case kUndefinedReturnValue:
1164 info.GetReturnValue().SetUndefined();
1166 case kEmptyStringReturnValue:
1167 info.GetReturnValue().SetEmptyString();
1173 void FastReturnValueCallback<Object>(
1174 const v8::FunctionCallbackInfo<v8::Value>& info) {
1175 v8::Handle<v8::Object> object;
1176 if (!fast_return_value_object_is_empty) object = Object::New();
1177 info.GetReturnValue().Set(object);
1180 template<typename T>
1181 Handle<Value> TestFastReturnValues() {
1183 v8::HandleScope scope(env->GetIsolate());
1184 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
1185 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1186 object_template->Set("callback", v8::FunctionTemplate::New(callback));
1187 v8::Local<v8::Object> object = object_template->NewInstance();
1188 (*env)->Global()->Set(v8_str("callback_object"), object);
1189 return scope.Close(CompileRun("callback_object.callback()"));
1193 THREADED_PROFILED_TEST(FastReturnValues) {
1195 v8::HandleScope scope(v8::Isolate::GetCurrent());
1196 v8::Handle<v8::Value> value;
1197 // check int32_t and uint32_t
1198 int32_t int_values[] = {
1200 i::Smi::kMinValue, i::Smi::kMaxValue
1202 for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1203 for (int modifier = -1; modifier <= 1; modifier++) {
1204 int int_value = int_values[i] + modifier;
1206 fast_return_value_int32 = int_value;
1207 value = TestFastReturnValues<int32_t>();
1208 CHECK(value->IsInt32());
1209 CHECK(fast_return_value_int32 == value->Int32Value());
1211 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1212 value = TestFastReturnValues<uint32_t>();
1213 CHECK(value->IsUint32());
1214 CHECK(fast_return_value_uint32 == value->Uint32Value());
1218 value = TestFastReturnValues<double>();
1219 CHECK(value->IsNumber());
1220 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1221 // check bool values
1222 for (int i = 0; i < 2; i++) {
1223 fast_return_value_bool = i == 0;
1224 value = TestFastReturnValues<bool>();
1225 CHECK(value->IsBoolean());
1226 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1229 ReturnValueOddball oddballs[] = {
1231 kUndefinedReturnValue,
1232 kEmptyStringReturnValue
1234 for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1235 fast_return_value_void = oddballs[i];
1236 value = TestFastReturnValues<void>();
1237 switch (fast_return_value_void) {
1238 case kNullReturnValue:
1239 CHECK(value->IsNull());
1241 case kUndefinedReturnValue:
1242 CHECK(value->IsUndefined());
1244 case kEmptyStringReturnValue:
1245 CHECK(value->IsString());
1246 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1251 fast_return_value_object_is_empty = false;
1252 value = TestFastReturnValues<Object>();
1253 CHECK(value->IsObject());
1254 fast_return_value_object_is_empty = true;
1255 value = TestFastReturnValues<Object>();
1256 CHECK(value->IsUndefined());
1260 THREADED_TEST(FunctionTemplateSetLength) {
1262 v8::HandleScope scope(env->GetIsolate());
1264 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(
1265 handle_callback, Handle<v8::Value>(), Handle<v8::Signature>(), 23);
1266 Local<Function> fun = fun_templ->GetFunction();
1267 env->Global()->Set(v8_str("obj"), fun);
1268 Local<Script> script = v8_compile("obj.length");
1269 CHECK_EQ(23, script->Run()->Int32Value());
1272 Local<v8::FunctionTemplate> fun_templ =
1273 v8::FunctionTemplate::New(handle_callback);
1274 fun_templ->SetLength(22);
1275 Local<Function> fun = fun_templ->GetFunction();
1276 env->Global()->Set(v8_str("obj"), fun);
1277 Local<Script> script = v8_compile("obj.length");
1278 CHECK_EQ(22, script->Run()->Int32Value());
1281 // Without setting length it defaults to 0.
1282 Local<v8::FunctionTemplate> fun_templ =
1283 v8::FunctionTemplate::New(handle_callback);
1284 Local<Function> fun = fun_templ->GetFunction();
1285 env->Global()->Set(v8_str("obj"), fun);
1286 Local<Script> script = v8_compile("obj.length");
1287 CHECK_EQ(0, script->Run()->Int32Value());
1292 static void* expected_ptr;
1293 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1294 void* ptr = v8::External::Cast(*args.Data())->Value();
1295 CHECK_EQ(expected_ptr, ptr);
1296 args.GetReturnValue().Set(true);
1300 static void TestExternalPointerWrapping() {
1302 v8::HandleScope scope(env->GetIsolate());
1304 v8::Handle<v8::Value> data = v8::External::New(expected_ptr);
1306 v8::Handle<v8::Object> obj = v8::Object::New();
1307 obj->Set(v8_str("func"),
1308 v8::FunctionTemplate::New(callback, data)->GetFunction());
1309 env->Global()->Set(v8_str("obj"), obj);
1312 "function foo() {\n"
1313 " for (var i = 0; i < 13; i++) obj.func();\n"
1315 "foo(), true")->BooleanValue());
1319 THREADED_TEST(ExternalWrap) {
1320 // Check heap allocated object.
1323 TestExternalPointerWrapping();
1326 // Check stack allocated object.
1328 expected_ptr = &foo;
1329 TestExternalPointerWrapping();
1331 // Check not aligned addresses.
1333 char* s = new char[n];
1334 for (int i = 0; i < n; i++) {
1335 expected_ptr = s + i;
1336 TestExternalPointerWrapping();
1341 // Check several invalid addresses.
1342 expected_ptr = reinterpret_cast<void*>(1);
1343 TestExternalPointerWrapping();
1345 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1346 TestExternalPointerWrapping();
1348 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1349 TestExternalPointerWrapping();
1351 #if defined(V8_HOST_ARCH_X64)
1352 // Check a value with a leading 1 bit in x64 Smi encoding.
1353 expected_ptr = reinterpret_cast<void*>(0x400000000);
1354 TestExternalPointerWrapping();
1356 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1357 TestExternalPointerWrapping();
1359 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1360 TestExternalPointerWrapping();
1365 THREADED_TEST(FindInstanceInPrototypeChain) {
1367 v8::HandleScope scope(env->GetIsolate());
1369 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
1370 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
1371 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
1372 derived->Inherit(base);
1374 Local<v8::Function> base_function = base->GetFunction();
1375 Local<v8::Function> derived_function = derived->GetFunction();
1376 Local<v8::Function> other_function = other->GetFunction();
1378 Local<v8::Object> base_instance = base_function->NewInstance();
1379 Local<v8::Object> derived_instance = derived_function->NewInstance();
1380 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1381 Local<v8::Object> other_instance = other_function->NewInstance();
1382 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1383 other_instance->Set(v8_str("__proto__"), derived_instance2);
1385 // base_instance is only an instance of base.
1386 CHECK_EQ(base_instance,
1387 base_instance->FindInstanceInPrototypeChain(base));
1388 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1389 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1391 // derived_instance is an instance of base and derived.
1392 CHECK_EQ(derived_instance,
1393 derived_instance->FindInstanceInPrototypeChain(base));
1394 CHECK_EQ(derived_instance,
1395 derived_instance->FindInstanceInPrototypeChain(derived));
1396 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1398 // other_instance is an instance of other and its immediate
1399 // prototype derived_instance2 is an instance of base and derived.
1400 // Note, derived_instance is an instance of base and derived too,
1401 // but it comes after derived_instance2 in the prototype chain of
1403 CHECK_EQ(derived_instance2,
1404 other_instance->FindInstanceInPrototypeChain(base));
1405 CHECK_EQ(derived_instance2,
1406 other_instance->FindInstanceInPrototypeChain(derived));
1407 CHECK_EQ(other_instance,
1408 other_instance->FindInstanceInPrototypeChain(other));
1412 THREADED_TEST(TinyInteger) {
1414 v8::HandleScope scope(env->GetIsolate());
1415 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1417 int32_t value = 239;
1418 Local<v8::Integer> value_obj = v8::Integer::New(value);
1419 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1421 value_obj = v8::Integer::New(value, isolate);
1422 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1426 THREADED_TEST(BigSmiInteger) {
1428 v8::HandleScope scope(env->GetIsolate());
1429 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1431 int32_t value = i::Smi::kMaxValue;
1432 // We cannot add one to a Smi::kMaxValue without wrapping.
1433 if (i::SmiValuesAre31Bits()) {
1434 CHECK(i::Smi::IsValid(value));
1435 CHECK(!i::Smi::IsValid(value + 1));
1437 Local<v8::Integer> value_obj = v8::Integer::New(value);
1438 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1440 value_obj = v8::Integer::New(value, isolate);
1441 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1446 THREADED_TEST(BigInteger) {
1448 v8::HandleScope scope(env->GetIsolate());
1449 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1451 // We cannot add one to a Smi::kMaxValue without wrapping.
1452 if (i::SmiValuesAre31Bits()) {
1453 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1454 // The code will not be run in that case, due to the "if" guard.
1456 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1457 CHECK(value > i::Smi::kMaxValue);
1458 CHECK(!i::Smi::IsValid(value));
1460 Local<v8::Integer> value_obj = v8::Integer::New(value);
1461 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1463 value_obj = v8::Integer::New(value, isolate);
1464 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1469 THREADED_TEST(TinyUnsignedInteger) {
1471 v8::HandleScope scope(env->GetIsolate());
1472 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1474 uint32_t value = 239;
1476 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1477 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1479 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1480 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1484 THREADED_TEST(BigUnsignedSmiInteger) {
1486 v8::HandleScope scope(env->GetIsolate());
1487 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1489 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1490 CHECK(i::Smi::IsValid(value));
1491 CHECK(!i::Smi::IsValid(value + 1));
1493 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1494 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1496 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1497 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1501 THREADED_TEST(BigUnsignedInteger) {
1503 v8::HandleScope scope(env->GetIsolate());
1504 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1506 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1507 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1508 CHECK(!i::Smi::IsValid(value));
1510 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1511 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1513 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1514 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1518 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1520 v8::HandleScope scope(env->GetIsolate());
1521 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1523 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1524 uint32_t value = INT32_MAX_AS_UINT + 1;
1525 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1527 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1528 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1530 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1531 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1535 THREADED_TEST(IsNativeError) {
1537 v8::HandleScope scope(env->GetIsolate());
1538 v8::Handle<Value> syntax_error = CompileRun(
1539 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1540 CHECK(syntax_error->IsNativeError());
1541 v8::Handle<Value> not_error = CompileRun("{a:42}");
1542 CHECK(!not_error->IsNativeError());
1543 v8::Handle<Value> not_object = CompileRun("42");
1544 CHECK(!not_object->IsNativeError());
1548 THREADED_TEST(StringObject) {
1550 v8::HandleScope scope(env->GetIsolate());
1551 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1552 CHECK(boxed_string->IsStringObject());
1553 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1554 CHECK(!unboxed_string->IsStringObject());
1555 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1556 CHECK(!boxed_not_string->IsStringObject());
1557 v8::Handle<Value> not_object = CompileRun("0");
1558 CHECK(!not_object->IsStringObject());
1559 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1560 CHECK(!as_boxed.IsEmpty());
1561 Local<v8::String> the_string = as_boxed->ValueOf();
1562 CHECK(!the_string.IsEmpty());
1563 ExpectObject("\"test\"", the_string);
1564 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1565 CHECK(new_boxed_string->IsStringObject());
1566 as_boxed = new_boxed_string.As<v8::StringObject>();
1567 the_string = as_boxed->ValueOf();
1568 CHECK(!the_string.IsEmpty());
1569 ExpectObject("\"test\"", the_string);
1573 THREADED_TEST(NumberObject) {
1575 v8::HandleScope scope(env->GetIsolate());
1576 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1577 CHECK(boxed_number->IsNumberObject());
1578 v8::Handle<Value> unboxed_number = CompileRun("42");
1579 CHECK(!unboxed_number->IsNumberObject());
1580 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1581 CHECK(!boxed_not_number->IsNumberObject());
1582 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1583 CHECK(!as_boxed.IsEmpty());
1584 double the_number = as_boxed->ValueOf();
1585 CHECK_EQ(42.0, the_number);
1586 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1587 CHECK(new_boxed_number->IsNumberObject());
1588 as_boxed = new_boxed_number.As<v8::NumberObject>();
1589 the_number = as_boxed->ValueOf();
1590 CHECK_EQ(43.0, the_number);
1594 THREADED_TEST(BooleanObject) {
1596 v8::HandleScope scope(env->GetIsolate());
1597 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1598 CHECK(boxed_boolean->IsBooleanObject());
1599 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1600 CHECK(!unboxed_boolean->IsBooleanObject());
1601 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1602 CHECK(!boxed_not_boolean->IsBooleanObject());
1603 v8::Handle<v8::BooleanObject> as_boxed =
1604 boxed_boolean.As<v8::BooleanObject>();
1605 CHECK(!as_boxed.IsEmpty());
1606 bool the_boolean = as_boxed->ValueOf();
1607 CHECK_EQ(true, the_boolean);
1608 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1609 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1610 CHECK(boxed_true->IsBooleanObject());
1611 CHECK(boxed_false->IsBooleanObject());
1612 as_boxed = boxed_true.As<v8::BooleanObject>();
1613 CHECK_EQ(true, as_boxed->ValueOf());
1614 as_boxed = boxed_false.As<v8::BooleanObject>();
1615 CHECK_EQ(false, as_boxed->ValueOf());
1619 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1621 v8::HandleScope scope(env->GetIsolate());
1623 Local<Value> primitive_false = Boolean::New(false);
1624 CHECK(primitive_false->IsBoolean());
1625 CHECK(!primitive_false->IsBooleanObject());
1626 CHECK(!primitive_false->BooleanValue());
1627 CHECK(!primitive_false->IsTrue());
1628 CHECK(primitive_false->IsFalse());
1630 Local<Value> false_value = BooleanObject::New(false);
1631 CHECK(!false_value->IsBoolean());
1632 CHECK(false_value->IsBooleanObject());
1633 CHECK(false_value->BooleanValue());
1634 CHECK(!false_value->IsTrue());
1635 CHECK(!false_value->IsFalse());
1637 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1638 CHECK(!false_boolean_object->IsBoolean());
1639 CHECK(false_boolean_object->IsBooleanObject());
1640 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1641 // CHECK(false_boolean_object->BooleanValue());
1642 CHECK(!false_boolean_object->ValueOf());
1643 CHECK(!false_boolean_object->IsTrue());
1644 CHECK(!false_boolean_object->IsFalse());
1646 Local<Value> primitive_true = Boolean::New(true);
1647 CHECK(primitive_true->IsBoolean());
1648 CHECK(!primitive_true->IsBooleanObject());
1649 CHECK(primitive_true->BooleanValue());
1650 CHECK(primitive_true->IsTrue());
1651 CHECK(!primitive_true->IsFalse());
1653 Local<Value> true_value = BooleanObject::New(true);
1654 CHECK(!true_value->IsBoolean());
1655 CHECK(true_value->IsBooleanObject());
1656 CHECK(true_value->BooleanValue());
1657 CHECK(!true_value->IsTrue());
1658 CHECK(!true_value->IsFalse());
1660 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1661 CHECK(!true_boolean_object->IsBoolean());
1662 CHECK(true_boolean_object->IsBooleanObject());
1663 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1664 // CHECK(true_boolean_object->BooleanValue());
1665 CHECK(true_boolean_object->ValueOf());
1666 CHECK(!true_boolean_object->IsTrue());
1667 CHECK(!true_boolean_object->IsFalse());
1671 THREADED_TEST(Number) {
1673 v8::HandleScope scope(env->GetIsolate());
1674 double PI = 3.1415926;
1675 Local<v8::Number> pi_obj = v8::Number::New(PI);
1676 CHECK_EQ(PI, pi_obj->NumberValue());
1680 THREADED_TEST(ToNumber) {
1682 v8::HandleScope scope(env->GetIsolate());
1683 Local<String> str = v8_str("3.1415926");
1684 CHECK_EQ(3.1415926, str->NumberValue());
1685 v8::Handle<v8::Boolean> t = v8::True();
1686 CHECK_EQ(1.0, t->NumberValue());
1687 v8::Handle<v8::Boolean> f = v8::False();
1688 CHECK_EQ(0.0, f->NumberValue());
1692 THREADED_TEST(Date) {
1694 v8::HandleScope scope(env->GetIsolate());
1695 double PI = 3.1415926;
1696 Local<Value> date = v8::Date::New(PI);
1697 CHECK_EQ(3.0, date->NumberValue());
1698 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1699 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1703 THREADED_TEST(Boolean) {
1705 v8::HandleScope scope(env->GetIsolate());
1706 v8::Handle<v8::Boolean> t = v8::True();
1708 v8::Handle<v8::Boolean> f = v8::False();
1710 v8::Handle<v8::Primitive> u = v8::Undefined();
1711 CHECK(!u->BooleanValue());
1712 v8::Handle<v8::Primitive> n = v8::Null();
1713 CHECK(!n->BooleanValue());
1714 v8::Handle<String> str1 = v8_str("");
1715 CHECK(!str1->BooleanValue());
1716 v8::Handle<String> str2 = v8_str("x");
1717 CHECK(str2->BooleanValue());
1718 CHECK(!v8::Number::New(0)->BooleanValue());
1719 CHECK(v8::Number::New(-1)->BooleanValue());
1720 CHECK(v8::Number::New(1)->BooleanValue());
1721 CHECK(v8::Number::New(42)->BooleanValue());
1722 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1726 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1727 ApiTestFuzzer::Fuzz();
1728 args.GetReturnValue().Set(v8_num(13.4));
1732 static void GetM(Local<String> name,
1733 const v8::PropertyCallbackInfo<v8::Value>& info) {
1734 ApiTestFuzzer::Fuzz();
1735 info.GetReturnValue().Set(v8_num(876));
1739 THREADED_TEST(GlobalPrototype) {
1740 v8::HandleScope scope(v8::Isolate::GetCurrent());
1741 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1742 func_templ->PrototypeTemplate()->Set(
1744 v8::FunctionTemplate::New(DummyCallHandler));
1745 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1746 templ->Set("x", v8_num(200));
1747 templ->SetAccessor(v8_str("m"), GetM);
1748 LocalContext env(0, templ);
1749 v8::Handle<Script> script(v8_compile("dummy()"));
1750 v8::Handle<Value> result(script->Run());
1751 CHECK_EQ(13.4, result->NumberValue());
1752 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1753 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1757 THREADED_TEST(ObjectTemplate) {
1758 v8::HandleScope scope(v8::Isolate::GetCurrent());
1759 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1760 templ1->Set("x", v8_num(10));
1761 templ1->Set("y", v8_num(13));
1763 Local<v8::Object> instance1 = templ1->NewInstance();
1764 env->Global()->Set(v8_str("p"), instance1);
1765 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1766 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1767 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1768 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1769 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1770 templ2->Set("a", v8_num(12));
1771 templ2->Set("b", templ1);
1772 Local<v8::Object> instance2 = templ2->NewInstance();
1773 env->Global()->Set(v8_str("q"), instance2);
1774 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1775 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1776 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1777 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1781 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1782 ApiTestFuzzer::Fuzz();
1783 args.GetReturnValue().Set(v8_num(17.2));
1787 static void GetKnurd(Local<String> property,
1788 const v8::PropertyCallbackInfo<v8::Value>& info) {
1789 ApiTestFuzzer::Fuzz();
1790 info.GetReturnValue().Set(v8_num(15.2));
1794 THREADED_TEST(DescriptorInheritance) {
1795 v8::HandleScope scope(v8::Isolate::GetCurrent());
1796 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1797 super->PrototypeTemplate()->Set("flabby",
1798 v8::FunctionTemplate::New(GetFlabby));
1799 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1801 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1803 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1804 base1->Inherit(super);
1805 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1807 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1808 base2->Inherit(super);
1809 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1813 env->Global()->Set(v8_str("s"), super->GetFunction());
1814 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1815 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1817 // Checks right __proto__ chain.
1818 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1819 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1821 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1823 // Instance accessor should not be visible on function object or its prototype
1824 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1825 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1826 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1828 env->Global()->Set(v8_str("obj"),
1829 base1->GetFunction()->NewInstance());
1830 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1831 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1832 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1833 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1834 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1836 env->Global()->Set(v8_str("obj2"),
1837 base2->GetFunction()->NewInstance());
1838 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1839 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1840 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1841 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1842 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1844 // base1 and base2 cannot cross reference to each's prototype
1845 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1846 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1850 int echo_named_call_count;
1853 static void EchoNamedProperty(Local<String> name,
1854 const v8::PropertyCallbackInfo<v8::Value>& info) {
1855 ApiTestFuzzer::Fuzz();
1856 CHECK_EQ(v8_str("data"), info.Data());
1857 echo_named_call_count++;
1858 info.GetReturnValue().Set(name);
1862 // Helper functions for Interceptor/Accessor interaction tests
1864 void SimpleAccessorGetter(Local<String> name,
1865 const v8::PropertyCallbackInfo<v8::Value>& info) {
1866 Handle<Object> self = info.This();
1867 info.GetReturnValue().Set(
1868 self->Get(String::Concat(v8_str("accessor_"), name)));
1871 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1872 const v8::PropertyCallbackInfo<void>& info) {
1873 Handle<Object> self = info.This();
1874 self->Set(String::Concat(v8_str("accessor_"), name), value);
1877 void EmptyInterceptorGetter(Local<String> name,
1878 const v8::PropertyCallbackInfo<v8::Value>& info) {
1881 void EmptyInterceptorSetter(Local<String> name,
1883 const v8::PropertyCallbackInfo<v8::Value>& info) {
1886 void InterceptorGetter(Local<String> name,
1887 const v8::PropertyCallbackInfo<v8::Value>& info) {
1888 // Intercept names that start with 'interceptor_'.
1889 String::Utf8Value utf8(name);
1890 char* name_str = *utf8;
1891 char prefix[] = "interceptor_";
1893 for (i = 0; name_str[i] && prefix[i]; ++i) {
1894 if (name_str[i] != prefix[i]) return;
1896 Handle<Object> self = info.This();
1897 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1900 void InterceptorSetter(Local<String> name,
1902 const v8::PropertyCallbackInfo<v8::Value>& info) {
1903 // Intercept accesses that set certain integer values, for which the name does
1904 // not start with 'accessor_'.
1905 String::Utf8Value utf8(name);
1906 char* name_str = *utf8;
1907 char prefix[] = "accessor_";
1909 for (i = 0; name_str[i] && prefix[i]; ++i) {
1910 if (name_str[i] != prefix[i]) break;
1912 if (!prefix[i]) return;
1914 if (value->IsInt32() && value->Int32Value() < 10000) {
1915 Handle<Object> self = info.This();
1916 self->SetHiddenValue(name, value);
1917 info.GetReturnValue().Set(value);
1921 void AddAccessor(Handle<FunctionTemplate> templ,
1922 Handle<String> name,
1923 v8::AccessorGetterCallback getter,
1924 v8::AccessorSetterCallback setter) {
1925 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1928 void AddInterceptor(Handle<FunctionTemplate> templ,
1929 v8::NamedPropertyGetterCallback getter,
1930 v8::NamedPropertySetterCallback setter) {
1931 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1935 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1936 v8::HandleScope scope(v8::Isolate::GetCurrent());
1937 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1938 Handle<FunctionTemplate> child = FunctionTemplate::New();
1939 child->Inherit(parent);
1940 AddAccessor(parent, v8_str("age"),
1941 SimpleAccessorGetter, SimpleAccessorSetter);
1942 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1944 env->Global()->Set(v8_str("Child"), child->GetFunction());
1945 CompileRun("var child = new Child;"
1947 ExpectBoolean("child.hasOwnProperty('age')", false);
1948 ExpectInt32("child.age", 10);
1949 ExpectInt32("child.accessor_age", 10);
1953 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1954 v8::HandleScope scope(v8::Isolate::GetCurrent());
1955 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1956 Handle<FunctionTemplate> child = FunctionTemplate::New();
1957 child->Inherit(parent);
1958 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1960 env->Global()->Set(v8_str("Child"), child->GetFunction());
1961 CompileRun("var child = new Child;"
1962 "var parent = child.__proto__;"
1963 "Object.defineProperty(parent, 'age', "
1964 " {get: function(){ return this.accessor_age; }, "
1965 " set: function(v){ this.accessor_age = v; }, "
1966 " enumerable: true, configurable: true});"
1968 ExpectBoolean("child.hasOwnProperty('age')", false);
1969 ExpectInt32("child.age", 10);
1970 ExpectInt32("child.accessor_age", 10);
1974 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1975 v8::HandleScope scope(v8::Isolate::GetCurrent());
1976 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1977 Handle<FunctionTemplate> child = FunctionTemplate::New();
1978 child->Inherit(parent);
1979 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1981 env->Global()->Set(v8_str("Child"), child->GetFunction());
1982 CompileRun("var child = new Child;"
1983 "var parent = child.__proto__;"
1984 "parent.name = 'Alice';");
1985 ExpectBoolean("child.hasOwnProperty('name')", false);
1986 ExpectString("child.name", "Alice");
1987 CompileRun("child.name = 'Bob';");
1988 ExpectString("child.name", "Bob");
1989 ExpectBoolean("child.hasOwnProperty('name')", true);
1990 ExpectString("parent.name", "Alice");
1994 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1995 v8::HandleScope scope(v8::Isolate::GetCurrent());
1996 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1997 AddAccessor(templ, v8_str("age"),
1998 SimpleAccessorGetter, SimpleAccessorSetter);
1999 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2001 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2002 CompileRun("var obj = new Obj;"
2003 "function setAge(i){ obj.age = i; };"
2004 "for(var i = 0; i <= 10000; i++) setAge(i);");
2005 // All i < 10000 go to the interceptor.
2006 ExpectInt32("obj.interceptor_age", 9999);
2007 // The last i goes to the accessor.
2008 ExpectInt32("obj.accessor_age", 10000);
2012 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2013 v8::HandleScope scope(v8::Isolate::GetCurrent());
2014 Handle<FunctionTemplate> templ = FunctionTemplate::New();
2015 AddAccessor(templ, v8_str("age"),
2016 SimpleAccessorGetter, SimpleAccessorSetter);
2017 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2019 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2020 CompileRun("var obj = new Obj;"
2021 "function setAge(i){ obj.age = i; };"
2022 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2023 // All i >= 10000 go to the accessor.
2024 ExpectInt32("obj.accessor_age", 10000);
2025 // The last i goes to the interceptor.
2026 ExpectInt32("obj.interceptor_age", 9999);
2030 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2031 v8::HandleScope scope(v8::Isolate::GetCurrent());
2032 Handle<FunctionTemplate> parent = FunctionTemplate::New();
2033 Handle<FunctionTemplate> child = FunctionTemplate::New();
2034 child->Inherit(parent);
2035 AddAccessor(parent, v8_str("age"),
2036 SimpleAccessorGetter, SimpleAccessorSetter);
2037 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2039 env->Global()->Set(v8_str("Child"), child->GetFunction());
2040 CompileRun("var child = new Child;"
2041 "function setAge(i){ child.age = i; };"
2042 "for(var i = 0; i <= 10000; i++) setAge(i);");
2043 // All i < 10000 go to the interceptor.
2044 ExpectInt32("child.interceptor_age", 9999);
2045 // The last i goes to the accessor.
2046 ExpectInt32("child.accessor_age", 10000);
2050 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2051 v8::HandleScope scope(v8::Isolate::GetCurrent());
2052 Handle<FunctionTemplate> parent = FunctionTemplate::New();
2053 Handle<FunctionTemplate> child = FunctionTemplate::New();
2054 child->Inherit(parent);
2055 AddAccessor(parent, v8_str("age"),
2056 SimpleAccessorGetter, SimpleAccessorSetter);
2057 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2059 env->Global()->Set(v8_str("Child"), child->GetFunction());
2060 CompileRun("var child = new Child;"
2061 "function setAge(i){ child.age = i; };"
2062 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2063 // All i >= 10000 go to the accessor.
2064 ExpectInt32("child.accessor_age", 10000);
2065 // The last i goes to the interceptor.
2066 ExpectInt32("child.interceptor_age", 9999);
2070 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2071 v8::HandleScope scope(v8::Isolate::GetCurrent());
2072 Handle<FunctionTemplate> templ = FunctionTemplate::New();
2073 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2075 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2076 CompileRun("var obj = new Obj;"
2077 "function setter(i) { this.accessor_age = i; };"
2078 "function getter() { return this.accessor_age; };"
2079 "function setAge(i) { obj.age = i; };"
2080 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2081 "for(var i = 0; i <= 10000; i++) setAge(i);");
2082 // All i < 10000 go to the interceptor.
2083 ExpectInt32("obj.interceptor_age", 9999);
2084 // The last i goes to the JavaScript accessor.
2085 ExpectInt32("obj.accessor_age", 10000);
2086 // The installed JavaScript getter is still intact.
2087 // This last part is a regression test for issue 1651 and relies on the fact
2088 // that both interceptor and accessor are being installed on the same object.
2089 ExpectInt32("obj.age", 10000);
2090 ExpectBoolean("obj.hasOwnProperty('age')", true);
2091 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2095 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2096 v8::HandleScope scope(v8::Isolate::GetCurrent());
2097 Handle<FunctionTemplate> templ = FunctionTemplate::New();
2098 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2100 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2101 CompileRun("var obj = new Obj;"
2102 "function setter(i) { this.accessor_age = i; };"
2103 "function getter() { return this.accessor_age; };"
2104 "function setAge(i) { obj.age = i; };"
2105 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2106 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2107 // All i >= 10000 go to the accessor.
2108 ExpectInt32("obj.accessor_age", 10000);
2109 // The last i goes to the interceptor.
2110 ExpectInt32("obj.interceptor_age", 9999);
2111 // The installed JavaScript getter is still intact.
2112 // This last part is a regression test for issue 1651 and relies on the fact
2113 // that both interceptor and accessor are being installed on the same object.
2114 ExpectInt32("obj.age", 10000);
2115 ExpectBoolean("obj.hasOwnProperty('age')", true);
2116 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2120 THREADED_TEST(SwitchFromInterceptorToProperty) {
2121 v8::HandleScope scope(v8::Isolate::GetCurrent());
2122 Handle<FunctionTemplate> parent = FunctionTemplate::New();
2123 Handle<FunctionTemplate> child = FunctionTemplate::New();
2124 child->Inherit(parent);
2125 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2127 env->Global()->Set(v8_str("Child"), child->GetFunction());
2128 CompileRun("var child = new Child;"
2129 "function setAge(i){ child.age = i; };"
2130 "for(var i = 0; i <= 10000; i++) setAge(i);");
2131 // All i < 10000 go to the interceptor.
2132 ExpectInt32("child.interceptor_age", 9999);
2133 // The last i goes to child's own property.
2134 ExpectInt32("child.age", 10000);
2138 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2139 v8::HandleScope scope(v8::Isolate::GetCurrent());
2140 Handle<FunctionTemplate> parent = FunctionTemplate::New();
2141 Handle<FunctionTemplate> child = FunctionTemplate::New();
2142 child->Inherit(parent);
2143 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2145 env->Global()->Set(v8_str("Child"), child->GetFunction());
2146 CompileRun("var child = new Child;"
2147 "function setAge(i){ child.age = i; };"
2148 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2149 // All i >= 10000 go to child's own property.
2150 ExpectInt32("child.age", 10000);
2151 // The last i goes to the interceptor.
2152 ExpectInt32("child.interceptor_age", 9999);
2156 THREADED_TEST(NamedPropertyHandlerGetter) {
2157 echo_named_call_count = 0;
2158 v8::HandleScope scope(v8::Isolate::GetCurrent());
2159 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2160 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2164 env->Global()->Set(v8_str("obj"),
2165 templ->GetFunction()->NewInstance());
2166 CHECK_EQ(echo_named_call_count, 0);
2167 v8_compile("obj.x")->Run();
2168 CHECK_EQ(echo_named_call_count, 1);
2169 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2170 v8::Handle<Value> str = CompileRun(code);
2171 String::Utf8Value value(str);
2172 CHECK_EQ(*value, "oddlepoddle");
2173 // Check default behavior
2174 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2175 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2176 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2180 int echo_indexed_call_count = 0;
2183 static void EchoIndexedProperty(
2185 const v8::PropertyCallbackInfo<v8::Value>& info) {
2186 ApiTestFuzzer::Fuzz();
2187 CHECK_EQ(v8_num(637), info.Data());
2188 echo_indexed_call_count++;
2189 info.GetReturnValue().Set(v8_num(index));
2193 THREADED_TEST(IndexedPropertyHandlerGetter) {
2194 v8::HandleScope scope(v8::Isolate::GetCurrent());
2195 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2196 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2200 env->Global()->Set(v8_str("obj"),
2201 templ->GetFunction()->NewInstance());
2202 Local<Script> script = v8_compile("obj[900]");
2203 CHECK_EQ(script->Run()->Int32Value(), 900);
2207 v8::Handle<v8::Object> bottom;
2209 static void CheckThisIndexedPropertyHandler(
2211 const v8::PropertyCallbackInfo<v8::Value>& info) {
2212 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2213 ApiTestFuzzer::Fuzz();
2214 CHECK(info.This()->Equals(bottom));
2217 static void CheckThisNamedPropertyHandler(
2219 const v8::PropertyCallbackInfo<v8::Value>& info) {
2220 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2221 ApiTestFuzzer::Fuzz();
2222 CHECK(info.This()->Equals(bottom));
2225 void CheckThisIndexedPropertySetter(
2228 const v8::PropertyCallbackInfo<v8::Value>& info) {
2229 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2230 ApiTestFuzzer::Fuzz();
2231 CHECK(info.This()->Equals(bottom));
2235 void CheckThisNamedPropertySetter(
2236 Local<String> property,
2238 const v8::PropertyCallbackInfo<v8::Value>& info) {
2239 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2240 ApiTestFuzzer::Fuzz();
2241 CHECK(info.This()->Equals(bottom));
2244 void CheckThisIndexedPropertyQuery(
2246 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2247 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2248 ApiTestFuzzer::Fuzz();
2249 CHECK(info.This()->Equals(bottom));
2253 void CheckThisNamedPropertyQuery(
2254 Local<String> property,
2255 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2256 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2257 ApiTestFuzzer::Fuzz();
2258 CHECK(info.This()->Equals(bottom));
2262 void CheckThisIndexedPropertyDeleter(
2264 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2265 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2266 ApiTestFuzzer::Fuzz();
2267 CHECK(info.This()->Equals(bottom));
2271 void CheckThisNamedPropertyDeleter(
2272 Local<String> property,
2273 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2274 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2275 ApiTestFuzzer::Fuzz();
2276 CHECK(info.This()->Equals(bottom));
2280 void CheckThisIndexedPropertyEnumerator(
2281 const v8::PropertyCallbackInfo<v8::Array>& info) {
2282 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2283 ApiTestFuzzer::Fuzz();
2284 CHECK(info.This()->Equals(bottom));
2288 void CheckThisNamedPropertyEnumerator(
2289 const v8::PropertyCallbackInfo<v8::Array>& info) {
2290 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2291 ApiTestFuzzer::Fuzz();
2292 CHECK(info.This()->Equals(bottom));
2296 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2298 v8::HandleScope scope(env->GetIsolate());
2300 // Set up a prototype chain with three interceptors.
2301 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2302 templ->InstanceTemplate()->SetIndexedPropertyHandler(
2303 CheckThisIndexedPropertyHandler,
2304 CheckThisIndexedPropertySetter,
2305 CheckThisIndexedPropertyQuery,
2306 CheckThisIndexedPropertyDeleter,
2307 CheckThisIndexedPropertyEnumerator);
2309 templ->InstanceTemplate()->SetNamedPropertyHandler(
2310 CheckThisNamedPropertyHandler,
2311 CheckThisNamedPropertySetter,
2312 CheckThisNamedPropertyQuery,
2313 CheckThisNamedPropertyDeleter,
2314 CheckThisNamedPropertyEnumerator);
2316 bottom = templ->GetFunction()->NewInstance();
2317 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2318 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2320 bottom->SetPrototype(middle);
2321 middle->SetPrototype(top);
2322 env->Global()->Set(v8_str("obj"), bottom);
2324 // Indexed and named get.
2325 Script::Compile(v8_str("obj[0]"))->Run();
2326 Script::Compile(v8_str("obj.x"))->Run();
2328 // Indexed and named set.
2329 Script::Compile(v8_str("obj[1] = 42"))->Run();
2330 Script::Compile(v8_str("obj.y = 42"))->Run();
2332 // Indexed and named query.
2333 Script::Compile(v8_str("0 in obj"))->Run();
2334 Script::Compile(v8_str("'x' in obj"))->Run();
2336 // Indexed and named deleter.
2337 Script::Compile(v8_str("delete obj[0]"))->Run();
2338 Script::Compile(v8_str("delete obj.x"))->Run();
2341 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
2345 static void PrePropertyHandlerGet(
2347 const v8::PropertyCallbackInfo<v8::Value>& info) {
2348 ApiTestFuzzer::Fuzz();
2349 if (v8_str("pre")->Equals(key)) {
2350 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2355 static void PrePropertyHandlerQuery(
2357 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2358 if (v8_str("pre")->Equals(key)) {
2359 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2364 THREADED_TEST(PrePropertyHandler) {
2365 v8::HandleScope scope(v8::Isolate::GetCurrent());
2366 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
2367 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2369 PrePropertyHandlerQuery);
2370 LocalContext env(NULL, desc->InstanceTemplate());
2371 Script::Compile(v8_str(
2372 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
2373 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
2374 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2375 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
2376 CHECK_EQ(v8_str("Object: on"), result_on);
2377 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
2378 CHECK(result_post.IsEmpty());
2382 THREADED_TEST(UndefinedIsNotEnumerable) {
2384 v8::HandleScope scope(env->GetIsolate());
2385 v8::Handle<Value> result = Script::Compile(v8_str(
2386 "this.propertyIsEnumerable(undefined)"))->Run();
2387 CHECK(result->IsFalse());
2391 v8::Handle<Script> call_recursively_script;
2392 static const int kTargetRecursionDepth = 200; // near maximum
2395 static void CallScriptRecursivelyCall(
2396 const v8::FunctionCallbackInfo<v8::Value>& args) {
2397 ApiTestFuzzer::Fuzz();
2398 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2399 if (depth == kTargetRecursionDepth) return;
2400 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
2401 args.GetReturnValue().Set(call_recursively_script->Run());
2405 static void CallFunctionRecursivelyCall(
2406 const v8::FunctionCallbackInfo<v8::Value>& args) {
2407 ApiTestFuzzer::Fuzz();
2408 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2409 if (depth == kTargetRecursionDepth) {
2410 printf("[depth = %d]\n", depth);
2413 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
2414 v8::Handle<Value> function =
2415 args.This()->Get(v8_str("callFunctionRecursively"));
2416 args.GetReturnValue().Set(
2417 function.As<Function>()->Call(args.This(), 0, NULL));
2421 THREADED_TEST(DeepCrossLanguageRecursion) {
2422 v8::HandleScope scope(v8::Isolate::GetCurrent());
2423 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
2424 global->Set(v8_str("callScriptRecursively"),
2425 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
2426 global->Set(v8_str("callFunctionRecursively"),
2427 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
2428 LocalContext env(NULL, global);
2430 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
2431 call_recursively_script = v8_compile("callScriptRecursively()");
2432 call_recursively_script->Run();
2433 call_recursively_script = v8::Handle<Script>();
2435 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
2436 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
2440 static void ThrowingPropertyHandlerGet(
2442 const v8::PropertyCallbackInfo<v8::Value>& info) {
2443 ApiTestFuzzer::Fuzz();
2444 info.GetReturnValue().Set(v8::ThrowException(key));
2448 static void ThrowingPropertyHandlerSet(
2451 const v8::PropertyCallbackInfo<v8::Value>& info) {
2452 v8::ThrowException(key);
2453 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2457 THREADED_TEST(CallbackExceptionRegression) {
2458 v8::HandleScope scope(v8::Isolate::GetCurrent());
2459 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2460 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2461 ThrowingPropertyHandlerSet);
2463 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2464 v8::Handle<Value> otto = Script::Compile(v8_str(
2465 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
2466 CHECK_EQ(v8_str("otto"), otto);
2467 v8::Handle<Value> netto = Script::Compile(v8_str(
2468 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
2469 CHECK_EQ(v8_str("netto"), netto);
2473 THREADED_TEST(FunctionPrototype) {
2474 v8::HandleScope scope(v8::Isolate::GetCurrent());
2475 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
2476 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2478 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2479 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
2480 CHECK_EQ(script->Run()->Int32Value(), 321);
2484 THREADED_TEST(InternalFields) {
2486 v8::HandleScope scope(env->GetIsolate());
2488 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2489 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2490 instance_templ->SetInternalFieldCount(1);
2491 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2492 CHECK_EQ(1, obj->InternalFieldCount());
2493 CHECK(obj->GetInternalField(0)->IsUndefined());
2494 obj->SetInternalField(0, v8_num(17));
2495 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2499 THREADED_TEST(GlobalObjectInternalFields) {
2500 v8::HandleScope scope(v8::Isolate::GetCurrent());
2501 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
2502 global_template->SetInternalFieldCount(1);
2503 LocalContext env(NULL, global_template);
2504 v8::Handle<v8::Object> global_proxy = env->Global();
2505 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2506 CHECK_EQ(1, global->InternalFieldCount());
2507 CHECK(global->GetInternalField(0)->IsUndefined());
2508 global->SetInternalField(0, v8_num(17));
2509 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2513 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2515 v8::HandleScope scope(v8::Isolate::GetCurrent());
2517 v8::Local<v8::Object> global = env->Global();
2518 global->Set(0, v8::String::New("value"));
2519 CHECK(global->HasRealIndexedProperty(0));
2523 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2525 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2526 obj->SetAlignedPointerInInternalField(0, value);
2527 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2528 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2532 THREADED_TEST(InternalFieldsAlignedPointers) {
2534 v8::HandleScope scope(env->GetIsolate());
2536 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2537 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2538 instance_templ->SetInternalFieldCount(1);
2539 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2540 CHECK_EQ(1, obj->InternalFieldCount());
2542 CheckAlignedPointerInInternalField(obj, NULL);
2544 int* heap_allocated = new int[100];
2545 CheckAlignedPointerInInternalField(obj, heap_allocated);
2546 delete[] heap_allocated;
2548 int stack_allocated[100];
2549 CheckAlignedPointerInInternalField(obj, stack_allocated);
2551 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2552 CheckAlignedPointerInInternalField(obj, huge);
2556 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2559 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2560 (*env)->SetAlignedPointerInEmbedderData(index, value);
2561 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2562 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2566 static void* AlignedTestPointer(int i) {
2567 return reinterpret_cast<void*>(i * 1234);
2571 THREADED_TEST(EmbedderDataAlignedPointers) {
2573 v8::HandleScope scope(env->GetIsolate());
2575 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2577 int* heap_allocated = new int[100];
2578 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2579 delete[] heap_allocated;
2581 int stack_allocated[100];
2582 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2584 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2585 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2587 // Test growing of the embedder data's backing store.
2588 for (int i = 0; i < 100; i++) {
2589 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2591 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2592 for (int i = 0; i < 100; i++) {
2593 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2598 static void CheckEmbedderData(LocalContext* env,
2600 v8::Handle<Value> data) {
2601 (*env)->SetEmbedderData(index, data);
2602 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2606 THREADED_TEST(EmbedderData) {
2608 v8::HandleScope scope(env->GetIsolate());
2610 CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps"));
2611 CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog."));
2612 CheckEmbedderData(&env, 1, v8::Number::New(1.2345));
2613 CheckEmbedderData(&env, 0, v8::Boolean::New(true));
2617 THREADED_TEST(IdentityHash) {
2619 v8::HandleScope scope(env->GetIsolate());
2621 // Ensure that the test starts with an fresh heap to test whether the hash
2622 // code is based on the address.
2623 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2624 Local<v8::Object> obj = v8::Object::New();
2625 int hash = obj->GetIdentityHash();
2626 int hash1 = obj->GetIdentityHash();
2627 CHECK_EQ(hash, hash1);
2628 int hash2 = v8::Object::New()->GetIdentityHash();
2629 // Since the identity hash is essentially a random number two consecutive
2630 // objects should not be assigned the same hash code. If the test below fails
2631 // the random number generator should be evaluated.
2632 CHECK_NE(hash, hash2);
2633 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2634 int hash3 = v8::Object::New()->GetIdentityHash();
2635 // Make sure that the identity hash is not based on the initial address of
2636 // the object alone. If the test below fails the random number generator
2637 // should be evaluated.
2638 CHECK_NE(hash, hash3);
2639 int hash4 = obj->GetIdentityHash();
2640 CHECK_EQ(hash, hash4);
2642 // Check identity hashes behaviour in the presence of JS accessors.
2643 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2645 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2646 Local<v8::Object> o1 = v8::Object::New();
2647 Local<v8::Object> o2 = v8::Object::New();
2648 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2652 "function cnst() { return 42; };\n"
2653 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2654 Local<v8::Object> o1 = v8::Object::New();
2655 Local<v8::Object> o2 = v8::Object::New();
2656 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2661 THREADED_TEST(SymbolProperties) {
2662 i::FLAG_harmony_symbols = true;
2665 v8::Isolate* isolate = env->GetIsolate();
2666 v8::HandleScope scope(isolate);
2668 v8::Local<v8::Object> obj = v8::Object::New();
2669 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2670 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol");
2672 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2674 // Check basic symbol functionality.
2675 CHECK(sym1->IsSymbol());
2676 CHECK(sym2->IsSymbol());
2677 CHECK(!obj->IsSymbol());
2679 CHECK(sym1->Equals(sym1));
2680 CHECK(sym2->Equals(sym2));
2681 CHECK(!sym1->Equals(sym2));
2682 CHECK(!sym2->Equals(sym1));
2683 CHECK(sym1->StrictEquals(sym1));
2684 CHECK(sym2->StrictEquals(sym2));
2685 CHECK(!sym1->StrictEquals(sym2));
2686 CHECK(!sym2->StrictEquals(sym1));
2688 CHECK(sym2->Name()->Equals(v8::String::New("my-symbol")));
2690 v8::Local<v8::Value> sym_val = sym2;
2691 CHECK(sym_val->IsSymbol());
2692 CHECK(sym_val->Equals(sym2));
2693 CHECK(sym_val->StrictEquals(sym2));
2694 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2696 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2697 CHECK(sym_obj->IsSymbolObject());
2698 CHECK(!sym2->IsSymbolObject());
2699 CHECK(!obj->IsSymbolObject());
2700 CHECK(sym_obj->Equals(sym2));
2701 CHECK(!sym_obj->StrictEquals(sym2));
2702 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2703 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2705 // Make sure delete of a non-existent symbol property works.
2706 CHECK(obj->Delete(sym1));
2707 CHECK(!obj->Has(sym1));
2709 CHECK(obj->Set(sym1, v8::Integer::New(1503)));
2710 CHECK(obj->Has(sym1));
2711 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2712 CHECK(obj->Set(sym1, v8::Integer::New(2002)));
2713 CHECK(obj->Has(sym1));
2714 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2715 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2717 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2718 int num_props = obj->GetPropertyNames()->Length();
2719 CHECK(obj->Set(v8::String::New("bla"), v8::Integer::New(20)));
2720 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2721 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2723 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2725 // Add another property and delete it afterwards to force the object in
2727 CHECK(obj->Set(sym2, v8::Integer::New(2008)));
2728 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2729 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2730 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2731 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2733 CHECK(obj->Has(sym1));
2734 CHECK(obj->Has(sym2));
2735 CHECK(obj->Delete(sym2));
2736 CHECK(obj->Has(sym1));
2737 CHECK(!obj->Has(sym2));
2738 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2739 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2743 class ScopedArrayBufferContents {
2745 explicit ScopedArrayBufferContents(
2746 const v8::ArrayBuffer::Contents& contents)
2747 : contents_(contents) {}
2748 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2749 void* Data() const { return contents_.Data(); }
2750 size_t ByteLength() const { return contents_.ByteLength(); }
2752 const v8::ArrayBuffer::Contents contents_;
2755 template <typename T>
2756 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2757 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2758 for (int i = 0; i < value->InternalFieldCount(); i++) {
2759 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2764 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2766 v8::Isolate* isolate = env->GetIsolate();
2767 v8::HandleScope handle_scope(isolate);
2769 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(1024);
2770 CheckInternalFieldsAreZero(ab);
2771 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2772 CHECK(!ab->IsExternal());
2773 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2775 ScopedArrayBufferContents ab_contents(ab->Externalize());
2776 CHECK(ab->IsExternal());
2778 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2779 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2780 ASSERT(data != NULL);
2781 env->Global()->Set(v8_str("ab"), ab);
2783 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2784 CHECK_EQ(1024, result->Int32Value());
2786 result = CompileRun("var u8 = new Uint8Array(ab);"
2790 CHECK_EQ(1024, result->Int32Value());
2791 CHECK_EQ(0xFF, data[0]);
2792 CHECK_EQ(0xAA, data[1]);
2795 result = CompileRun("u8[0] + u8[1]");
2796 CHECK_EQ(0xDD, result->Int32Value());
2800 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2802 v8::Isolate* isolate = env->GetIsolate();
2803 v8::HandleScope handle_scope(isolate);
2806 v8::Local<v8::Value> result =
2807 CompileRun("var ab1 = new ArrayBuffer(2);"
2808 "var u8_a = new Uint8Array(ab1);"
2810 "u8_a[1] = 0xFF; u8_a.buffer");
2811 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2812 CheckInternalFieldsAreZero(ab1);
2813 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2814 CHECK(!ab1->IsExternal());
2815 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2816 CHECK(ab1->IsExternal());
2818 result = CompileRun("ab1.byteLength");
2819 CHECK_EQ(2, result->Int32Value());
2820 result = CompileRun("u8_a[0]");
2821 CHECK_EQ(0xAA, result->Int32Value());
2822 result = CompileRun("u8_a[1]");
2823 CHECK_EQ(0xFF, result->Int32Value());
2824 result = CompileRun("var u8_b = new Uint8Array(ab1);"
2827 CHECK_EQ(0xBB, result->Int32Value());
2828 result = CompileRun("u8_b[1]");
2829 CHECK_EQ(0xFF, result->Int32Value());
2831 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2832 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2833 CHECK_EQ(0xBB, ab1_data[0]);
2834 CHECK_EQ(0xFF, ab1_data[1]);
2837 result = CompileRun("u8_a[0] + u8_a[1]");
2838 CHECK_EQ(0xDD, result->Int32Value());
2842 THREADED_TEST(ArrayBuffer_External) {
2844 v8::Isolate* isolate = env->GetIsolate();
2845 v8::HandleScope handle_scope(isolate);
2847 i::ScopedVector<uint8_t> my_data(100);
2848 memset(my_data.start(), 0, 100);
2849 Local<v8::ArrayBuffer> ab3 = v8::ArrayBuffer::New(my_data.start(), 100);
2850 CheckInternalFieldsAreZero(ab3);
2851 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2852 CHECK(ab3->IsExternal());
2854 env->Global()->Set(v8_str("ab3"), ab3);
2856 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2857 CHECK_EQ(100, result->Int32Value());
2859 result = CompileRun("var u8_b = new Uint8Array(ab3);"
2863 CHECK_EQ(100, result->Int32Value());
2864 CHECK_EQ(0xBB, my_data[0]);
2865 CHECK_EQ(0xCC, my_data[1]);
2868 result = CompileRun("u8_b[0] + u8_b[1]");
2869 CHECK_EQ(0xDD, result->Int32Value());
2873 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
2874 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
2875 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
2879 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
2880 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
2881 CHECK_EQ(0, static_cast<int>(ta->Length()));
2882 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
2886 static void CheckIsTypedArrayVarNeutered(const char* name) {
2887 i::ScopedVector<char> source(1024);
2888 i::OS::SNPrintF(source,
2889 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
2891 CHECK(CompileRun(source.start())->IsTrue());
2892 v8::Handle<v8::TypedArray> ta =
2893 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
2894 CheckIsNeutered(ta);
2898 template <typename TypedArray, int kElementSize>
2899 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
2902 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
2903 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
2904 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
2905 CHECK_EQ(length, static_cast<int>(ta->Length()));
2906 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
2911 THREADED_TEST(ArrayBuffer_NeuteringApi) {
2913 v8::Isolate* isolate = env->GetIsolate();
2914 v8::HandleScope handle_scope(isolate);
2916 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(1024);
2918 v8::Handle<v8::Uint8Array> u8a =
2919 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
2920 v8::Handle<v8::Uint8ClampedArray> u8c =
2921 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
2922 v8::Handle<v8::Int8Array> i8a =
2923 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
2925 v8::Handle<v8::Uint16Array> u16a =
2926 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
2927 v8::Handle<v8::Int16Array> i16a =
2928 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
2930 v8::Handle<v8::Uint32Array> u32a =
2931 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
2932 v8::Handle<v8::Int32Array> i32a =
2933 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
2935 v8::Handle<v8::Float32Array> f32a =
2936 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
2937 v8::Handle<v8::Float64Array> f64a =
2938 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
2940 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
2941 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
2942 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
2943 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
2945 ScopedArrayBufferContents contents(buffer->Externalize());
2947 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
2948 CheckIsNeutered(u8a);
2949 CheckIsNeutered(u8c);
2950 CheckIsNeutered(i8a);
2951 CheckIsNeutered(u16a);
2952 CheckIsNeutered(i16a);
2953 CheckIsNeutered(u32a);
2954 CheckIsNeutered(i32a);
2955 CheckIsNeutered(f32a);
2956 CheckIsNeutered(f64a);
2957 CheckDataViewIsNeutered(dv);
2961 THREADED_TEST(ArrayBuffer_NeuteringScript) {
2963 v8::Isolate* isolate = env->GetIsolate();
2964 v8::HandleScope handle_scope(isolate);
2967 "var ab = new ArrayBuffer(1024);"
2968 "var u8a = new Uint8Array(ab, 1, 1023);"
2969 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
2970 "var i8a = new Int8Array(ab, 1, 1023);"
2971 "var u16a = new Uint16Array(ab, 2, 511);"
2972 "var i16a = new Int16Array(ab, 2, 511);"
2973 "var u32a = new Uint32Array(ab, 4, 255);"
2974 "var i32a = new Int32Array(ab, 4, 255);"
2975 "var f32a = new Float32Array(ab, 4, 255);"
2976 "var f64a = new Float64Array(ab, 8, 127);"
2977 "var dv = new DataView(ab, 1, 1023);");
2979 v8::Handle<v8::ArrayBuffer> ab =
2980 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
2982 v8::Handle<v8::DataView> dv =
2983 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
2985 ScopedArrayBufferContents contents(ab->Externalize());
2987 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
2988 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
2990 CheckIsTypedArrayVarNeutered("u8a");
2991 CheckIsTypedArrayVarNeutered("u8c");
2992 CheckIsTypedArrayVarNeutered("i8a");
2993 CheckIsTypedArrayVarNeutered("u16a");
2994 CheckIsTypedArrayVarNeutered("i16a");
2995 CheckIsTypedArrayVarNeutered("u32a");
2996 CheckIsTypedArrayVarNeutered("i32a");
2997 CheckIsTypedArrayVarNeutered("f32a");
2998 CheckIsTypedArrayVarNeutered("f64a");
3000 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3001 CheckDataViewIsNeutered(dv);
3006 THREADED_TEST(HiddenProperties) {
3008 v8::HandleScope scope(env->GetIsolate());
3010 v8::Local<v8::Object> obj = v8::Object::New();
3011 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3012 v8::Local<v8::String> empty = v8_str("");
3013 v8::Local<v8::String> prop_name = v8_str("prop_name");
3015 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
3017 // Make sure delete of a non-existent hidden value works
3018 CHECK(obj->DeleteHiddenValue(key));
3020 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
3021 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3022 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
3023 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3025 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
3027 // Make sure we do not find the hidden property.
3028 CHECK(!obj->Has(empty));
3029 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3030 CHECK(obj->Get(empty)->IsUndefined());
3031 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3032 CHECK(obj->Set(empty, v8::Integer::New(2003)));
3033 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3034 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3036 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
3038 // Add another property and delete it afterwards to force the object in
3040 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
3041 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3042 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3043 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3044 CHECK(obj->Delete(prop_name));
3045 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3047 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
3049 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3050 CHECK(obj->GetHiddenValue(key).IsEmpty());
3052 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
3053 CHECK(obj->DeleteHiddenValue(key));
3054 CHECK(obj->GetHiddenValue(key).IsEmpty());
3058 THREADED_TEST(Regress97784) {
3059 // Regression test for crbug.com/97784
3060 // Messing with the Object.prototype should not have effect on
3061 // hidden properties.
3063 v8::HandleScope scope(env->GetIsolate());
3065 v8::Local<v8::Object> obj = v8::Object::New();
3066 v8::Local<v8::String> key = v8_str("hidden");
3069 "set_called = false;"
3070 "Object.defineProperty("
3071 " Object.prototype,"
3073 " {get: function() { return 45; },"
3074 " set: function() { set_called = true; }})");
3076 CHECK(obj->GetHiddenValue(key).IsEmpty());
3077 // Make sure that the getter and setter from Object.prototype is not invoked.
3078 // If it did we would have full access to the hidden properties in
3080 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
3081 ExpectFalse("set_called");
3082 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3086 static bool interceptor_for_hidden_properties_called;
3087 static void InterceptorForHiddenProperties(
3088 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3089 interceptor_for_hidden_properties_called = true;
3093 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3094 LocalContext context;
3095 v8::HandleScope scope(context->GetIsolate());
3097 interceptor_for_hidden_properties_called = false;
3099 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3101 // Associate an interceptor with an object and start setting hidden values.
3102 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
3103 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3104 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3105 Local<v8::Function> function = fun_templ->GetFunction();
3106 Local<v8::Object> obj = function->NewInstance();
3107 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
3108 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3109 CHECK(!interceptor_for_hidden_properties_called);
3113 THREADED_TEST(External) {
3114 v8::HandleScope scope(v8::Isolate::GetCurrent());
3116 Local<v8::External> ext = v8::External::New(&x);
3118 env->Global()->Set(v8_str("ext"), ext);
3119 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
3120 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3121 int* ptr = static_cast<int*>(reext->Value());
3126 // Make sure unaligned pointers are wrapped properly.
3127 char* data = i::StrDup("0123456789");
3128 Local<v8::Value> zero = v8::External::New(&data[0]);
3129 Local<v8::Value> one = v8::External::New(&data[1]);
3130 Local<v8::Value> two = v8::External::New(&data[2]);
3131 Local<v8::Value> three = v8::External::New(&data[3]);
3133 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3134 CHECK_EQ('0', *char_ptr);
3135 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3136 CHECK_EQ('1', *char_ptr);
3137 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3138 CHECK_EQ('2', *char_ptr);
3139 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3140 CHECK_EQ('3', *char_ptr);
3141 i::DeleteArray(data);
3145 THREADED_TEST(GlobalHandle) {
3146 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3147 v8::Persistent<String> global;
3149 v8::HandleScope scope(isolate);
3150 global.Reset(isolate, v8_str("str"));
3153 v8::HandleScope scope(isolate);
3154 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3159 v8::HandleScope scope(isolate);
3160 global.Reset(isolate, v8_str("str"));
3163 v8::HandleScope scope(isolate);
3164 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3170 THREADED_TEST(ResettingGlobalHandle) {
3171 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3172 v8::Persistent<String> global;
3174 v8::HandleScope scope(isolate);
3175 global.Reset(isolate, v8_str("str"));
3177 v8::internal::GlobalHandles* global_handles =
3178 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3179 int initial_handle_count = global_handles->global_handles_count();
3181 v8::HandleScope scope(isolate);
3182 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3185 v8::HandleScope scope(isolate);
3186 global.Reset(isolate, v8_str("longer"));
3188 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3190 v8::HandleScope scope(isolate);
3191 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3194 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3198 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3199 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3200 v8::Persistent<String> global;
3202 v8::HandleScope scope(isolate);
3203 global.Reset(isolate, v8_str("str"));
3205 v8::internal::GlobalHandles* global_handles =
3206 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3207 int initial_handle_count = global_handles->global_handles_count();
3209 v8::HandleScope scope(isolate);
3210 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3213 v8::HandleScope scope(isolate);
3214 Local<String> empty;
3215 global.Reset(isolate, empty);
3217 CHECK(global.IsEmpty());
3218 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3222 THREADED_TEST(ClearAndLeakGlobal) {
3223 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3224 v8::internal::GlobalHandles* global_handles = NULL;
3225 int initial_handle_count = 0;
3226 v8::Persistent<String> global;
3228 v8::HandleScope scope(isolate);
3229 Local<String> str = v8_str("str");
3231 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3232 initial_handle_count = global_handles->global_handles_count();
3233 global.Reset(isolate, str);
3235 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1);
3236 String* str = global.ClearAndLeak();
3237 CHECK(global.IsEmpty());
3238 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1);
3239 global_handles->Destroy(reinterpret_cast<i::Object**>(str));
3240 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3244 THREADED_TEST(GlobalHandleUpcast) {
3245 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3246 v8::HandleScope scope(isolate);
3247 v8::Local<String> local = v8::Local<String>::New(v8_str("str"));
3248 v8::Persistent<String> global_string(isolate, local);
3249 v8::Persistent<Value>& global_value =
3250 v8::Persistent<Value>::Cast(global_string);
3251 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3252 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3253 global_string.Dispose();
3257 THREADED_TEST(HandleEquality) {
3258 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3259 v8::Persistent<String> global1;
3260 v8::Persistent<String> global2;
3262 v8::HandleScope scope(isolate);
3263 global1.Reset(isolate, v8_str("str"));
3264 global2.Reset(isolate, v8_str("str2"));
3266 CHECK_EQ(global1 == global1, true);
3267 CHECK_EQ(global1 != global1, false);
3269 v8::HandleScope scope(isolate);
3270 Local<String> local1 = Local<String>::New(isolate, global1);
3271 Local<String> local2 = Local<String>::New(isolate, global2);
3273 CHECK_EQ(global1 == local1, true);
3274 CHECK_EQ(global1 != local1, false);
3275 CHECK_EQ(local1 == global1, true);
3276 CHECK_EQ(local1 != global1, false);
3278 CHECK_EQ(global1 == local2, false);
3279 CHECK_EQ(global1 != local2, true);
3280 CHECK_EQ(local2 == global1, false);
3281 CHECK_EQ(local2 != global1, true);
3283 CHECK_EQ(local1 == local2, false);
3284 CHECK_EQ(local1 != local2, true);
3286 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3287 CHECK_EQ(local1 == anotherLocal1, true);
3288 CHECK_EQ(local1 != anotherLocal1, false);
3295 THREADED_TEST(LocalHandle) {
3296 v8::HandleScope scope(v8::Isolate::GetCurrent());
3297 v8::Local<String> local = v8::Local<String>::New(v8_str("str"));
3298 CHECK_EQ(local->Length(), 3);
3300 local = v8::Local<String>::New(v8::Isolate::GetCurrent(), v8_str("str"));
3301 CHECK_EQ(local->Length(), 3);
3305 class WeakCallCounter {
3307 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3308 int id() { return id_; }
3309 void increment() { number_of_weak_calls_++; }
3310 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3313 int number_of_weak_calls_;
3317 static void WeakPointerCallback(v8::Isolate* isolate,
3318 Persistent<Value>* handle,
3319 WeakCallCounter* counter) {
3320 CHECK_EQ(1234, counter->id());
3321 counter->increment();
3326 static UniqueId MakeUniqueId(const Persistent<Value>& p) {
3327 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3331 THREADED_TEST(ApiObjectGroups) {
3333 v8::Isolate* iso = env->GetIsolate();
3334 HandleScope scope(iso);
3336 Persistent<Value> g1s1;
3337 Persistent<Value> g1s2;
3338 Persistent<Value> g1c1;
3339 Persistent<Value> g2s1;
3340 Persistent<Value> g2s2;
3341 Persistent<Value> g2c1;
3343 WeakCallCounter counter(1234);
3346 HandleScope scope(iso);
3347 g1s1.Reset(iso, Object::New());
3348 g1s2.Reset(iso, Object::New());
3349 g1c1.Reset(iso, Object::New());
3350 g1s1.MakeWeak(&counter, &WeakPointerCallback);
3351 g1s2.MakeWeak(&counter, &WeakPointerCallback);
3352 g1c1.MakeWeak(&counter, &WeakPointerCallback);
3354 g2s1.Reset(iso, Object::New());
3355 g2s2.Reset(iso, Object::New());
3356 g2c1.Reset(iso, Object::New());
3357 g2s1.MakeWeak(&counter, &WeakPointerCallback);
3358 g2s2.MakeWeak(&counter, &WeakPointerCallback);
3359 g2c1.MakeWeak(&counter, &WeakPointerCallback);
3362 Persistent<Value> root(iso, g1s1); // make a root.
3364 // Connect group 1 and 2, make a cycle.
3366 HandleScope scope(iso);
3367 CHECK(Local<Object>::New(iso, g1s2.As<Object>())->
3368 Set(0, Local<Value>::New(iso, g2s2)));
3369 CHECK(Local<Object>::New(iso, g2s1.As<Object>())->
3370 Set(0, Local<Value>::New(iso, g1s1)));
3374 UniqueId id1 = MakeUniqueId(g1s1);
3375 UniqueId id2 = MakeUniqueId(g2s2);
3376 iso->SetObjectGroupId(g1s1, id1);
3377 iso->SetObjectGroupId(g1s2, id1);
3378 iso->SetReferenceFromGroup(id1, g1c1);
3379 iso->SetObjectGroupId(g2s1, id2);
3380 iso->SetObjectGroupId(g2s2, id2);
3381 iso->SetReferenceFromGroup(id2, g2c1);
3383 // Do a single full GC, ensure incremental marking is stopped.
3384 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3386 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3388 // All object should be alive.
3389 CHECK_EQ(0, counter.NumberOfWeakCalls());
3392 root.MakeWeak(&counter, &WeakPointerCallback);
3393 // But make children strong roots---all the objects (except for children)
3394 // should be collectable now.
3398 // Groups are deleted, rebuild groups.
3400 UniqueId id1 = MakeUniqueId(g1s1);
3401 UniqueId id2 = MakeUniqueId(g2s2);
3402 iso->SetObjectGroupId(g1s1, id1);
3403 iso->SetObjectGroupId(g1s2, id1);
3404 iso->SetReferenceFromGroup(id1, g1c1);
3405 iso->SetObjectGroupId(g2s1, id2);
3406 iso->SetObjectGroupId(g2s2, id2);
3407 iso->SetReferenceFromGroup(id2, g2c1);
3410 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3412 // All objects should be gone. 5 global handles in total.
3413 CHECK_EQ(5, counter.NumberOfWeakCalls());
3415 // And now make children weak again and collect them.
3416 g1c1.MakeWeak(&counter, &WeakPointerCallback);
3417 g2c1.MakeWeak(&counter, &WeakPointerCallback);
3419 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3420 CHECK_EQ(7, counter.NumberOfWeakCalls());
3424 THREADED_TEST(ApiObjectGroupsCycle) {
3426 v8::Isolate* iso = env->GetIsolate();
3427 HandleScope scope(iso);
3429 WeakCallCounter counter(1234);
3431 Persistent<Value> g1s1;
3432 Persistent<Value> g1s2;
3433 Persistent<Value> g2s1;
3434 Persistent<Value> g2s2;
3435 Persistent<Value> g3s1;
3436 Persistent<Value> g3s2;
3437 Persistent<Value> g4s1;
3438 Persistent<Value> g4s2;
3441 HandleScope scope(iso);
3442 g1s1.Reset(iso, Object::New());
3443 g1s2.Reset(iso, Object::New());
3444 g1s1.MakeWeak(&counter, &WeakPointerCallback);
3445 g1s2.MakeWeak(&counter, &WeakPointerCallback);
3446 CHECK(g1s1.IsWeak());
3447 CHECK(g1s2.IsWeak());
3449 g2s1.Reset(iso, Object::New());
3450 g2s2.Reset(iso, Object::New());
3451 g2s1.MakeWeak(&counter, &WeakPointerCallback);
3452 g2s2.MakeWeak(&counter, &WeakPointerCallback);
3453 CHECK(g2s1.IsWeak());
3454 CHECK(g2s2.IsWeak());
3456 g3s1.Reset(iso, Object::New());
3457 g3s2.Reset(iso, Object::New());
3458 g3s1.MakeWeak(&counter, &WeakPointerCallback);
3459 g3s2.MakeWeak(&counter, &WeakPointerCallback);
3460 CHECK(g3s1.IsWeak());
3461 CHECK(g3s2.IsWeak());
3463 g4s1.Reset(iso, Object::New());
3464 g4s2.Reset(iso, Object::New());
3465 g4s1.MakeWeak(&counter, &WeakPointerCallback);
3466 g4s2.MakeWeak(&counter, &WeakPointerCallback);
3467 CHECK(g4s1.IsWeak());
3468 CHECK(g4s2.IsWeak());
3471 Persistent<Value> root(iso, g1s1); // make a root.
3473 // Connect groups. We're building the following cycle:
3474 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3477 UniqueId id1 = MakeUniqueId(g1s1);
3478 UniqueId id2 = MakeUniqueId(g2s1);
3479 UniqueId id3 = MakeUniqueId(g3s1);
3480 UniqueId id4 = MakeUniqueId(g4s1);
3481 iso->SetObjectGroupId(g1s1, id1);
3482 iso->SetObjectGroupId(g1s2, id1);
3483 iso->SetReferenceFromGroup(id1, g2s1);
3484 iso->SetObjectGroupId(g2s1, id2);
3485 iso->SetObjectGroupId(g2s2, id2);
3486 iso->SetReferenceFromGroup(id2, g3s1);
3487 iso->SetObjectGroupId(g3s1, id3);
3488 iso->SetObjectGroupId(g3s2, id3);
3489 iso->SetReferenceFromGroup(id3, g4s1);
3490 iso->SetObjectGroupId(g4s1, id4);
3491 iso->SetObjectGroupId(g4s2, id4);
3492 iso->SetReferenceFromGroup(id4, g1s1);
3494 // Do a single full GC
3495 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3497 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3499 // All object should be alive.
3500 CHECK_EQ(0, counter.NumberOfWeakCalls());
3503 root.MakeWeak(&counter, &WeakPointerCallback);
3505 // Groups are deleted, rebuild groups.
3507 UniqueId id1 = MakeUniqueId(g1s1);
3508 UniqueId id2 = MakeUniqueId(g2s1);
3509 UniqueId id3 = MakeUniqueId(g3s1);
3510 UniqueId id4 = MakeUniqueId(g4s1);
3511 iso->SetObjectGroupId(g1s1, id1);
3512 iso->SetObjectGroupId(g1s2, id1);
3513 iso->SetReferenceFromGroup(id1, g2s1);
3514 iso->SetObjectGroupId(g2s1, id2);
3515 iso->SetObjectGroupId(g2s2, id2);
3516 iso->SetReferenceFromGroup(id2, g3s1);
3517 iso->SetObjectGroupId(g3s1, id3);
3518 iso->SetObjectGroupId(g3s2, id3);
3519 iso->SetReferenceFromGroup(id3, g4s1);
3520 iso->SetObjectGroupId(g4s1, id4);
3521 iso->SetObjectGroupId(g4s2, id4);
3522 iso->SetReferenceFromGroup(id4, g1s1);
3525 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3527 // All objects should be gone. 9 global handles in total.
3528 CHECK_EQ(9, counter.NumberOfWeakCalls());
3532 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3533 // on the buildbots, so was made non-threaded for the time being.
3534 TEST(ApiObjectGroupsCycleForScavenger) {
3535 i::FLAG_stress_compaction = false;
3536 i::FLAG_gc_global = false;
3538 v8::Isolate* iso = env->GetIsolate();
3539 HandleScope scope(iso);
3541 WeakCallCounter counter(1234);
3543 Persistent<Value> g1s1;
3544 Persistent<Value> g1s2;
3545 Persistent<Value> g2s1;
3546 Persistent<Value> g2s2;
3547 Persistent<Value> g3s1;
3548 Persistent<Value> g3s2;
3551 HandleScope scope(iso);
3552 g1s1.Reset(iso, Object::New());
3553 g1s2.Reset(iso, Object::New());
3554 g1s1.MakeWeak(&counter, &WeakPointerCallback);
3555 g1s2.MakeWeak(&counter, &WeakPointerCallback);
3557 g2s1.Reset(iso, Object::New());
3558 g2s2.Reset(iso, Object::New());
3559 g2s1.MakeWeak(&counter, &WeakPointerCallback);
3560 g2s2.MakeWeak(&counter, &WeakPointerCallback);
3562 g3s1.Reset(iso, Object::New());
3563 g3s2.Reset(iso, Object::New());
3564 g3s1.MakeWeak(&counter, &WeakPointerCallback);
3565 g3s2.MakeWeak(&counter, &WeakPointerCallback);
3569 Persistent<Value> root(iso, g1s1);
3570 root.MarkPartiallyDependent();
3572 // Connect groups. We're building the following cycle:
3573 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3576 HandleScope handle_scope(iso);
3577 g1s1.MarkPartiallyDependent();
3578 g1s2.MarkPartiallyDependent();
3579 g2s1.MarkPartiallyDependent();
3580 g2s2.MarkPartiallyDependent();
3581 g3s1.MarkPartiallyDependent();
3582 g3s2.MarkPartiallyDependent();
3583 iso->SetObjectGroupId(g1s1, UniqueId(1));
3584 iso->SetObjectGroupId(g1s2, UniqueId(1));
3585 Local<Object>::New(iso, g1s1.As<Object>())->Set(
3586 v8_str("x"), Local<Value>::New(iso, g2s1));
3587 iso->SetObjectGroupId(g2s1, UniqueId(2));
3588 iso->SetObjectGroupId(g2s2, UniqueId(2));
3589 Local<Object>::New(iso, g2s1.As<Object>())->Set(
3590 v8_str("x"), Local<Value>::New(iso, g3s1));
3591 iso->SetObjectGroupId(g3s1, UniqueId(3));
3592 iso->SetObjectGroupId(g3s2, UniqueId(3));
3593 Local<Object>::New(iso, g3s1.As<Object>())->Set(
3594 v8_str("x"), Local<Value>::New(iso, g1s1));
3597 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3599 heap->CollectGarbage(i::NEW_SPACE);
3601 // All objects should be alive.
3602 CHECK_EQ(0, counter.NumberOfWeakCalls());
3605 root.MakeWeak(&counter, &WeakPointerCallback);
3606 root.MarkPartiallyDependent();
3608 // Groups are deleted, rebuild groups.
3610 HandleScope handle_scope(iso);
3611 g1s1.MarkPartiallyDependent();
3612 g1s2.MarkPartiallyDependent();
3613 g2s1.MarkPartiallyDependent();
3614 g2s2.MarkPartiallyDependent();
3615 g3s1.MarkPartiallyDependent();
3616 g3s2.MarkPartiallyDependent();
3617 iso->SetObjectGroupId(g1s1, UniqueId(1));
3618 iso->SetObjectGroupId(g1s2, UniqueId(1));
3619 Local<Object>::New(iso, g1s1.As<Object>())->Set(
3620 v8_str("x"), Local<Value>::New(iso, g2s1));
3621 iso->SetObjectGroupId(g2s1, UniqueId(2));
3622 iso->SetObjectGroupId(g2s2, UniqueId(2));
3623 Local<Object>::New(iso, g2s1.As<Object>())->Set(
3624 v8_str("x"), Local<Value>::New(iso, g3s1));
3625 iso->SetObjectGroupId(g3s1, UniqueId(3));
3626 iso->SetObjectGroupId(g3s2, UniqueId(3));
3627 Local<Object>::New(iso, g3s1.As<Object>())->Set(
3628 v8_str("x"), Local<Value>::New(iso, g1s1));
3631 heap->CollectGarbage(i::NEW_SPACE);
3633 // All objects should be gone. 7 global handles in total.
3634 CHECK_EQ(7, counter.NumberOfWeakCalls());
3638 THREADED_TEST(ScriptException) {
3640 v8::HandleScope scope(env->GetIsolate());
3641 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
3642 v8::TryCatch try_catch;
3643 Local<Value> result = script->Run();
3644 CHECK(result.IsEmpty());
3645 CHECK(try_catch.HasCaught());
3646 String::Utf8Value exception_value(try_catch.Exception());
3647 CHECK_EQ(*exception_value, "panama!");
3651 TEST(TryCatchCustomException) {
3653 v8::HandleScope scope(env->GetIsolate());
3654 v8::TryCatch try_catch;
3655 CompileRun("function CustomError() { this.a = 'b'; }"
3656 "(function f() { throw new CustomError(); })();");
3657 CHECK(try_catch.HasCaught());
3658 CHECK(try_catch.Exception()->ToObject()->
3659 Get(v8_str("a"))->Equals(v8_str("b")));
3663 bool message_received;
3666 static void check_message_0(v8::Handle<v8::Message> message,
3667 v8::Handle<Value> data) {
3668 CHECK_EQ(5.76, data->NumberValue());
3669 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3670 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
3671 CHECK(!message->IsSharedCrossOrigin());
3672 message_received = true;
3676 THREADED_TEST(MessageHandler0) {
3677 message_received = false;
3678 v8::HandleScope scope(v8::Isolate::GetCurrent());
3679 CHECK(!message_received);
3680 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
3681 LocalContext context;
3682 v8::ScriptOrigin origin =
3683 v8::ScriptOrigin(v8_str("6.75"));
3684 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3686 script->SetData(v8_str("7.56"));
3688 CHECK(message_received);
3689 // clear out the message listener
3690 v8::V8::RemoveMessageListeners(check_message_0);
3694 static void check_message_1(v8::Handle<v8::Message> message,
3695 v8::Handle<Value> data) {
3696 CHECK(data->IsNumber());
3697 CHECK_EQ(1337, data->Int32Value());
3698 CHECK(!message->IsSharedCrossOrigin());
3699 message_received = true;
3703 TEST(MessageHandler1) {
3704 message_received = false;
3705 v8::HandleScope scope(v8::Isolate::GetCurrent());
3706 CHECK(!message_received);
3707 v8::V8::AddMessageListener(check_message_1);
3708 LocalContext context;
3709 CompileRun("throw 1337;");
3710 CHECK(message_received);
3711 // clear out the message listener
3712 v8::V8::RemoveMessageListeners(check_message_1);
3716 static void check_message_2(v8::Handle<v8::Message> message,
3717 v8::Handle<Value> data) {
3718 LocalContext context;
3719 CHECK(data->IsObject());
3720 v8::Local<v8::Value> hidden_property =
3721 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
3722 CHECK(v8_str("hidden value")->Equals(hidden_property));
3723 CHECK(!message->IsSharedCrossOrigin());
3724 message_received = true;
3728 TEST(MessageHandler2) {
3729 message_received = false;
3730 v8::HandleScope scope(v8::Isolate::GetCurrent());
3731 CHECK(!message_received);
3732 v8::V8::AddMessageListener(check_message_2);
3733 LocalContext context;
3734 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
3735 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
3736 v8_str("hidden value"));
3737 context->Global()->Set(v8_str("error"), error);
3738 CompileRun("throw error;");
3739 CHECK(message_received);
3740 // clear out the message listener
3741 v8::V8::RemoveMessageListeners(check_message_2);
3745 static void check_message_3(v8::Handle<v8::Message> message,
3746 v8::Handle<Value> data) {
3747 CHECK(message->IsSharedCrossOrigin());
3748 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3749 message_received = true;
3753 TEST(MessageHandler3) {
3754 message_received = false;
3755 v8::HandleScope scope(v8::Isolate::GetCurrent());
3756 CHECK(!message_received);
3757 v8::V8::AddMessageListener(check_message_3);
3758 LocalContext context;
3759 v8::ScriptOrigin origin =
3760 v8::ScriptOrigin(v8_str("6.75"),
3761 v8::Integer::New(1),
3762 v8::Integer::New(2),
3764 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3767 CHECK(message_received);
3768 // clear out the message listener
3769 v8::V8::RemoveMessageListeners(check_message_3);
3773 static void check_message_4(v8::Handle<v8::Message> message,
3774 v8::Handle<Value> data) {
3775 CHECK(!message->IsSharedCrossOrigin());
3776 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3777 message_received = true;
3781 TEST(MessageHandler4) {
3782 message_received = false;
3783 v8::HandleScope scope(v8::Isolate::GetCurrent());
3784 CHECK(!message_received);
3785 v8::V8::AddMessageListener(check_message_4);
3786 LocalContext context;
3787 v8::ScriptOrigin origin =
3788 v8::ScriptOrigin(v8_str("6.75"),
3789 v8::Integer::New(1),
3790 v8::Integer::New(2),
3792 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3795 CHECK(message_received);
3796 // clear out the message listener
3797 v8::V8::RemoveMessageListeners(check_message_4);
3801 static void check_message_5a(v8::Handle<v8::Message> message,
3802 v8::Handle<Value> data) {
3803 CHECK(message->IsSharedCrossOrigin());
3804 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3805 message_received = true;
3809 static void check_message_5b(v8::Handle<v8::Message> message,
3810 v8::Handle<Value> data) {
3811 CHECK(!message->IsSharedCrossOrigin());
3812 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3813 message_received = true;
3817 TEST(MessageHandler5) {
3818 message_received = false;
3819 v8::HandleScope scope(v8::Isolate::GetCurrent());
3820 CHECK(!message_received);
3821 v8::V8::AddMessageListener(check_message_5a);
3822 LocalContext context;
3823 v8::ScriptOrigin origin =
3824 v8::ScriptOrigin(v8_str("6.75"),
3825 v8::Integer::New(1),
3826 v8::Integer::New(2),
3828 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3831 CHECK(message_received);
3832 // clear out the message listener
3833 v8::V8::RemoveMessageListeners(check_message_5a);
3835 message_received = false;
3836 v8::V8::AddMessageListener(check_message_5b);
3838 v8::ScriptOrigin(v8_str("6.75"),
3839 v8::Integer::New(1),
3840 v8::Integer::New(2),
3842 script = Script::Compile(v8_str("throw 'error'"),
3845 CHECK(message_received);
3846 // clear out the message listener
3847 v8::V8::RemoveMessageListeners(check_message_5b);
3851 THREADED_TEST(GetSetProperty) {
3852 LocalContext context;
3853 v8::HandleScope scope(context->GetIsolate());
3854 context->Global()->Set(v8_str("foo"), v8_num(14));
3855 context->Global()->Set(v8_str("12"), v8_num(92));
3856 context->Global()->Set(v8::Integer::New(16), v8_num(32));
3857 context->Global()->Set(v8_num(13), v8_num(56));
3858 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
3859 CHECK_EQ(14, foo->Int32Value());
3860 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
3861 CHECK_EQ(92, twelve->Int32Value());
3862 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
3863 CHECK_EQ(32, sixteen->Int32Value());
3864 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
3865 CHECK_EQ(56, thirteen->Int32Value());
3866 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
3867 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
3868 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
3869 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
3870 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
3871 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
3872 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
3873 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
3874 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
3878 THREADED_TEST(PropertyAttributes) {
3879 LocalContext context;
3880 v8::HandleScope scope(context->GetIsolate());
3882 Local<String> prop = v8_str("none");
3883 context->Global()->Set(prop, v8_num(7));
3884 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
3886 prop = v8_str("read_only");
3887 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
3888 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3889 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
3890 Script::Compile(v8_str("read_only = 9"))->Run();
3891 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3892 context->Global()->Set(prop, v8_num(10));
3893 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3895 prop = v8_str("dont_delete");
3896 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
3897 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
3898 Script::Compile(v8_str("delete dont_delete"))->Run();
3899 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
3900 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
3902 prop = v8_str("dont_enum");
3903 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
3904 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
3906 prop = v8_str("absent");
3907 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
3908 Local<Value> fake_prop = v8_num(1);
3909 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
3912 Local<Value> exception =
3913 CompileRun("({ toString: function() { throw 'exception';} })");
3914 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
3915 CHECK(try_catch.HasCaught());
3916 String::Utf8Value exception_value(try_catch.Exception());
3917 CHECK_EQ("exception", *exception_value);
3922 THREADED_TEST(Array) {
3923 LocalContext context;
3924 v8::HandleScope scope(context->GetIsolate());
3925 Local<v8::Array> array = v8::Array::New();
3926 CHECK_EQ(0, array->Length());
3927 CHECK(array->Get(0)->IsUndefined());
3928 CHECK(!array->Has(0));
3929 CHECK(array->Get(100)->IsUndefined());
3930 CHECK(!array->Has(100));
3931 array->Set(2, v8_num(7));
3932 CHECK_EQ(3, array->Length());
3933 CHECK(!array->Has(0));
3934 CHECK(!array->Has(1));
3935 CHECK(array->Has(2));
3936 CHECK_EQ(7, array->Get(2)->Int32Value());
3937 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
3938 Local<v8::Array> arr = obj.As<v8::Array>();
3939 CHECK_EQ(3, arr->Length());
3940 CHECK_EQ(1, arr->Get(0)->Int32Value());
3941 CHECK_EQ(2, arr->Get(1)->Int32Value());
3942 CHECK_EQ(3, arr->Get(2)->Int32Value());
3943 array = v8::Array::New(27);
3944 CHECK_EQ(27, array->Length());
3945 array = v8::Array::New(-27);
3946 CHECK_EQ(0, array->Length());
3950 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
3951 v8::HandleScope scope(args.GetIsolate());
3952 ApiTestFuzzer::Fuzz();
3953 Local<v8::Array> result = v8::Array::New(args.Length());
3954 for (int i = 0; i < args.Length(); i++)
3955 result->Set(i, args[i]);
3956 args.GetReturnValue().Set(scope.Close(result));
3960 THREADED_TEST(Vector) {
3961 v8::HandleScope scope(v8::Isolate::GetCurrent());
3962 Local<ObjectTemplate> global = ObjectTemplate::New();
3963 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
3964 LocalContext context(0, global);
3966 const char* fun = "f()";
3967 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
3968 CHECK_EQ(0, a0->Length());
3970 const char* fun2 = "f(11)";
3971 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
3972 CHECK_EQ(1, a1->Length());
3973 CHECK_EQ(11, a1->Get(0)->Int32Value());
3975 const char* fun3 = "f(12, 13)";
3976 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
3977 CHECK_EQ(2, a2->Length());
3978 CHECK_EQ(12, a2->Get(0)->Int32Value());
3979 CHECK_EQ(13, a2->Get(1)->Int32Value());
3981 const char* fun4 = "f(14, 15, 16)";
3982 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
3983 CHECK_EQ(3, a3->Length());
3984 CHECK_EQ(14, a3->Get(0)->Int32Value());
3985 CHECK_EQ(15, a3->Get(1)->Int32Value());
3986 CHECK_EQ(16, a3->Get(2)->Int32Value());
3988 const char* fun5 = "f(17, 18, 19, 20)";
3989 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
3990 CHECK_EQ(4, a4->Length());
3991 CHECK_EQ(17, a4->Get(0)->Int32Value());
3992 CHECK_EQ(18, a4->Get(1)->Int32Value());
3993 CHECK_EQ(19, a4->Get(2)->Int32Value());
3994 CHECK_EQ(20, a4->Get(3)->Int32Value());
3998 THREADED_TEST(FunctionCall) {
3999 LocalContext context;
4000 v8::HandleScope scope(context->GetIsolate());
4004 " for (var i = 0; i < arguments.length; i++) {"
4005 " result.push(arguments[i]);"
4009 Local<Function> Foo =
4010 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4012 v8::Handle<Value>* args0 = NULL;
4013 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4014 CHECK_EQ(0, a0->Length());
4016 v8::Handle<Value> args1[] = { v8_num(1.1) };
4017 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4018 CHECK_EQ(1, a1->Length());
4019 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
4021 v8::Handle<Value> args2[] = { v8_num(2.2),
4023 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4024 CHECK_EQ(2, a2->Length());
4025 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
4026 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
4028 v8::Handle<Value> args3[] = { v8_num(4.4),
4031 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4032 CHECK_EQ(3, a3->Length());
4033 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
4034 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
4035 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
4037 v8::Handle<Value> args4[] = { v8_num(7.7),
4041 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4042 CHECK_EQ(4, a4->Length());
4043 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
4044 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
4045 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
4046 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
4050 static const char* js_code_causing_out_of_memory =
4051 "var a = new Array(); while(true) a.push(a);";
4054 // These tests run for a long time and prevent us from running tests
4055 // that come after them so they cannot run in parallel.
4057 // It's not possible to read a snapshot into a heap with different dimensions.
4058 if (i::Snapshot::IsEnabled()) return;
4060 static const int K = 1024;
4061 v8::ResourceConstraints constraints;
4062 constraints.set_max_young_space_size(256 * K);
4063 constraints.set_max_old_space_size(5 * K * K);
4064 v8::SetResourceConstraints(&constraints);
4066 // Execute a script that causes out of memory.
4067 LocalContext context;
4068 v8::HandleScope scope(context->GetIsolate());
4069 v8::V8::IgnoreOutOfMemoryException();
4070 Local<Script> script =
4071 Script::Compile(String::New(js_code_causing_out_of_memory));
4072 Local<Value> result = script->Run();
4074 // Check for out of memory state.
4075 CHECK(result.IsEmpty());
4076 CHECK(context->HasOutOfMemoryException());
4080 void ProvokeOutOfMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
4081 ApiTestFuzzer::Fuzz();
4083 LocalContext context;
4084 v8::HandleScope scope(context->GetIsolate());
4085 Local<Script> script =
4086 Script::Compile(String::New(js_code_causing_out_of_memory));
4087 Local<Value> result = script->Run();
4089 // Check for out of memory state.
4090 CHECK(result.IsEmpty());
4091 CHECK(context->HasOutOfMemoryException());
4093 args.GetReturnValue().Set(result);
4097 TEST(OutOfMemoryNested) {
4098 // It's not possible to read a snapshot into a heap with different dimensions.
4099 if (i::Snapshot::IsEnabled()) return;
4101 static const int K = 1024;
4102 v8::ResourceConstraints constraints;
4103 constraints.set_max_young_space_size(256 * K);
4104 constraints.set_max_old_space_size(5 * K * K);
4105 v8::SetResourceConstraints(&constraints);
4107 v8::HandleScope scope(v8::Isolate::GetCurrent());
4108 Local<ObjectTemplate> templ = ObjectTemplate::New();
4109 templ->Set(v8_str("ProvokeOutOfMemory"),
4110 v8::FunctionTemplate::New(ProvokeOutOfMemory));
4111 LocalContext context(0, templ);
4112 v8::V8::IgnoreOutOfMemoryException();
4113 Local<Value> result = CompileRun(
4114 "var thrown = false;"
4116 " ProvokeOutOfMemory();"
4120 // Check for out of memory state.
4121 CHECK(result.IsEmpty());
4122 CHECK(context->HasOutOfMemoryException());
4126 TEST(HugeConsStringOutOfMemory) {
4127 // It's not possible to read a snapshot into a heap with different dimensions.
4128 if (i::Snapshot::IsEnabled()) return;
4130 static const int K = 1024;
4131 v8::ResourceConstraints constraints;
4132 constraints.set_max_young_space_size(256 * K);
4133 constraints.set_max_old_space_size(4 * K * K);
4134 v8::SetResourceConstraints(&constraints);
4136 // Execute a script that causes out of memory.
4137 v8::V8::IgnoreOutOfMemoryException();
4139 LocalContext context;
4140 v8::HandleScope scope(context->GetIsolate());
4142 // Build huge string. This should fail with out of memory exception.
4143 Local<Value> result = CompileRun(
4144 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
4145 "for (var i = 0; i < 22; i++) { str = str + str; }");
4147 // Check for out of memory state.
4148 CHECK(result.IsEmpty());
4149 CHECK(context->HasOutOfMemoryException());
4153 THREADED_TEST(ConstructCall) {
4154 LocalContext context;
4155 v8::HandleScope scope(context->GetIsolate());
4159 " for (var i = 0; i < arguments.length; i++) {"
4160 " result.push(arguments[i]);"
4164 Local<Function> Foo =
4165 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4167 v8::Handle<Value>* args0 = NULL;
4168 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4169 CHECK_EQ(0, a0->Length());
4171 v8::Handle<Value> args1[] = { v8_num(1.1) };
4172 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4173 CHECK_EQ(1, a1->Length());
4174 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
4176 v8::Handle<Value> args2[] = { v8_num(2.2),
4178 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4179 CHECK_EQ(2, a2->Length());
4180 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
4181 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
4183 v8::Handle<Value> args3[] = { v8_num(4.4),
4186 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4187 CHECK_EQ(3, a3->Length());
4188 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
4189 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
4190 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
4192 v8::Handle<Value> args4[] = { v8_num(7.7),
4196 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4197 CHECK_EQ(4, a4->Length());
4198 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
4199 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
4200 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
4201 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
4205 static void CheckUncle(v8::TryCatch* try_catch) {
4206 CHECK(try_catch->HasCaught());
4207 String::Utf8Value str_value(try_catch->Exception());
4208 CHECK_EQ(*str_value, "uncle?");
4213 THREADED_TEST(ConversionNumber) {
4215 v8::HandleScope scope(env->GetIsolate());
4216 // Very large number.
4217 CompileRun("var obj = Math.pow(2,32) * 1237;");
4218 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4219 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4220 CHECK_EQ(0, obj->ToInt32()->Value());
4221 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4223 CompileRun("var obj = -1234567890123;");
4224 obj = env->Global()->Get(v8_str("obj"));
4225 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4226 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4227 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4228 // Small positive integer.
4229 CompileRun("var obj = 42;");
4230 obj = env->Global()->Get(v8_str("obj"));
4231 CHECK_EQ(42.0, obj->ToNumber()->Value());
4232 CHECK_EQ(42, obj->ToInt32()->Value());
4233 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4234 // Negative integer.
4235 CompileRun("var obj = -37;");
4236 obj = env->Global()->Get(v8_str("obj"));
4237 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4238 CHECK_EQ(-37, obj->ToInt32()->Value());
4239 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4240 // Positive non-int32 integer.
4241 CompileRun("var obj = 0x81234567;");
4242 obj = env->Global()->Get(v8_str("obj"));
4243 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4244 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4245 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4247 CompileRun("var obj = 42.3;");
4248 obj = env->Global()->Get(v8_str("obj"));
4249 CHECK_EQ(42.3, obj->ToNumber()->Value());
4250 CHECK_EQ(42, obj->ToInt32()->Value());
4251 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4252 // Large negative fraction.
4253 CompileRun("var obj = -5726623061.75;");
4254 obj = env->Global()->Get(v8_str("obj"));
4255 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4256 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4257 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4261 THREADED_TEST(isNumberType) {
4263 v8::HandleScope scope(env->GetIsolate());
4264 // Very large number.
4265 CompileRun("var obj = Math.pow(2,32) * 1237;");
4266 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4267 CHECK(!obj->IsInt32());
4268 CHECK(!obj->IsUint32());
4269 // Large negative number.
4270 CompileRun("var obj = -1234567890123;");
4271 obj = env->Global()->Get(v8_str("obj"));
4272 CHECK(!obj->IsInt32());
4273 CHECK(!obj->IsUint32());
4274 // Small positive integer.
4275 CompileRun("var obj = 42;");
4276 obj = env->Global()->Get(v8_str("obj"));
4277 CHECK(obj->IsInt32());
4278 CHECK(obj->IsUint32());
4279 // Negative integer.
4280 CompileRun("var obj = -37;");
4281 obj = env->Global()->Get(v8_str("obj"));
4282 CHECK(obj->IsInt32());
4283 CHECK(!obj->IsUint32());
4284 // Positive non-int32 integer.
4285 CompileRun("var obj = 0x81234567;");
4286 obj = env->Global()->Get(v8_str("obj"));
4287 CHECK(!obj->IsInt32());
4288 CHECK(obj->IsUint32());
4290 CompileRun("var obj = 42.3;");
4291 obj = env->Global()->Get(v8_str("obj"));
4292 CHECK(!obj->IsInt32());
4293 CHECK(!obj->IsUint32());
4294 // Large negative fraction.
4295 CompileRun("var obj = -5726623061.75;");
4296 obj = env->Global()->Get(v8_str("obj"));
4297 CHECK(!obj->IsInt32());
4298 CHECK(!obj->IsUint32());
4300 CompileRun("var obj = 0.0;");
4301 obj = env->Global()->Get(v8_str("obj"));
4302 CHECK(obj->IsInt32());
4303 CHECK(obj->IsUint32());
4305 CompileRun("var obj = -0.0;");
4306 obj = env->Global()->Get(v8_str("obj"));
4307 CHECK(!obj->IsInt32());
4308 CHECK(!obj->IsUint32());
4312 THREADED_TEST(ConversionException) {
4314 v8::HandleScope scope(env->GetIsolate());
4316 "function TestClass() { };"
4317 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4318 "var obj = new TestClass();");
4319 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4321 v8::TryCatch try_catch;
4323 Local<Value> to_string_result = obj->ToString();
4324 CHECK(to_string_result.IsEmpty());
4325 CheckUncle(&try_catch);
4327 Local<Value> to_number_result = obj->ToNumber();
4328 CHECK(to_number_result.IsEmpty());
4329 CheckUncle(&try_catch);
4331 Local<Value> to_integer_result = obj->ToInteger();
4332 CHECK(to_integer_result.IsEmpty());
4333 CheckUncle(&try_catch);
4335 Local<Value> to_uint32_result = obj->ToUint32();
4336 CHECK(to_uint32_result.IsEmpty());
4337 CheckUncle(&try_catch);
4339 Local<Value> to_int32_result = obj->ToInt32();
4340 CHECK(to_int32_result.IsEmpty());
4341 CheckUncle(&try_catch);
4343 Local<Value> to_object_result = v8::Undefined()->ToObject();
4344 CHECK(to_object_result.IsEmpty());
4345 CHECK(try_catch.HasCaught());
4348 int32_t int32_value = obj->Int32Value();
4349 CHECK_EQ(0, int32_value);
4350 CheckUncle(&try_catch);
4352 uint32_t uint32_value = obj->Uint32Value();
4353 CHECK_EQ(0, uint32_value);
4354 CheckUncle(&try_catch);
4356 double number_value = obj->NumberValue();
4357 CHECK_NE(0, std::isnan(number_value));
4358 CheckUncle(&try_catch);
4360 int64_t integer_value = obj->IntegerValue();
4361 CHECK_EQ(0.0, static_cast<double>(integer_value));
4362 CheckUncle(&try_catch);
4366 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4367 ApiTestFuzzer::Fuzz();
4368 v8::ThrowException(v8_str("konto"));
4372 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4373 if (args.Length() < 1) {
4374 args.GetReturnValue().Set(false);
4377 v8::HandleScope scope(args.GetIsolate());
4378 v8::TryCatch try_catch;
4379 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
4380 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4381 args.GetReturnValue().Set(try_catch.HasCaught());
4385 THREADED_TEST(APICatch) {
4386 v8::HandleScope scope(v8::Isolate::GetCurrent());
4387 Local<ObjectTemplate> templ = ObjectTemplate::New();
4388 templ->Set(v8_str("ThrowFromC"),
4389 v8::FunctionTemplate::New(ThrowFromC));
4390 LocalContext context(0, templ);
4392 "var thrown = false;"
4398 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4399 CHECK(thrown->BooleanValue());
4403 THREADED_TEST(APIThrowTryCatch) {
4404 v8::HandleScope scope(v8::Isolate::GetCurrent());
4405 Local<ObjectTemplate> templ = ObjectTemplate::New();
4406 templ->Set(v8_str("ThrowFromC"),
4407 v8::FunctionTemplate::New(ThrowFromC));
4408 LocalContext context(0, templ);
4409 v8::TryCatch try_catch;
4410 CompileRun("ThrowFromC();");
4411 CHECK(try_catch.HasCaught());
4415 // Test that a try-finally block doesn't shadow a try-catch block
4416 // when setting up an external handler.
4418 // BUG(271): Some of the exception propagation does not work on the
4419 // ARM simulator because the simulator separates the C++ stack and the
4420 // JS stack. This test therefore fails on the simulator. The test is
4421 // not threaded to allow the threading tests to run on the simulator.
4422 TEST(TryCatchInTryFinally) {
4423 v8::HandleScope scope(v8::Isolate::GetCurrent());
4424 Local<ObjectTemplate> templ = ObjectTemplate::New();
4425 templ->Set(v8_str("CCatcher"),
4426 v8::FunctionTemplate::New(CCatcher));
4427 LocalContext context(0, templ);
4428 Local<Value> result = CompileRun("try {"
4430 " CCatcher('throw 7;');"
4435 CHECK(result->IsTrue());
4439 static void check_reference_error_message(
4440 v8::Handle<v8::Message> message,
4441 v8::Handle<v8::Value> data) {
4442 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4443 CHECK(message->Get()->Equals(v8_str(reference_error)));
4447 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4448 ApiTestFuzzer::Fuzz();
4453 // Test that overwritten methods are not invoked on uncaught exception
4454 // formatting. However, they are invoked when performing normal error
4455 // string conversions.
4456 TEST(APIThrowMessageOverwrittenToString) {
4457 v8::HandleScope scope(v8::Isolate::GetCurrent());
4458 v8::V8::AddMessageListener(check_reference_error_message);
4459 Local<ObjectTemplate> templ = ObjectTemplate::New();
4460 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
4461 LocalContext context(NULL, templ);
4462 CompileRun("asdf;");
4463 CompileRun("var limit = {};"
4464 "limit.valueOf = fail;"
4465 "Error.stackTraceLimit = limit;");
4467 CompileRun("Array.prototype.pop = fail;");
4468 CompileRun("Object.prototype.hasOwnProperty = fail;");
4469 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4470 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4471 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4472 CompileRun("ReferenceError.prototype.toString ="
4473 " function() { return 'Whoops' }");
4474 CompileRun("asdf;");
4475 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4476 CompileRun("asdf;");
4477 CompileRun("ReferenceError.prototype.constructor = void 0;");
4478 CompileRun("asdf;");
4479 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4480 CompileRun("asdf;");
4481 CompileRun("ReferenceError.prototype = new Object();");
4482 CompileRun("asdf;");
4483 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4484 CHECK(string->Equals(v8_str("Whoops")));
4485 CompileRun("ReferenceError.prototype.constructor = new Object();"
4486 "ReferenceError.prototype.constructor.name = 1;"
4487 "Number.prototype.toString = function() { return 'Whoops'; };"
4488 "ReferenceError.prototype.toString = Object.prototype.toString;");
4489 CompileRun("asdf;");
4490 v8::V8::RemoveMessageListeners(check_reference_error_message);
4494 static void check_custom_error_tostring(
4495 v8::Handle<v8::Message> message,
4496 v8::Handle<v8::Value> data) {
4497 const char* uncaught_error = "Uncaught MyError toString";
4498 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4502 TEST(CustomErrorToString) {
4503 LocalContext context;
4504 v8::HandleScope scope(context->GetIsolate());
4505 v8::V8::AddMessageListener(check_custom_error_tostring);
4507 "function MyError(name, message) { "
4508 " this.name = name; "
4509 " this.message = message; "
4511 "MyError.prototype = Object.create(Error.prototype); "
4512 "MyError.prototype.toString = function() { "
4513 " return 'MyError toString'; "
4515 "throw new MyError('my name', 'my message'); ");
4516 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4520 static void check_custom_error_message(
4521 v8::Handle<v8::Message> message,
4522 v8::Handle<v8::Value> data) {
4523 const char* uncaught_error = "Uncaught MyError: my message";
4524 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4525 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4529 TEST(CustomErrorMessage) {
4530 LocalContext context;
4531 v8::HandleScope scope(context->GetIsolate());
4532 v8::V8::AddMessageListener(check_custom_error_message);
4536 "function MyError(msg) { "
4537 " this.name = 'MyError'; "
4538 " this.message = msg; "
4540 "MyError.prototype = new Error(); "
4541 "throw new MyError('my message'); ");
4545 "function MyError(msg) { "
4546 " this.name = 'MyError'; "
4547 " this.message = msg; "
4549 "inherits = function(childCtor, parentCtor) { "
4550 " function tempCtor() {}; "
4551 " tempCtor.prototype = parentCtor.prototype; "
4552 " childCtor.superClass_ = parentCtor.prototype; "
4553 " childCtor.prototype = new tempCtor(); "
4554 " childCtor.prototype.constructor = childCtor; "
4556 "inherits(MyError, Error); "
4557 "throw new MyError('my message'); ");
4561 "function MyError(msg) { "
4562 " this.name = 'MyError'; "
4563 " this.message = msg; "
4565 "MyError.prototype = Object.create(Error.prototype); "
4566 "throw new MyError('my message'); ");
4568 v8::V8::RemoveMessageListeners(check_custom_error_message);
4572 static void receive_message(v8::Handle<v8::Message> message,
4573 v8::Handle<v8::Value> data) {
4575 message_received = true;
4579 TEST(APIThrowMessage) {
4580 message_received = false;
4581 v8::HandleScope scope(v8::Isolate::GetCurrent());
4582 v8::V8::AddMessageListener(receive_message);
4583 Local<ObjectTemplate> templ = ObjectTemplate::New();
4584 templ->Set(v8_str("ThrowFromC"),
4585 v8::FunctionTemplate::New(ThrowFromC));
4586 LocalContext context(0, templ);
4587 CompileRun("ThrowFromC();");
4588 CHECK(message_received);
4589 v8::V8::RemoveMessageListeners(receive_message);
4593 TEST(APIThrowMessageAndVerboseTryCatch) {
4594 message_received = false;
4595 v8::HandleScope scope(v8::Isolate::GetCurrent());
4596 v8::V8::AddMessageListener(receive_message);
4597 Local<ObjectTemplate> templ = ObjectTemplate::New();
4598 templ->Set(v8_str("ThrowFromC"),
4599 v8::FunctionTemplate::New(ThrowFromC));
4600 LocalContext context(0, templ);
4601 v8::TryCatch try_catch;
4602 try_catch.SetVerbose(true);
4603 Local<Value> result = CompileRun("ThrowFromC();");
4604 CHECK(try_catch.HasCaught());
4605 CHECK(result.IsEmpty());
4606 CHECK(message_received);
4607 v8::V8::RemoveMessageListeners(receive_message);
4611 TEST(APIStackOverflowAndVerboseTryCatch) {
4612 message_received = false;
4613 LocalContext context;
4614 v8::HandleScope scope(context->GetIsolate());
4615 v8::V8::AddMessageListener(receive_message);
4616 v8::TryCatch try_catch;
4617 try_catch.SetVerbose(true);
4618 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
4619 CHECK(try_catch.HasCaught());
4620 CHECK(result.IsEmpty());
4621 CHECK(message_received);
4622 v8::V8::RemoveMessageListeners(receive_message);
4626 THREADED_TEST(ExternalScriptException) {
4627 v8::HandleScope scope(v8::Isolate::GetCurrent());
4628 Local<ObjectTemplate> templ = ObjectTemplate::New();
4629 templ->Set(v8_str("ThrowFromC"),
4630 v8::FunctionTemplate::New(ThrowFromC));
4631 LocalContext context(0, templ);
4633 v8::TryCatch try_catch;
4634 Local<Script> script
4635 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
4636 Local<Value> result = script->Run();
4637 CHECK(result.IsEmpty());
4638 CHECK(try_catch.HasCaught());
4639 String::Utf8Value exception_value(try_catch.Exception());
4640 CHECK_EQ("konto", *exception_value);
4645 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
4646 ApiTestFuzzer::Fuzz();
4647 CHECK_EQ(4, args.Length());
4648 int count = args[0]->Int32Value();
4649 int cInterval = args[2]->Int32Value();
4651 v8::ThrowException(v8_str("FromC"));
4654 Local<v8::Object> global = Context::GetCurrent()->Global();
4655 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
4656 v8::Handle<Value> argv[] = { v8_num(count - 1),
4660 if (count % cInterval == 0) {
4661 v8::TryCatch try_catch;
4662 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
4663 int expected = args[3]->Int32Value();
4664 if (try_catch.HasCaught()) {
4665 CHECK_EQ(expected, count);
4666 CHECK(result.IsEmpty());
4667 CHECK(!i::Isolate::Current()->has_scheduled_exception());
4669 CHECK_NE(expected, count);
4671 args.GetReturnValue().Set(result);
4674 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
4681 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
4682 ApiTestFuzzer::Fuzz();
4683 CHECK_EQ(3, args.Length());
4684 bool equality = args[0]->BooleanValue();
4685 int count = args[1]->Int32Value();
4686 int expected = args[2]->Int32Value();
4688 CHECK_EQ(count, expected);
4690 CHECK_NE(count, expected);
4695 THREADED_TEST(EvalInTryFinally) {
4696 LocalContext context;
4697 v8::HandleScope scope(context->GetIsolate());
4698 v8::TryCatch try_catch;
4699 CompileRun("(function() {"
4701 " eval('asldkf (*&^&*^');"
4706 CHECK(!try_catch.HasCaught());
4710 // This test works by making a stack of alternating JavaScript and C
4711 // activations. These activations set up exception handlers with regular
4712 // intervals, one interval for C activations and another for JavaScript
4713 // activations. When enough activations have been created an exception is
4714 // thrown and we check that the right activation catches the exception and that
4715 // no other activations do. The right activation is always the topmost one with
4716 // a handler, regardless of whether it is in JavaScript or C.
4718 // The notation used to describe a test case looks like this:
4720 // *JS[4] *C[3] @JS[2] C[1] JS[0]
4722 // Each entry is an activation, either JS or C. The index is the count at that
4723 // level. Stars identify activations with exception handlers, the @ identifies
4724 // the exception handler that should catch the exception.
4726 // BUG(271): Some of the exception propagation does not work on the
4727 // ARM simulator because the simulator separates the C++ stack and the
4728 // JS stack. This test therefore fails on the simulator. The test is
4729 // not threaded to allow the threading tests to run on the simulator.
4730 TEST(ExceptionOrder) {
4731 v8::HandleScope scope(v8::Isolate::GetCurrent());
4732 Local<ObjectTemplate> templ = ObjectTemplate::New();
4733 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
4734 templ->Set(v8_str("CThrowCountDown"),
4735 v8::FunctionTemplate::New(CThrowCountDown));
4736 LocalContext context(0, templ);
4738 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
4739 " if (count == 0) throw 'FromJS';"
4740 " if (count % jsInterval == 0) {"
4742 " var value = CThrowCountDown(count - 1,"
4746 " check(false, count, expected);"
4749 " check(true, count, expected);"
4752 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
4755 Local<Function> fun =
4756 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
4759 // count jsInterval cInterval expected
4761 // *JS[4] *C[3] @JS[2] C[1] JS[0]
4762 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
4763 fun->Call(fun, argc, a0);
4765 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
4766 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
4767 fun->Call(fun, argc, a1);
4769 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
4770 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
4771 fun->Call(fun, argc, a2);
4773 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
4774 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
4775 fun->Call(fun, argc, a3);
4777 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
4778 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
4779 fun->Call(fun, argc, a4);
4781 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
4782 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
4783 fun->Call(fun, argc, a5);
4787 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
4788 ApiTestFuzzer::Fuzz();
4789 CHECK_EQ(1, args.Length());
4790 v8::ThrowException(args[0]);
4794 THREADED_TEST(ThrowValues) {
4795 v8::HandleScope scope(v8::Isolate::GetCurrent());
4796 Local<ObjectTemplate> templ = ObjectTemplate::New();
4797 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
4798 LocalContext context(0, templ);
4799 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4800 "function Run(obj) {"
4806 " return 'no exception';"
4808 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
4809 CHECK_EQ(5, result->Length());
4810 CHECK(result->Get(v8::Integer::New(0))->IsString());
4811 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
4812 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
4813 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
4814 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
4815 CHECK(result->Get(v8::Integer::New(3))->IsNull());
4816 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
4820 THREADED_TEST(CatchZero) {
4821 LocalContext context;
4822 v8::HandleScope scope(context->GetIsolate());
4823 v8::TryCatch try_catch;
4824 CHECK(!try_catch.HasCaught());
4825 Script::Compile(v8_str("throw 10"))->Run();
4826 CHECK(try_catch.HasCaught());
4827 CHECK_EQ(10, try_catch.Exception()->Int32Value());
4829 CHECK(!try_catch.HasCaught());
4830 Script::Compile(v8_str("throw 0"))->Run();
4831 CHECK(try_catch.HasCaught());
4832 CHECK_EQ(0, try_catch.Exception()->Int32Value());
4836 THREADED_TEST(CatchExceptionFromWith) {
4837 LocalContext context;
4838 v8::HandleScope scope(context->GetIsolate());
4839 v8::TryCatch try_catch;
4840 CHECK(!try_catch.HasCaught());
4841 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
4842 CHECK(try_catch.HasCaught());
4846 THREADED_TEST(TryCatchAndFinallyHidingException) {
4847 LocalContext context;
4848 v8::HandleScope scope(context->GetIsolate());
4849 v8::TryCatch try_catch;
4850 CHECK(!try_catch.HasCaught());
4851 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
4852 CompileRun("f({toString: function() { throw 42; }});");
4853 CHECK(!try_catch.HasCaught());
4857 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
4858 v8::TryCatch try_catch;
4862 THREADED_TEST(TryCatchAndFinally) {
4863 LocalContext context;
4864 v8::HandleScope scope(context->GetIsolate());
4865 context->Global()->Set(
4866 v8_str("native_with_try_catch"),
4867 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
4868 v8::TryCatch try_catch;
4869 CHECK(!try_catch.HasCaught());
4872 " throw new Error('a');\n"
4874 " native_with_try_catch();\n"
4876 CHECK(try_catch.HasCaught());
4880 static void TryCatchNestedHelper(int depth) {
4882 v8::TryCatch try_catch;
4883 try_catch.SetVerbose(true);
4884 TryCatchNestedHelper(depth - 1);
4885 CHECK(try_catch.HasCaught());
4886 try_catch.ReThrow();
4888 v8::ThrowException(v8_str("back"));
4893 TEST(TryCatchNested) {
4894 v8::V8::Initialize();
4895 LocalContext context;
4896 v8::HandleScope scope(context->GetIsolate());
4897 v8::TryCatch try_catch;
4898 TryCatchNestedHelper(5);
4899 CHECK(try_catch.HasCaught());
4900 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
4904 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
4905 CHECK(try_catch->HasCaught());
4906 Handle<Message> message = try_catch->Message();
4907 Handle<Value> resource = message->GetScriptResourceName();
4908 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
4909 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
4910 "Uncaught Error: a"));
4911 CHECK_EQ(1, message->GetLineNumber());
4912 CHECK_EQ(6, message->GetStartColumn());
4916 void TryCatchMixedNestingHelper(
4917 const v8::FunctionCallbackInfo<v8::Value>& args) {
4918 ApiTestFuzzer::Fuzz();
4919 v8::TryCatch try_catch;
4920 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
4921 CHECK(try_catch.HasCaught());
4922 TryCatchMixedNestingCheck(&try_catch);
4923 try_catch.ReThrow();
4927 // This test ensures that an outer TryCatch in the following situation:
4928 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
4929 // does not clobber the Message object generated for the inner TryCatch.
4930 // This exercises the ability of TryCatch.ReThrow() to restore the
4931 // inner pending Message before throwing the exception again.
4932 TEST(TryCatchMixedNesting) {
4933 v8::HandleScope scope(v8::Isolate::GetCurrent());
4934 v8::V8::Initialize();
4935 v8::TryCatch try_catch;
4936 Local<ObjectTemplate> templ = ObjectTemplate::New();
4937 templ->Set(v8_str("TryCatchMixedNestingHelper"),
4938 v8::FunctionTemplate::New(TryCatchMixedNestingHelper));
4939 LocalContext context(0, templ);
4940 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
4941 TryCatchMixedNestingCheck(&try_catch);
4945 THREADED_TEST(Equality) {
4946 LocalContext context;
4947 v8::Isolate* isolate = context->GetIsolate();
4948 v8::HandleScope scope(context->GetIsolate());
4949 // Check that equality works at all before relying on CHECK_EQ
4950 CHECK(v8_str("a")->Equals(v8_str("a")));
4951 CHECK(!v8_str("a")->Equals(v8_str("b")));
4953 CHECK_EQ(v8_str("a"), v8_str("a"));
4954 CHECK_NE(v8_str("a"), v8_str("b"));
4955 CHECK_EQ(v8_num(1), v8_num(1));
4956 CHECK_EQ(v8_num(1.00), v8_num(1));
4957 CHECK_NE(v8_num(1), v8_num(2));
4959 // Assume String is not internalized.
4960 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
4961 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
4962 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
4963 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
4964 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
4965 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
4966 Local<Value> not_a_number = v8_num(i::OS::nan_value());
4967 CHECK(!not_a_number->StrictEquals(not_a_number));
4968 CHECK(v8::False()->StrictEquals(v8::False()));
4969 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
4971 v8::Handle<v8::Object> obj = v8::Object::New();
4972 v8::Persistent<v8::Object> alias(isolate, obj);
4973 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
4978 THREADED_TEST(MultiRun) {
4979 LocalContext context;
4980 v8::HandleScope scope(context->GetIsolate());
4981 Local<Script> script = Script::Compile(v8_str("x"));
4982 for (int i = 0; i < 10; i++)
4987 static void GetXValue(Local<String> name,
4988 const v8::PropertyCallbackInfo<v8::Value>& info) {
4989 ApiTestFuzzer::Fuzz();
4990 CHECK_EQ(info.Data(), v8_str("donut"));
4991 CHECK_EQ(name, v8_str("x"));
4992 info.GetReturnValue().Set(name);
4996 THREADED_TEST(SimplePropertyRead) {
4997 LocalContext context;
4998 v8::HandleScope scope(context->GetIsolate());
4999 Local<ObjectTemplate> templ = ObjectTemplate::New();
5000 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5001 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5002 Local<Script> script = Script::Compile(v8_str("obj.x"));
5003 for (int i = 0; i < 10; i++) {
5004 Local<Value> result = script->Run();
5005 CHECK_EQ(result, v8_str("x"));
5010 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5011 LocalContext context;
5012 v8::HandleScope scope(context->GetIsolate());
5013 Local<ObjectTemplate> templ = ObjectTemplate::New();
5014 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5015 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5017 // Uses getOwnPropertyDescriptor to check the configurable status
5018 Local<Script> script_desc
5019 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
5021 "prop.configurable;"));
5022 Local<Value> result = script_desc->Run();
5023 CHECK_EQ(result->BooleanValue(), true);
5025 // Redefine get - but still configurable
5026 Local<Script> script_define
5027 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
5028 " configurable: true };"
5029 "Object.defineProperty(obj, 'x', desc);"
5031 result = script_define->Run();
5032 CHECK_EQ(result, v8_num(42));
5034 // Check that the accessor is still configurable
5035 result = script_desc->Run();
5036 CHECK_EQ(result->BooleanValue(), true);
5038 // Redefine to a non-configurable
5040 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
5041 " configurable: false };"
5042 "Object.defineProperty(obj, 'x', desc);"
5044 result = script_define->Run();
5045 CHECK_EQ(result, v8_num(43));
5046 result = script_desc->Run();
5047 CHECK_EQ(result->BooleanValue(), false);
5049 // Make sure that it is not possible to redefine again
5050 v8::TryCatch try_catch;
5051 result = script_define->Run();
5052 CHECK(try_catch.HasCaught());
5053 String::Utf8Value exception_value(try_catch.Exception());
5054 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5058 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5059 v8::HandleScope scope(v8::Isolate::GetCurrent());
5060 Local<ObjectTemplate> templ = ObjectTemplate::New();
5061 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5062 LocalContext context;
5063 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5065 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
5066 "Object.getOwnPropertyDescriptor( "
5068 "prop.configurable;"));
5069 Local<Value> result = script_desc->Run();
5070 CHECK_EQ(result->BooleanValue(), true);
5072 Local<Script> script_define =
5073 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
5074 " configurable: true };"
5075 "Object.defineProperty(obj, 'x', desc);"
5077 result = script_define->Run();
5078 CHECK_EQ(result, v8_num(42));
5081 result = script_desc->Run();
5082 CHECK_EQ(result->BooleanValue(), true);
5086 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
5087 " configurable: false };"
5088 "Object.defineProperty(obj, 'x', desc);"
5090 result = script_define->Run();
5091 CHECK_EQ(result, v8_num(43));
5092 result = script_desc->Run();
5094 CHECK_EQ(result->BooleanValue(), false);
5096 v8::TryCatch try_catch;
5097 result = script_define->Run();
5098 CHECK(try_catch.HasCaught());
5099 String::Utf8Value exception_value(try_catch.Exception());
5100 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5104 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5106 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5110 THREADED_TEST(DefineAPIAccessorOnObject) {
5111 v8::HandleScope scope(v8::Isolate::GetCurrent());
5112 Local<ObjectTemplate> templ = ObjectTemplate::New();
5113 LocalContext context;
5115 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5116 CompileRun("var obj2 = {};");
5118 CHECK(CompileRun("obj1.x")->IsUndefined());
5119 CHECK(CompileRun("obj2.x")->IsUndefined());
5121 CHECK(GetGlobalProperty(&context, "obj1")->
5122 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5124 ExpectString("obj1.x", "x");
5125 CHECK(CompileRun("obj2.x")->IsUndefined());
5127 CHECK(GetGlobalProperty(&context, "obj2")->
5128 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5130 ExpectString("obj1.x", "x");
5131 ExpectString("obj2.x", "x");
5133 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5134 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5136 CompileRun("Object.defineProperty(obj1, 'x',"
5137 "{ get: function() { return 'y'; }, configurable: true })");
5139 ExpectString("obj1.x", "y");
5140 ExpectString("obj2.x", "x");
5142 CompileRun("Object.defineProperty(obj2, 'x',"
5143 "{ get: function() { return 'y'; }, configurable: true })");
5145 ExpectString("obj1.x", "y");
5146 ExpectString("obj2.x", "y");
5148 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5149 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5151 CHECK(GetGlobalProperty(&context, "obj1")->
5152 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5153 CHECK(GetGlobalProperty(&context, "obj2")->
5154 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5156 ExpectString("obj1.x", "x");
5157 ExpectString("obj2.x", "x");
5159 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5160 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5162 // Define getters/setters, but now make them not configurable.
5163 CompileRun("Object.defineProperty(obj1, 'x',"
5164 "{ get: function() { return 'z'; }, configurable: false })");
5165 CompileRun("Object.defineProperty(obj2, 'x',"
5166 "{ get: function() { return 'z'; }, configurable: false })");
5168 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5169 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5171 ExpectString("obj1.x", "z");
5172 ExpectString("obj2.x", "z");
5174 CHECK(!GetGlobalProperty(&context, "obj1")->
5175 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5176 CHECK(!GetGlobalProperty(&context, "obj2")->
5177 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5179 ExpectString("obj1.x", "z");
5180 ExpectString("obj2.x", "z");
5184 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5185 v8::HandleScope scope(v8::Isolate::GetCurrent());
5186 Local<ObjectTemplate> templ = ObjectTemplate::New();
5187 LocalContext context;
5189 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5190 CompileRun("var obj2 = {};");
5192 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5195 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5196 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5199 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5201 ExpectString("obj1.x", "x");
5202 ExpectString("obj2.x", "x");
5204 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5205 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5207 CHECK(!GetGlobalProperty(&context, "obj1")->
5208 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5209 CHECK(!GetGlobalProperty(&context, "obj2")->
5210 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5213 v8::TryCatch try_catch;
5214 CompileRun("Object.defineProperty(obj1, 'x',"
5215 "{get: function() { return 'func'; }})");
5216 CHECK(try_catch.HasCaught());
5217 String::Utf8Value exception_value(try_catch.Exception());
5218 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5221 v8::TryCatch try_catch;
5222 CompileRun("Object.defineProperty(obj2, 'x',"
5223 "{get: function() { return 'func'; }})");
5224 CHECK(try_catch.HasCaught());
5225 String::Utf8Value exception_value(try_catch.Exception());
5226 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5231 static void Get239Value(Local<String> name,
5232 const v8::PropertyCallbackInfo<v8::Value>& info) {
5233 ApiTestFuzzer::Fuzz();
5234 CHECK_EQ(info.Data(), v8_str("donut"));
5235 CHECK_EQ(name, v8_str("239"));
5236 info.GetReturnValue().Set(name);
5240 THREADED_TEST(ElementAPIAccessor) {
5241 v8::HandleScope scope(v8::Isolate::GetCurrent());
5242 Local<ObjectTemplate> templ = ObjectTemplate::New();
5243 LocalContext context;
5245 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5246 CompileRun("var obj2 = {};");
5248 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5252 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5257 ExpectString("obj1[239]", "239");
5258 ExpectString("obj2[239]", "239");
5259 ExpectString("obj1['239']", "239");
5260 ExpectString("obj2['239']", "239");
5264 v8::Persistent<Value> xValue;
5267 static void SetXValue(Local<String> name,
5269 const v8::PropertyCallbackInfo<void>& info) {
5270 CHECK_EQ(value, v8_num(4));
5271 CHECK_EQ(info.Data(), v8_str("donut"));
5272 CHECK_EQ(name, v8_str("x"));
5273 CHECK(xValue.IsEmpty());
5274 xValue.Reset(info.GetIsolate(), value);
5278 THREADED_TEST(SimplePropertyWrite) {
5279 v8::HandleScope scope(v8::Isolate::GetCurrent());
5280 Local<ObjectTemplate> templ = ObjectTemplate::New();
5281 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5282 LocalContext context;
5283 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5284 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
5285 for (int i = 0; i < 10; i++) {
5286 CHECK(xValue.IsEmpty());
5288 CHECK_EQ(v8_num(4), Local<Value>::New(v8::Isolate::GetCurrent(), xValue));
5295 THREADED_TEST(SetterOnly) {
5296 v8::HandleScope scope(v8::Isolate::GetCurrent());
5297 Local<ObjectTemplate> templ = ObjectTemplate::New();
5298 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5299 LocalContext context;
5300 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5301 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5302 for (int i = 0; i < 10; i++) {
5303 CHECK(xValue.IsEmpty());
5305 CHECK_EQ(v8_num(4), Local<Value>::New(v8::Isolate::GetCurrent(), xValue));
5312 THREADED_TEST(NoAccessors) {
5313 v8::HandleScope scope(v8::Isolate::GetCurrent());
5314 Local<ObjectTemplate> templ = ObjectTemplate::New();
5315 templ->SetAccessor(v8_str("x"),
5316 static_cast<v8::AccessorGetterCallback>(NULL),
5319 LocalContext context;
5320 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5321 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5322 for (int i = 0; i < 10; i++) {
5328 static void XPropertyGetter(Local<String> property,
5329 const v8::PropertyCallbackInfo<v8::Value>& info) {
5330 ApiTestFuzzer::Fuzz();
5331 CHECK(info.Data()->IsUndefined());
5332 info.GetReturnValue().Set(property);
5336 THREADED_TEST(NamedInterceptorPropertyRead) {
5337 v8::HandleScope scope(v8::Isolate::GetCurrent());
5338 Local<ObjectTemplate> templ = ObjectTemplate::New();
5339 templ->SetNamedPropertyHandler(XPropertyGetter);
5340 LocalContext context;
5341 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5342 Local<Script> script = Script::Compile(v8_str("obj.x"));
5343 for (int i = 0; i < 10; i++) {
5344 Local<Value> result = script->Run();
5345 CHECK_EQ(result, v8_str("x"));
5350 THREADED_TEST(NamedInterceptorDictionaryIC) {
5351 v8::HandleScope scope(v8::Isolate::GetCurrent());
5352 Local<ObjectTemplate> templ = ObjectTemplate::New();
5353 templ->SetNamedPropertyHandler(XPropertyGetter);
5354 LocalContext context;
5355 // Create an object with a named interceptor.
5356 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5357 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
5358 for (int i = 0; i < 10; i++) {
5359 Local<Value> result = script->Run();
5360 CHECK_EQ(result, v8_str("x"));
5362 // Create a slow case object and a function accessing a property in
5363 // that slow case object (with dictionary probing in generated
5364 // code). Then force object with a named interceptor into slow-case,
5365 // pass it to the function, and check that the interceptor is called
5366 // instead of accessing the local property.
5367 Local<Value> result =
5368 CompileRun("function get_x(o) { return o.x; };"
5369 "var obj = { x : 42, y : 0 };"
5371 "for (var i = 0; i < 10; i++) get_x(obj);"
5372 "interceptor_obj.x = 42;"
5373 "interceptor_obj.y = 10;"
5374 "delete interceptor_obj.y;"
5375 "get_x(interceptor_obj)");
5376 CHECK_EQ(result, v8_str("x"));
5380 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5381 v8::Isolate* isolate = v8::Isolate::GetCurrent();
5382 v8::HandleScope scope(isolate);
5383 v8::Local<Context> context1 = Context::New(isolate);
5386 Local<ObjectTemplate> templ = ObjectTemplate::New();
5387 templ->SetNamedPropertyHandler(XPropertyGetter);
5388 // Create an object with a named interceptor.
5389 v8::Local<v8::Object> object = templ->NewInstance();
5390 context1->Global()->Set(v8_str("interceptor_obj"), object);
5392 // Force the object into the slow case.
5393 CompileRun("interceptor_obj.y = 0;"
5394 "delete interceptor_obj.y;");
5398 // Introduce the object into a different context.
5399 // Repeat named loads to exercise ICs.
5400 LocalContext context2;
5401 context2->Global()->Set(v8_str("interceptor_obj"), object);
5402 Local<Value> result =
5403 CompileRun("function get_x(o) { return o.x; }"
5404 "interceptor_obj.x = 42;"
5405 "for (var i=0; i != 10; i++) {"
5406 " get_x(interceptor_obj);"
5408 "get_x(interceptor_obj)");
5409 // Check that the interceptor was actually invoked.
5410 CHECK_EQ(result, v8_str("x"));
5413 // Return to the original context and force some object to the slow case
5414 // to cause the NormalizedMapCache to verify.
5416 CompileRun("var obj = { x : 0 }; delete obj.x;");
5421 static void SetXOnPrototypeGetter(
5422 Local<String> property,
5423 const v8::PropertyCallbackInfo<v8::Value>& info) {
5424 // Set x on the prototype object and do not handle the get request.
5425 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5426 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
5430 // This is a regression test for http://crbug.com/20104. Map
5431 // transitions should not interfere with post interceptor lookup.
5432 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5433 v8::HandleScope scope(v8::Isolate::GetCurrent());
5434 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
5435 Local<v8::ObjectTemplate> instance_template
5436 = function_template->InstanceTemplate();
5437 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5438 LocalContext context;
5439 context->Global()->Set(v8_str("F"), function_template->GetFunction());
5440 // Create an instance of F and introduce a map transition for x.
5441 CompileRun("var o = new F(); o.x = 23;");
5442 // Create an instance of F and invoke the getter. The result should be 23.
5443 Local<Value> result = CompileRun("o = new F(); o.x");
5444 CHECK_EQ(result->Int32Value(), 23);
5448 static void IndexedPropertyGetter(
5450 const v8::PropertyCallbackInfo<v8::Value>& info) {
5451 ApiTestFuzzer::Fuzz();
5453 info.GetReturnValue().Set(v8_num(625));
5458 static void IndexedPropertySetter(
5461 const v8::PropertyCallbackInfo<v8::Value>& info) {
5462 ApiTestFuzzer::Fuzz();
5464 info.GetReturnValue().Set(value);
5469 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5470 v8::HandleScope scope(v8::Isolate::GetCurrent());
5471 Local<ObjectTemplate> templ = ObjectTemplate::New();
5472 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5473 IndexedPropertySetter);
5474 LocalContext context;
5475 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5476 Local<Script> getter_script = Script::Compile(v8_str(
5477 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
5478 Local<Script> setter_script = Script::Compile(v8_str(
5479 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5482 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
5483 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5485 "obj.foo;")); // This setter should not run, due to the interceptor.
5486 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
5488 Local<Value> result = getter_script->Run();
5489 CHECK_EQ(v8_num(5), result);
5490 result = setter_script->Run();
5491 CHECK_EQ(v8_num(23), result);
5492 result = interceptor_setter_script->Run();
5493 CHECK_EQ(v8_num(23), result);
5494 result = interceptor_getter_script->Run();
5495 CHECK_EQ(v8_num(625), result);
5499 static void UnboxedDoubleIndexedPropertyGetter(
5501 const v8::PropertyCallbackInfo<v8::Value>& info) {
5502 ApiTestFuzzer::Fuzz();
5504 info.GetReturnValue().Set(v8_num(index));
5509 static void UnboxedDoubleIndexedPropertySetter(
5512 const v8::PropertyCallbackInfo<v8::Value>& info) {
5513 ApiTestFuzzer::Fuzz();
5515 info.GetReturnValue().Set(v8_num(index));
5520 void UnboxedDoubleIndexedPropertyEnumerator(
5521 const v8::PropertyCallbackInfo<v8::Array>& info) {
5522 // Force the list of returned keys to be stored in a FastDoubleArray.
5523 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5524 "keys = new Array(); keys[125000] = 1;"
5525 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5526 "keys.length = 25; keys;"));
5527 Local<Value> result = indexed_property_names_script->Run();
5528 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5532 // Make sure that the the interceptor code in the runtime properly handles
5533 // merging property name lists for double-array-backed arrays.
5534 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5535 v8::HandleScope scope(v8::Isolate::GetCurrent());
5536 Local<ObjectTemplate> templ = ObjectTemplate::New();
5537 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5538 UnboxedDoubleIndexedPropertySetter,
5541 UnboxedDoubleIndexedPropertyEnumerator);
5542 LocalContext context;
5543 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5544 // When obj is created, force it to be Stored in a FastDoubleArray.
5545 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
5546 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
5548 "for (x in obj) {key_count++;};"
5550 Local<Value> result = create_unboxed_double_script->Run();
5551 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
5552 Local<Script> key_count_check = Script::Compile(v8_str(
5554 result = key_count_check->Run();
5555 CHECK_EQ(v8_num(40013), result);
5559 void NonStrictArgsIndexedPropertyEnumerator(
5560 const v8::PropertyCallbackInfo<v8::Array>& info) {
5561 // Force the list of returned keys to be stored in a Arguments object.
5562 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5564 " return arguments;"
5566 "keys = f(0, 1, 2, 3);"
5568 Local<Object> result =
5569 Local<Object>::Cast(indexed_property_names_script->Run());
5570 // Have to populate the handle manually, as it's not Cast-able.
5571 i::Handle<i::JSObject> o =
5572 v8::Utils::OpenHandle<Object, i::JSObject>(result);
5573 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
5574 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
5578 static void NonStrictIndexedPropertyGetter(
5580 const v8::PropertyCallbackInfo<v8::Value>& info) {
5581 ApiTestFuzzer::Fuzz();
5583 info.GetReturnValue().Set(v8_num(index));
5588 // Make sure that the the interceptor code in the runtime properly handles
5589 // merging property name lists for non-string arguments arrays.
5590 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
5591 v8::HandleScope scope(v8::Isolate::GetCurrent());
5592 Local<ObjectTemplate> templ = ObjectTemplate::New();
5593 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
5597 NonStrictArgsIndexedPropertyEnumerator);
5598 LocalContext context;
5599 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5600 Local<Script> create_args_script =
5601 Script::Compile(v8_str(
5602 "var key_count = 0;"
5603 "for (x in obj) {key_count++;} key_count;"));
5604 Local<Value> result = create_args_script->Run();
5605 CHECK_EQ(v8_num(4), result);
5609 static void IdentityIndexedPropertyGetter(
5611 const v8::PropertyCallbackInfo<v8::Value>& info) {
5612 info.GetReturnValue().Set(index);
5616 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
5617 v8::HandleScope scope(v8::Isolate::GetCurrent());
5618 Local<ObjectTemplate> templ = ObjectTemplate::New();
5619 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5621 LocalContext context;
5622 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5624 // Check fast object case.
5625 const char* fast_case_code =
5626 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
5627 ExpectString(fast_case_code, "0");
5630 const char* slow_case_code =
5631 "obj.x = 1; delete obj.x;"
5632 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
5633 ExpectString(slow_case_code, "1");
5637 THREADED_TEST(IndexedInterceptorWithNoSetter) {
5638 v8::HandleScope scope(v8::Isolate::GetCurrent());
5639 Local<ObjectTemplate> templ = ObjectTemplate::New();
5640 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5642 LocalContext context;
5643 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5648 " for (var i = 0; i < 100; i++) {"
5650 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
5656 ExpectString(code, "PASSED");
5660 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
5661 v8::HandleScope scope(v8::Isolate::GetCurrent());
5662 Local<ObjectTemplate> templ = ObjectTemplate::New();
5663 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5665 LocalContext context;
5666 Local<v8::Object> obj = templ->NewInstance();
5667 obj->TurnOnAccessCheck();
5668 context->Global()->Set(v8_str("obj"), obj);
5672 " for (var i = 0; i < 100; i++) {"
5674 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
5680 ExpectString(code, "PASSED");
5684 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
5685 i::FLAG_allow_natives_syntax = true;
5686 v8::HandleScope scope(v8::Isolate::GetCurrent());
5687 Local<ObjectTemplate> templ = ObjectTemplate::New();
5688 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5690 LocalContext context;
5691 Local<v8::Object> obj = templ->NewInstance();
5692 context->Global()->Set(v8_str("obj"), obj);
5696 " for (var i = 0; i < 100; i++) {"
5697 " var expected = i;"
5699 " %EnableAccessChecks(obj);"
5700 " expected = undefined;"
5703 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5704 " if (i == 5) %DisableAccessChecks(obj);"
5710 ExpectString(code, "PASSED");
5714 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
5715 v8::HandleScope scope(v8::Isolate::GetCurrent());
5716 Local<ObjectTemplate> templ = ObjectTemplate::New();
5717 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5719 LocalContext context;
5720 Local<v8::Object> obj = templ->NewInstance();
5721 context->Global()->Set(v8_str("obj"), obj);
5725 " for (var i = 0; i < 100; i++) {"
5727 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
5733 ExpectString(code, "PASSED");
5737 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
5738 v8::HandleScope scope(v8::Isolate::GetCurrent());
5739 Local<ObjectTemplate> templ = ObjectTemplate::New();
5740 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5742 LocalContext context;
5743 Local<v8::Object> obj = templ->NewInstance();
5744 context->Global()->Set(v8_str("obj"), obj);
5748 " for (var i = 0; i < 100; i++) {"
5749 " var expected = i;"
5753 " expected = undefined;"
5756 " /* probe minimal Smi number on 32-bit platforms */"
5757 " key = -(1 << 30);"
5758 " expected = undefined;"
5761 " /* probe minimal Smi number on 64-bit platforms */"
5763 " expected = undefined;"
5765 " var v = obj[key];"
5766 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5772 ExpectString(code, "PASSED");
5776 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
5777 v8::HandleScope scope(v8::Isolate::GetCurrent());
5778 Local<ObjectTemplate> templ = ObjectTemplate::New();
5779 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5781 LocalContext context;
5782 Local<v8::Object> obj = templ->NewInstance();
5783 context->Global()->Set(v8_str("obj"), obj);
5787 " for (var i = 0; i < 100; i++) {"
5788 " var expected = i;"
5792 " expected = undefined;"
5794 " var v = obj[key];"
5795 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5801 ExpectString(code, "PASSED");
5805 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
5806 v8::HandleScope scope(v8::Isolate::GetCurrent());
5807 Local<ObjectTemplate> templ = ObjectTemplate::New();
5808 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5810 LocalContext context;
5811 Local<v8::Object> obj = templ->NewInstance();
5812 context->Global()->Set(v8_str("obj"), obj);
5815 "var original = obj;"
5817 " for (var i = 0; i < 100; i++) {"
5818 " var expected = i;"
5820 " obj = {50: 'foobar'};"
5821 " expected = 'foobar';"
5824 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5825 " if (i == 50) obj = original;"
5831 ExpectString(code, "PASSED");
5835 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
5836 v8::HandleScope scope(v8::Isolate::GetCurrent());
5837 Local<ObjectTemplate> templ = ObjectTemplate::New();
5838 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5840 LocalContext context;
5841 Local<v8::Object> obj = templ->NewInstance();
5842 context->Global()->Set(v8_str("obj"), obj);
5845 "var original = obj;"
5847 " for (var i = 0; i < 100; i++) {"
5848 " var expected = i;"
5851 " expected = undefined;"
5854 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5855 " if (i == 5) obj = original;"
5861 ExpectString(code, "PASSED");
5865 THREADED_TEST(IndexedInterceptorOnProto) {
5866 v8::HandleScope scope(v8::Isolate::GetCurrent());
5867 Local<ObjectTemplate> templ = ObjectTemplate::New();
5868 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5870 LocalContext context;
5871 Local<v8::Object> obj = templ->NewInstance();
5872 context->Global()->Set(v8_str("obj"), obj);
5875 "var o = {__proto__: obj};"
5877 " for (var i = 0; i < 100; i++) {"
5879 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
5885 ExpectString(code, "PASSED");
5889 THREADED_TEST(MultiContexts) {
5890 v8::HandleScope scope(v8::Isolate::GetCurrent());
5891 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
5892 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
5894 Local<String> password = v8_str("Password");
5896 // Create an environment
5897 LocalContext context0(0, templ);
5898 context0->SetSecurityToken(password);
5899 v8::Handle<v8::Object> global0 = context0->Global();
5900 global0->Set(v8_str("custom"), v8_num(1234));
5901 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5903 // Create an independent environment
5904 LocalContext context1(0, templ);
5905 context1->SetSecurityToken(password);
5906 v8::Handle<v8::Object> global1 = context1->Global();
5907 global1->Set(v8_str("custom"), v8_num(1234));
5908 CHECK_NE(global0, global1);
5909 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5910 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
5912 // Now create a new context with the old global
5913 LocalContext context2(0, templ, global1);
5914 context2->SetSecurityToken(password);
5915 v8::Handle<v8::Object> global2 = context2->Global();
5916 CHECK_EQ(global1, global2);
5917 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
5918 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
5922 THREADED_TEST(FunctionPrototypeAcrossContexts) {
5923 // Make sure that functions created by cloning boilerplates cannot
5924 // communicate through their __proto__ field.
5926 v8::HandleScope scope(v8::Isolate::GetCurrent());
5929 v8::Handle<v8::Object> global0 =
5931 v8::Handle<v8::Object> object0 =
5932 global0->Get(v8_str("Object")).As<v8::Object>();
5933 v8::Handle<v8::Object> tostring0 =
5934 object0->Get(v8_str("toString")).As<v8::Object>();
5935 v8::Handle<v8::Object> proto0 =
5936 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
5937 proto0->Set(v8_str("custom"), v8_num(1234));
5940 v8::Handle<v8::Object> global1 =
5942 v8::Handle<v8::Object> object1 =
5943 global1->Get(v8_str("Object")).As<v8::Object>();
5944 v8::Handle<v8::Object> tostring1 =
5945 object1->Get(v8_str("toString")).As<v8::Object>();
5946 v8::Handle<v8::Object> proto1 =
5947 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
5948 CHECK(!proto1->Has(v8_str("custom")));
5952 THREADED_TEST(Regress892105) {
5953 // Make sure that object and array literals created by cloning
5954 // boilerplates cannot communicate through their __proto__
5955 // field. This is rather difficult to check, but we try to add stuff
5956 // to Object.prototype and Array.prototype and create a new
5957 // environment. This should succeed.
5959 v8::HandleScope scope(v8::Isolate::GetCurrent());
5961 Local<String> source = v8_str("Object.prototype.obj = 1234;"
5962 "Array.prototype.arr = 4567;"
5966 Local<Script> script0 = Script::Compile(source);
5967 CHECK_EQ(8901.0, script0->Run()->NumberValue());
5970 Local<Script> script1 = Script::Compile(source);
5971 CHECK_EQ(8901.0, script1->Run()->NumberValue());
5975 THREADED_TEST(UndetectableObject) {
5977 v8::HandleScope scope(env->GetIsolate());
5979 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
5980 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5982 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5983 env->Global()->Set(v8_str("undetectable"), obj);
5985 ExpectString("undetectable.toString()", "[object Object]");
5986 ExpectString("typeof undetectable", "undefined");
5987 ExpectString("typeof(undetectable)", "undefined");
5988 ExpectBoolean("typeof undetectable == 'undefined'", true);
5989 ExpectBoolean("typeof undetectable == 'object'", false);
5990 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
5991 ExpectBoolean("!undetectable", true);
5993 ExpectObject("true&&undetectable", obj);
5994 ExpectBoolean("false&&undetectable", false);
5995 ExpectBoolean("true||undetectable", true);
5996 ExpectObject("false||undetectable", obj);
5998 ExpectObject("undetectable&&true", obj);
5999 ExpectObject("undetectable&&false", obj);
6000 ExpectBoolean("undetectable||true", true);
6001 ExpectBoolean("undetectable||false", false);
6003 ExpectBoolean("undetectable==null", true);
6004 ExpectBoolean("null==undetectable", true);
6005 ExpectBoolean("undetectable==undefined", true);
6006 ExpectBoolean("undefined==undetectable", true);
6007 ExpectBoolean("undetectable==undetectable", true);
6010 ExpectBoolean("undetectable===null", false);
6011 ExpectBoolean("null===undetectable", false);
6012 ExpectBoolean("undetectable===undefined", false);
6013 ExpectBoolean("undefined===undetectable", false);
6014 ExpectBoolean("undetectable===undetectable", true);
6018 THREADED_TEST(VoidLiteral) {
6020 v8::HandleScope scope(env->GetIsolate());
6022 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
6023 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6025 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6026 env->Global()->Set(v8_str("undetectable"), obj);
6028 ExpectBoolean("undefined == void 0", true);
6029 ExpectBoolean("undetectable == void 0", true);
6030 ExpectBoolean("null == void 0", true);
6031 ExpectBoolean("undefined === void 0", true);
6032 ExpectBoolean("undetectable === void 0", false);
6033 ExpectBoolean("null === void 0", false);
6035 ExpectBoolean("void 0 == undefined", true);
6036 ExpectBoolean("void 0 == undetectable", true);
6037 ExpectBoolean("void 0 == null", true);
6038 ExpectBoolean("void 0 === undefined", true);
6039 ExpectBoolean("void 0 === undetectable", false);
6040 ExpectBoolean("void 0 === null", false);
6042 ExpectString("(function() {"
6044 " return x === void 0;"
6046 " return e.toString();"
6049 "ReferenceError: x is not defined");
6050 ExpectString("(function() {"
6052 " return void 0 === x;"
6054 " return e.toString();"
6057 "ReferenceError: x is not defined");
6061 THREADED_TEST(ExtensibleOnUndetectable) {
6063 v8::HandleScope scope(env->GetIsolate());
6065 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
6066 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6068 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6069 env->Global()->Set(v8_str("undetectable"), obj);
6071 Local<String> source = v8_str("undetectable.x = 42;"
6074 Local<Script> script = Script::Compile(source);
6076 CHECK_EQ(v8::Integer::New(42), script->Run());
6078 ExpectBoolean("Object.isExtensible(undetectable)", true);
6080 source = v8_str("Object.preventExtensions(undetectable);");
6081 script = Script::Compile(source);
6083 ExpectBoolean("Object.isExtensible(undetectable)", false);
6085 source = v8_str("undetectable.y = 2000;");
6086 script = Script::Compile(source);
6088 ExpectBoolean("undetectable.y == undefined", true);
6093 THREADED_TEST(UndetectableString) {
6095 v8::HandleScope scope(env->GetIsolate());
6097 Local<String> obj = String::NewUndetectable("foo");
6098 env->Global()->Set(v8_str("undetectable"), obj);
6100 ExpectString("undetectable", "foo");
6101 ExpectString("typeof undetectable", "undefined");
6102 ExpectString("typeof(undetectable)", "undefined");
6103 ExpectBoolean("typeof undetectable == 'undefined'", true);
6104 ExpectBoolean("typeof undetectable == 'string'", false);
6105 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6106 ExpectBoolean("!undetectable", true);
6108 ExpectObject("true&&undetectable", obj);
6109 ExpectBoolean("false&&undetectable", false);
6110 ExpectBoolean("true||undetectable", true);
6111 ExpectObject("false||undetectable", obj);
6113 ExpectObject("undetectable&&true", obj);
6114 ExpectObject("undetectable&&false", obj);
6115 ExpectBoolean("undetectable||true", true);
6116 ExpectBoolean("undetectable||false", false);
6118 ExpectBoolean("undetectable==null", true);
6119 ExpectBoolean("null==undetectable", true);
6120 ExpectBoolean("undetectable==undefined", true);
6121 ExpectBoolean("undefined==undetectable", true);
6122 ExpectBoolean("undetectable==undetectable", true);
6125 ExpectBoolean("undetectable===null", false);
6126 ExpectBoolean("null===undetectable", false);
6127 ExpectBoolean("undetectable===undefined", false);
6128 ExpectBoolean("undefined===undetectable", false);
6129 ExpectBoolean("undetectable===undetectable", true);
6133 TEST(UndetectableOptimized) {
6134 i::FLAG_allow_natives_syntax = true;
6136 v8::HandleScope scope(env->GetIsolate());
6138 Local<String> obj = String::NewUndetectable("foo");
6139 env->Global()->Set(v8_str("undetectable"), obj);
6140 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6143 "function testBranch() {"
6144 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6145 " if (%_IsUndetectableObject(detectable)) throw 2;"
6147 "function testBool() {"
6148 " var b1 = !%_IsUndetectableObject(undetectable);"
6149 " var b2 = %_IsUndetectableObject(detectable);"
6154 "%OptimizeFunctionOnNextCall(testBranch);"
6155 "%OptimizeFunctionOnNextCall(testBool);"
6156 "for (var i = 0; i < 10; i++) {"
6165 template <typename T> static void USE(T) { }
6168 // This test is not intended to be run, just type checked.
6169 static inline void PersistentHandles(v8::Isolate* isolate) {
6170 USE(PersistentHandles);
6171 Local<String> str = v8_str("foo");
6172 v8::Persistent<String> p_str(isolate, str);
6174 Local<Script> scr = Script::Compile(v8_str(""));
6175 v8::Persistent<Script> p_scr(isolate, scr);
6177 Local<ObjectTemplate> templ = ObjectTemplate::New();
6178 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6183 static void HandleLogDelegator(
6184 const v8::FunctionCallbackInfo<v8::Value>& args) {
6185 ApiTestFuzzer::Fuzz();
6189 THREADED_TEST(GlobalObjectTemplate) {
6190 v8::Isolate* isolate = v8::Isolate::GetCurrent();
6191 v8::HandleScope handle_scope(isolate);
6192 Local<ObjectTemplate> global_template = ObjectTemplate::New();
6193 global_template->Set(v8_str("JSNI_Log"),
6194 v8::FunctionTemplate::New(HandleLogDelegator));
6195 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6196 Context::Scope context_scope(context);
6197 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
6201 static const char* kSimpleExtensionSource =
6207 THREADED_TEST(SimpleExtensions) {
6208 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6209 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6210 const char* extension_names[] = { "simpletest" };
6211 v8::ExtensionConfiguration extensions(1, extension_names);
6212 v8::Handle<Context> context =
6213 Context::New(v8::Isolate::GetCurrent(), &extensions);
6214 Context::Scope lock(context);
6215 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6216 CHECK_EQ(result, v8::Integer::New(4));
6220 THREADED_TEST(NullExtensions) {
6221 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6222 v8::RegisterExtension(new Extension("nulltest", NULL));
6223 const char* extension_names[] = { "nulltest" };
6224 v8::ExtensionConfiguration extensions(1, extension_names);
6225 v8::Handle<Context> context =
6226 Context::New(v8::Isolate::GetCurrent(), &extensions);
6227 Context::Scope lock(context);
6228 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
6229 CHECK_EQ(result, v8::Integer::New(4));
6233 static const char* kEmbeddedExtensionSource =
6234 "function Ret54321(){return 54321;}~~@@$"
6235 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6236 static const int kEmbeddedExtensionSourceValidLen = 34;
6239 THREADED_TEST(ExtensionMissingSourceLength) {
6240 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6241 v8::RegisterExtension(new Extension("srclentest_fail",
6242 kEmbeddedExtensionSource));
6243 const char* extension_names[] = { "srclentest_fail" };
6244 v8::ExtensionConfiguration extensions(1, extension_names);
6245 v8::Handle<Context> context =
6246 Context::New(v8::Isolate::GetCurrent(), &extensions);
6247 CHECK_EQ(0, *context);
6251 THREADED_TEST(ExtensionWithSourceLength) {
6252 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6253 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6254 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6255 i::ScopedVector<char> extension_name(32);
6256 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6257 v8::RegisterExtension(new Extension(extension_name.start(),
6258 kEmbeddedExtensionSource, 0, 0,
6260 const char* extension_names[1] = { extension_name.start() };
6261 v8::ExtensionConfiguration extensions(1, extension_names);
6262 v8::Handle<Context> context =
6263 Context::New(v8::Isolate::GetCurrent(), &extensions);
6264 if (source_len == kEmbeddedExtensionSourceValidLen) {
6265 Context::Scope lock(context);
6266 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
6267 CHECK_EQ(v8::Integer::New(54321), result);
6269 // Anything but exactly the right length should fail to compile.
6270 CHECK_EQ(0, *context);
6276 static const char* kEvalExtensionSource1 =
6277 "function UseEval1() {"
6279 " return eval('x');"
6283 static const char* kEvalExtensionSource2 =
6287 " return eval('x');"
6289 " this.UseEval2 = e;"
6293 THREADED_TEST(UseEvalFromExtension) {
6294 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6295 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6296 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6297 const char* extension_names[] = { "evaltest1", "evaltest2" };
6298 v8::ExtensionConfiguration extensions(2, extension_names);
6299 v8::Handle<Context> context =
6300 Context::New(v8::Isolate::GetCurrent(), &extensions);
6301 Context::Scope lock(context);
6302 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
6303 CHECK_EQ(result, v8::Integer::New(42));
6304 result = Script::Compile(v8_str("UseEval2()"))->Run();
6305 CHECK_EQ(result, v8::Integer::New(42));
6309 static const char* kWithExtensionSource1 =
6310 "function UseWith1() {"
6312 " with({x:87}) { return x; }"
6317 static const char* kWithExtensionSource2 =
6321 " with ({x:87}) { return x; }"
6323 " this.UseWith2 = e;"
6327 THREADED_TEST(UseWithFromExtension) {
6328 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6329 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6330 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6331 const char* extension_names[] = { "withtest1", "withtest2" };
6332 v8::ExtensionConfiguration extensions(2, extension_names);
6333 v8::Handle<Context> context =
6334 Context::New(v8::Isolate::GetCurrent(), &extensions);
6335 Context::Scope lock(context);
6336 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
6337 CHECK_EQ(result, v8::Integer::New(87));
6338 result = Script::Compile(v8_str("UseWith2()"))->Run();
6339 CHECK_EQ(result, v8::Integer::New(87));
6343 THREADED_TEST(AutoExtensions) {
6344 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6345 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6346 extension->set_auto_enable(true);
6347 v8::RegisterExtension(extension);
6348 v8::Handle<Context> context =
6349 Context::New(v8::Isolate::GetCurrent());
6350 Context::Scope lock(context);
6351 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6352 CHECK_EQ(result, v8::Integer::New(4));
6356 static const char* kSyntaxErrorInExtensionSource =
6360 // Test that a syntax error in an extension does not cause a fatal
6361 // error but results in an empty context.
6362 THREADED_TEST(SyntaxErrorExtensions) {
6363 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6364 v8::RegisterExtension(new Extension("syntaxerror",
6365 kSyntaxErrorInExtensionSource));
6366 const char* extension_names[] = { "syntaxerror" };
6367 v8::ExtensionConfiguration extensions(1, extension_names);
6368 v8::Handle<Context> context =
6369 Context::New(v8::Isolate::GetCurrent(), &extensions);
6370 CHECK(context.IsEmpty());
6374 static const char* kExceptionInExtensionSource =
6378 // Test that an exception when installing an extension does not cause
6379 // a fatal error but results in an empty context.
6380 THREADED_TEST(ExceptionExtensions) {
6381 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6382 v8::RegisterExtension(new Extension("exception",
6383 kExceptionInExtensionSource));
6384 const char* extension_names[] = { "exception" };
6385 v8::ExtensionConfiguration extensions(1, extension_names);
6386 v8::Handle<Context> context =
6387 Context::New(v8::Isolate::GetCurrent(), &extensions);
6388 CHECK(context.IsEmpty());
6392 static const char* kNativeCallInExtensionSource =
6393 "function call_runtime_last_index_of(x) {"
6394 " return %StringLastIndexOf(x, 'bob', 10);"
6398 static const char* kNativeCallTest =
6399 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6401 // Test that a native runtime calls are supported in extensions.
6402 THREADED_TEST(NativeCallInExtensions) {
6403 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6404 v8::RegisterExtension(new Extension("nativecall",
6405 kNativeCallInExtensionSource));
6406 const char* extension_names[] = { "nativecall" };
6407 v8::ExtensionConfiguration extensions(1, extension_names);
6408 v8::Handle<Context> context =
6409 Context::New(v8::Isolate::GetCurrent(), &extensions);
6410 Context::Scope lock(context);
6411 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
6412 CHECK_EQ(result, v8::Integer::New(3));
6416 class NativeFunctionExtension : public Extension {
6418 NativeFunctionExtension(const char* name,
6420 v8::FunctionCallback fun = &Echo)
6421 : Extension(name, source),
6424 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
6425 v8::Handle<v8::String> name) {
6426 return v8::FunctionTemplate::New(function_);
6429 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6430 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6433 v8::FunctionCallback function_;
6437 THREADED_TEST(NativeFunctionDeclaration) {
6438 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6439 const char* name = "nativedecl";
6440 v8::RegisterExtension(new NativeFunctionExtension(name,
6441 "native function foo();"));
6442 const char* extension_names[] = { name };
6443 v8::ExtensionConfiguration extensions(1, extension_names);
6444 v8::Handle<Context> context =
6445 Context::New(v8::Isolate::GetCurrent(), &extensions);
6446 Context::Scope lock(context);
6447 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
6448 CHECK_EQ(result, v8::Integer::New(42));
6452 THREADED_TEST(NativeFunctionDeclarationError) {
6453 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6454 const char* name = "nativedeclerr";
6455 // Syntax error in extension code.
6456 v8::RegisterExtension(new NativeFunctionExtension(name,
6457 "native\nfunction foo();"));
6458 const char* extension_names[] = { name };
6459 v8::ExtensionConfiguration extensions(1, extension_names);
6460 v8::Handle<Context> context =
6461 Context::New(v8::Isolate::GetCurrent(), &extensions);
6462 CHECK(context.IsEmpty());
6466 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
6467 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6468 const char* name = "nativedeclerresc";
6469 // Syntax error in extension code - escape code in "native" means that
6470 // it's not treated as a keyword.
6471 v8::RegisterExtension(new NativeFunctionExtension(
6473 "nativ\\u0065 function foo();"));
6474 const char* extension_names[] = { name };
6475 v8::ExtensionConfiguration extensions(1, extension_names);
6476 v8::Handle<Context> context =
6477 Context::New(v8::Isolate::GetCurrent(), &extensions);
6478 CHECK(context.IsEmpty());
6482 static void CheckDependencies(const char* name, const char* expected) {
6483 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6484 v8::ExtensionConfiguration config(1, &name);
6485 LocalContext context(&config);
6486 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
6497 THREADED_TEST(ExtensionDependency) {
6498 static const char* kEDeps[] = { "D" };
6499 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6500 static const char* kDDeps[] = { "B", "C" };
6501 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6502 static const char* kBCDeps[] = { "A" };
6503 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6504 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6505 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6506 CheckDependencies("A", "undefinedA");
6507 CheckDependencies("B", "undefinedAB");
6508 CheckDependencies("C", "undefinedAC");
6509 CheckDependencies("D", "undefinedABCD");
6510 CheckDependencies("E", "undefinedABCDE");
6511 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6512 static const char* exts[2] = { "C", "E" };
6513 v8::ExtensionConfiguration config(2, exts);
6514 LocalContext context(&config);
6515 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6519 static const char* kExtensionTestScript =
6520 "native function A();"
6521 "native function B();"
6522 "native function C();"
6524 " if (i == 0) return A();"
6525 " if (i == 1) return B();"
6526 " if (i == 2) return C();"
6530 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6531 ApiTestFuzzer::Fuzz();
6532 if (args.IsConstructCall()) {
6533 args.This()->Set(v8_str("data"), args.Data());
6534 args.GetReturnValue().SetNull();
6537 args.GetReturnValue().Set(args.Data());
6541 class FunctionExtension : public Extension {
6543 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
6544 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
6545 v8::Handle<String> name);
6549 static int lookup_count = 0;
6550 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
6551 v8::Handle<String> name) {
6553 if (name->Equals(v8_str("A"))) {
6554 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
6555 } else if (name->Equals(v8_str("B"))) {
6556 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
6557 } else if (name->Equals(v8_str("C"))) {
6558 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
6560 return v8::Handle<v8::FunctionTemplate>();
6565 THREADED_TEST(FunctionLookup) {
6566 v8::RegisterExtension(new FunctionExtension());
6567 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6568 static const char* exts[1] = { "functiontest" };
6569 v8::ExtensionConfiguration config(1, exts);
6570 LocalContext context(&config);
6571 CHECK_EQ(3, lookup_count);
6572 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
6573 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
6574 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
6578 THREADED_TEST(NativeFunctionConstructCall) {
6579 v8::RegisterExtension(new FunctionExtension());
6580 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6581 static const char* exts[1] = { "functiontest" };
6582 v8::ExtensionConfiguration config(1, exts);
6583 LocalContext context(&config);
6584 for (int i = 0; i < 10; i++) {
6585 // Run a few times to ensure that allocation of objects doesn't
6586 // change behavior of a constructor function.
6587 CHECK_EQ(v8::Integer::New(8),
6588 Script::Compile(v8_str("(new A()).data"))->Run());
6589 CHECK_EQ(v8::Integer::New(7),
6590 Script::Compile(v8_str("(new B()).data"))->Run());
6591 CHECK_EQ(v8::Integer::New(6),
6592 Script::Compile(v8_str("(new C()).data"))->Run());
6597 static const char* last_location;
6598 static const char* last_message;
6599 void StoringErrorCallback(const char* location, const char* message) {
6600 if (last_location == NULL) {
6601 last_location = location;
6602 last_message = message;
6607 // ErrorReporting creates a circular extensions configuration and
6608 // tests that the fatal error handler gets called. This renders V8
6609 // unusable and therefore this test cannot be run in parallel.
6610 TEST(ErrorReporting) {
6611 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
6612 static const char* aDeps[] = { "B" };
6613 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
6614 static const char* bDeps[] = { "A" };
6615 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
6616 last_location = NULL;
6617 v8::ExtensionConfiguration config(1, bDeps);
6618 v8::Handle<Context> context =
6619 Context::New(v8::Isolate::GetCurrent(), &config);
6620 CHECK(context.IsEmpty());
6621 CHECK_NE(last_location, NULL);
6625 static const char* js_code_causing_huge_string_flattening =
6627 "for (var i = 0; i < 30; i++) {"
6633 void OOMCallback(const char* location, const char* message) {
6638 TEST(RegexpOutOfMemory) {
6639 // Execute a script that causes out of memory when flattening a string.
6640 v8::HandleScope scope(v8::Isolate::GetCurrent());
6641 v8::V8::SetFatalErrorHandler(OOMCallback);
6642 LocalContext context;
6643 Local<Script> script =
6644 Script::Compile(String::New(js_code_causing_huge_string_flattening));
6645 last_location = NULL;
6648 CHECK(false); // Should not return.
6652 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
6653 v8::Handle<Value> data) {
6654 CHECK(message->GetScriptResourceName()->IsUndefined());
6655 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
6656 message->GetLineNumber();
6657 message->GetSourceLine();
6661 THREADED_TEST(ErrorWithMissingScriptInfo) {
6662 LocalContext context;
6663 v8::HandleScope scope(context->GetIsolate());
6664 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
6665 Script::Compile(v8_str("throw Error()"))->Run();
6666 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
6670 int global_index = 0;
6674 Snorkel() { index_ = global_index++; }
6680 explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { }
6681 ~Whammy() { script_.Dispose(); }
6682 v8::Handle<Script> getScript() {
6683 if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo"));
6684 return Local<Script>::New(isolate_, script_);
6688 static const int kObjectCount = 256;
6690 v8::Isolate* isolate_;
6691 v8::Persistent<v8::Object> objects_[kObjectCount];
6692 v8::Persistent<Script> script_;
6695 static void HandleWeakReference(v8::Isolate* isolate,
6696 v8::Persistent<v8::Value>* obj,
6702 void WhammyPropertyGetter(Local<String> name,
6703 const v8::PropertyCallbackInfo<v8::Value>& info) {
6705 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
6707 v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_];
6709 v8::Handle<v8::Object> obj = v8::Object::New();
6710 if (!prev.IsEmpty()) {
6711 v8::Local<v8::Object>::New(info.GetIsolate(), prev)
6712 ->Set(v8_str("next"), obj);
6713 prev.MakeWeak<Value, Snorkel>(new Snorkel(), &HandleWeakReference);
6714 whammy->objects_[whammy->cursor_].Clear();
6716 whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj);
6717 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
6718 info.GetReturnValue().Set(whammy->getScript()->Run());
6722 THREADED_TEST(WeakReference) {
6723 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6724 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
6725 Whammy* whammy = new Whammy(v8::Isolate::GetCurrent());
6726 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
6728 v8::External::New(whammy));
6729 const char* extension_list[] = { "v8/gc" };
6730 v8::ExtensionConfiguration extensions(1, extension_list);
6731 v8::Handle<Context> context =
6732 Context::New(v8::Isolate::GetCurrent(), &extensions);
6733 Context::Scope context_scope(context);
6735 v8::Handle<v8::Object> interceptor = templ->NewInstance();
6736 context->Global()->Set(v8_str("whammy"), interceptor);
6739 "for (var i = 0; i < 10000; i++) {"
6740 " var obj = whammy.length;"
6741 " if (last) last.next = obj;"
6746 v8::Handle<Value> result = CompileRun(code);
6747 CHECK_EQ(4.0, result->NumberValue());
6752 static void DisposeAndSetFlag(v8::Isolate* isolate,
6753 v8::Persistent<v8::Object>* obj,
6760 THREADED_TEST(IndependentWeakHandle) {
6761 v8::Isolate* iso = v8::Isolate::GetCurrent();
6762 v8::HandleScope scope(iso);
6763 v8::Handle<Context> context = Context::New(iso);
6764 Context::Scope context_scope(context);
6766 v8::Persistent<v8::Object> object_a, object_b;
6769 v8::HandleScope handle_scope(iso);
6770 object_a.Reset(iso, v8::Object::New());
6771 object_b.Reset(iso, v8::Object::New());
6774 bool object_a_disposed = false;
6775 bool object_b_disposed = false;
6776 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
6777 object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag);
6778 CHECK(!object_b.IsIndependent());
6779 object_a.MarkIndependent();
6780 object_b.MarkIndependent();
6781 CHECK(object_b.IsIndependent());
6782 HEAP->PerformScavenge();
6783 CHECK(object_a_disposed);
6784 CHECK(object_b_disposed);
6788 static void InvokeScavenge() {
6789 HEAP->PerformScavenge();
6793 static void InvokeMarkSweep() {
6794 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
6798 static void ForceScavenge(v8::Isolate* isolate,
6799 v8::Persistent<v8::Object>* obj,
6807 static void ForceMarkSweep(v8::Isolate* isolate,
6808 v8::Persistent<v8::Object>* obj,
6816 THREADED_TEST(GCFromWeakCallbacks) {
6817 v8::Isolate* isolate = v8::Isolate::GetCurrent();
6818 v8::HandleScope scope(isolate);
6819 v8::Handle<Context> context = Context::New(isolate);
6820 Context::Scope context_scope(context);
6822 static const int kNumberOfGCTypes = 2;
6823 typedef v8::WeakReferenceCallbacks<v8::Object, bool>::Revivable Callback;
6824 Callback gc_forcing_callback[kNumberOfGCTypes] =
6825 {&ForceScavenge, &ForceMarkSweep};
6827 typedef void (*GCInvoker)();
6828 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
6830 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
6831 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
6832 v8::Persistent<v8::Object> object;
6834 v8::HandleScope handle_scope(isolate);
6835 object.Reset(isolate, v8::Object::New());
6837 bool disposed = false;
6838 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
6839 object.MarkIndependent();
6840 invoke_gc[outer_gc]();
6847 static void RevivingCallback(v8::Isolate* isolate,
6848 v8::Persistent<v8::Object>* obj,
6855 THREADED_TEST(IndependentHandleRevival) {
6856 v8::Isolate* isolate = v8::Isolate::GetCurrent();
6857 v8::HandleScope scope(isolate);
6858 v8::Handle<Context> context = Context::New(isolate);
6859 Context::Scope context_scope(context);
6861 v8::Persistent<v8::Object> object;
6863 v8::HandleScope handle_scope(isolate);
6864 v8::Local<v8::Object> o = v8::Object::New();
6865 object.Reset(isolate, o);
6866 o->Set(v8_str("x"), v8::Integer::New(1));
6867 v8::Local<String> y_str = v8_str("y");
6868 o->Set(y_str, y_str);
6870 bool revived = false;
6871 object.MakeWeak(&revived, &RevivingCallback);
6872 object.MarkIndependent();
6873 HEAP->PerformScavenge();
6875 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
6877 v8::HandleScope handle_scope(isolate);
6878 v8::Local<v8::Object> o = v8::Local<v8::Object>::New(isolate, object);
6879 v8::Local<String> y_str = v8_str("y");
6880 CHECK_EQ(v8::Integer::New(1), o->Get(v8_str("x")));
6881 CHECK(o->Get(y_str)->Equals(y_str));
6886 v8::Handle<Function> args_fun;
6889 static void ArgumentsTestCallback(
6890 const v8::FunctionCallbackInfo<v8::Value>& args) {
6891 ApiTestFuzzer::Fuzz();
6892 CHECK_EQ(args_fun, args.Callee());
6893 CHECK_EQ(3, args.Length());
6894 CHECK_EQ(v8::Integer::New(1), args[0]);
6895 CHECK_EQ(v8::Integer::New(2), args[1]);
6896 CHECK_EQ(v8::Integer::New(3), args[2]);
6897 CHECK_EQ(v8::Undefined(), args[3]);
6898 v8::HandleScope scope(args.GetIsolate());
6899 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
6903 THREADED_TEST(Arguments) {
6904 v8::HandleScope scope(v8::Isolate::GetCurrent());
6905 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
6906 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
6907 LocalContext context(NULL, global);
6908 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
6909 v8_compile("f(1, 2, 3)")->Run();
6913 static void NoBlockGetterX(Local<String> name,
6914 const v8::PropertyCallbackInfo<v8::Value>&) {
6918 static void NoBlockGetterI(uint32_t index,
6919 const v8::PropertyCallbackInfo<v8::Value>&) {
6923 static void PDeleter(Local<String> name,
6924 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
6925 if (!name->Equals(v8_str("foo"))) {
6926 return; // not intercepted
6929 info.GetReturnValue().Set(false); // intercepted, don't delete the property
6933 static void IDeleter(uint32_t index,
6934 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
6936 return; // not intercepted
6939 info.GetReturnValue().Set(false); // intercepted, don't delete the property
6943 THREADED_TEST(Deleter) {
6944 v8::HandleScope scope(v8::Isolate::GetCurrent());
6945 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6946 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
6947 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
6948 LocalContext context;
6949 context->Global()->Set(v8_str("k"), obj->NewInstance());
6955 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
6956 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
6958 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
6959 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
6961 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
6962 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
6964 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
6965 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
6969 static void GetK(Local<String> name,
6970 const v8::PropertyCallbackInfo<v8::Value>& info) {
6971 ApiTestFuzzer::Fuzz();
6972 if (name->Equals(v8_str("foo")) ||
6973 name->Equals(v8_str("bar")) ||
6974 name->Equals(v8_str("baz"))) {
6975 info.GetReturnValue().SetUndefined();
6980 static void IndexedGetK(uint32_t index,
6981 const v8::PropertyCallbackInfo<v8::Value>& info) {
6982 ApiTestFuzzer::Fuzz();
6983 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
6987 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
6988 ApiTestFuzzer::Fuzz();
6989 v8::Handle<v8::Array> result = v8::Array::New(3);
6990 result->Set(v8::Integer::New(0), v8_str("foo"));
6991 result->Set(v8::Integer::New(1), v8_str("bar"));
6992 result->Set(v8::Integer::New(2), v8_str("baz"));
6993 info.GetReturnValue().Set(result);
6997 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
6998 ApiTestFuzzer::Fuzz();
6999 v8::Handle<v8::Array> result = v8::Array::New(2);
7000 result->Set(v8::Integer::New(0), v8_str("0"));
7001 result->Set(v8::Integer::New(1), v8_str("1"));
7002 info.GetReturnValue().Set(result);
7006 THREADED_TEST(Enumerators) {
7007 v8::HandleScope scope(v8::Isolate::GetCurrent());
7008 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7009 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7010 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7011 LocalContext context;
7012 context->Global()->Set(v8_str("k"), obj->NewInstance());
7013 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7018 "k[4294967295] = 0;"
7020 "k[4294967296] = 0;"
7024 "k[30000000000] = 0;"
7027 "for (var prop in k) {"
7028 " result.push(prop);"
7031 // Check that we get all the property names returned including the
7032 // ones from the enumerators in the right order: indexed properties
7033 // in numerical order, indexed interceptor properties, named
7034 // properties in insertion order, named interceptor properties.
7035 // This order is not mandated by the spec, so this test is just
7036 // documenting our behavior.
7037 CHECK_EQ(17, result->Length());
7038 // Indexed properties in numerical order.
7039 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
7040 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
7041 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
7042 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
7043 // Indexed interceptor properties in the order they are returned
7044 // from the enumerator interceptor.
7045 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
7046 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
7047 // Named properties in insertion order.
7048 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
7049 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
7050 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
7051 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
7052 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
7053 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
7054 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
7055 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
7056 // Named interceptor properties.
7057 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
7058 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
7059 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
7064 int p_getter_count2;
7067 static void PGetter(Local<String> name,
7068 const v8::PropertyCallbackInfo<v8::Value>& info) {
7069 ApiTestFuzzer::Fuzz();
7071 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
7072 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7073 if (name->Equals(v8_str("p1"))) {
7074 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7075 } else if (name->Equals(v8_str("p2"))) {
7076 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7077 } else if (name->Equals(v8_str("p3"))) {
7078 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7079 } else if (name->Equals(v8_str("p4"))) {
7080 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7085 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7086 ApiTestFuzzer::Fuzz();
7087 LocalContext context;
7088 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7090 "o1.__proto__ = { };"
7091 "var o2 = { __proto__: o1 };"
7092 "var o3 = { __proto__: o2 };"
7093 "var o4 = { __proto__: o3 };"
7094 "for (var i = 0; i < 10; i++) o4.p4;"
7095 "for (var i = 0; i < 10; i++) o3.p3;"
7096 "for (var i = 0; i < 10; i++) o2.p2;"
7097 "for (var i = 0; i < 10; i++) o1.p1;");
7101 static void PGetter2(Local<String> name,
7102 const v8::PropertyCallbackInfo<v8::Value>& info) {
7103 ApiTestFuzzer::Fuzz();
7105 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
7106 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7107 if (name->Equals(v8_str("p1"))) {
7108 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7109 } else if (name->Equals(v8_str("p2"))) {
7110 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7111 } else if (name->Equals(v8_str("p3"))) {
7112 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7113 } else if (name->Equals(v8_str("p4"))) {
7114 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7119 THREADED_TEST(GetterHolders) {
7120 v8::HandleScope scope(v8::Isolate::GetCurrent());
7121 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7122 obj->SetAccessor(v8_str("p1"), PGetter);
7123 obj->SetAccessor(v8_str("p2"), PGetter);
7124 obj->SetAccessor(v8_str("p3"), PGetter);
7125 obj->SetAccessor(v8_str("p4"), PGetter);
7128 CHECK_EQ(40, p_getter_count);
7132 THREADED_TEST(PreInterceptorHolders) {
7133 v8::HandleScope scope(v8::Isolate::GetCurrent());
7134 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7135 obj->SetNamedPropertyHandler(PGetter2);
7136 p_getter_count2 = 0;
7138 CHECK_EQ(40, p_getter_count2);
7142 THREADED_TEST(ObjectInstantiation) {
7143 v8::HandleScope scope(v8::Isolate::GetCurrent());
7144 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7145 templ->SetAccessor(v8_str("t"), PGetter2);
7146 LocalContext context;
7147 context->Global()->Set(v8_str("o"), templ->NewInstance());
7148 for (int i = 0; i < 100; i++) {
7149 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
7150 v8::Handle<v8::Object> obj = templ->NewInstance();
7151 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7152 context->Global()->Set(v8_str("o2"), obj);
7153 v8::Handle<Value> value =
7154 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
7155 CHECK_EQ(v8::True(), value);
7156 context->Global()->Set(v8_str("o"), obj);
7161 static int StrCmp16(uint16_t* a, uint16_t* b) {
7163 if (*a == 0 && *b == 0) return 0;
7164 if (*a != *b) return 0 + *a - *b;
7171 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7173 if (n-- == 0) return 0;
7174 if (*a == 0 && *b == 0) return 0;
7175 if (*a != *b) return 0 + *a - *b;
7182 int GetUtf8Length(Handle<String> str) {
7183 int len = str->Utf8Length();
7185 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7186 i::FlattenString(istr);
7187 len = str->Utf8Length();
7193 THREADED_TEST(StringWrite) {
7194 LocalContext context;
7195 v8::HandleScope scope(context->GetIsolate());
7196 v8::Handle<String> str = v8_str("abcde");
7197 // abc<Icelandic eth><Unicode snowman>.
7198 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7199 v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
7200 const int kStride = 4; // Must match stride in for loops in JS below.
7203 "for (var i = 0; i < 0xd800; i += 4) {"
7204 " left = left + String.fromCharCode(i);"
7208 "for (var i = 0; i < 0xd800; i += 4) {"
7209 " right = String.fromCharCode(i) + right;"
7211 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
7212 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7213 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7215 CHECK_EQ(5, str2->Length());
7216 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7217 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7220 char utf8buf[0xd800 * 3];
7225 memset(utf8buf, 0x1, 1000);
7226 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7228 CHECK_EQ(5, charlen);
7229 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7231 memset(utf8buf, 0x1, 1000);
7232 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7234 CHECK_EQ(5, charlen);
7235 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7237 memset(utf8buf, 0x1, 1000);
7238 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7240 CHECK_EQ(4, charlen);
7241 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7243 memset(utf8buf, 0x1, 1000);
7244 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7246 CHECK_EQ(4, charlen);
7247 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7249 memset(utf8buf, 0x1, 1000);
7250 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7252 CHECK_EQ(4, charlen);
7253 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7255 memset(utf8buf, 0x1, 1000);
7256 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7258 CHECK_EQ(3, charlen);
7259 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7261 memset(utf8buf, 0x1, 1000);
7262 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7264 CHECK_EQ(3, charlen);
7265 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7267 memset(utf8buf, 0x1, 1000);
7268 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7270 CHECK_EQ(2, charlen);
7271 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7273 memset(utf8buf, 0x1, sizeof(utf8buf));
7274 len = GetUtf8Length(left_tree);
7276 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7277 CHECK_EQ(utf8_expected, len);
7278 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7279 CHECK_EQ(utf8_expected, len);
7280 CHECK_EQ(0xd800 / kStride, charlen);
7281 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7282 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7283 CHECK_EQ(0xc0 - kStride,
7284 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7285 CHECK_EQ(1, utf8buf[utf8_expected]);
7287 memset(utf8buf, 0x1, sizeof(utf8buf));
7288 len = GetUtf8Length(right_tree);
7289 CHECK_EQ(utf8_expected, len);
7290 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7291 CHECK_EQ(utf8_expected, len);
7292 CHECK_EQ(0xd800 / kStride, charlen);
7293 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7294 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7295 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7296 CHECK_EQ(1, utf8buf[utf8_expected]);
7298 memset(buf, 0x1, sizeof(buf));
7299 memset(wbuf, 0x1, sizeof(wbuf));
7300 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7302 len = str->Write(wbuf);
7304 CHECK_EQ(0, strcmp("abcde", buf));
7305 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7306 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7308 memset(buf, 0x1, sizeof(buf));
7309 memset(wbuf, 0x1, sizeof(wbuf));
7310 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7312 len = str->Write(wbuf, 0, 4);
7314 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7315 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7316 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7318 memset(buf, 0x1, sizeof(buf));
7319 memset(wbuf, 0x1, sizeof(wbuf));
7320 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7322 len = str->Write(wbuf, 0, 5);
7324 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7325 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7326 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7328 memset(buf, 0x1, sizeof(buf));
7329 memset(wbuf, 0x1, sizeof(wbuf));
7330 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7332 len = str->Write(wbuf, 0, 6);
7334 CHECK_EQ(0, strcmp("abcde", buf));
7335 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7336 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7338 memset(buf, 0x1, sizeof(buf));
7339 memset(wbuf, 0x1, sizeof(wbuf));
7340 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7342 len = str->Write(wbuf, 4, -1);
7344 CHECK_EQ(0, strcmp("e", buf));
7345 uint16_t answer5[] = {'e', '\0'};
7346 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7348 memset(buf, 0x1, sizeof(buf));
7349 memset(wbuf, 0x1, sizeof(wbuf));
7350 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7352 len = str->Write(wbuf, 4, 6);
7354 CHECK_EQ(0, strcmp("e", buf));
7355 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7357 memset(buf, 0x1, sizeof(buf));
7358 memset(wbuf, 0x1, sizeof(wbuf));
7359 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7361 len = str->Write(wbuf, 4, 1);
7363 CHECK_EQ(0, strncmp("e\1", buf, 2));
7364 uint16_t answer6[] = {'e', 0x101};
7365 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7367 memset(buf, 0x1, sizeof(buf));
7368 memset(wbuf, 0x1, sizeof(wbuf));
7369 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7371 len = str->Write(wbuf, 3, 1);
7373 CHECK_EQ(0, strncmp("d\1", buf, 2));
7374 uint16_t answer7[] = {'d', 0x101};
7375 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7377 memset(wbuf, 0x1, sizeof(wbuf));
7379 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7381 CHECK_EQ('X', wbuf[5]);
7382 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7383 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7384 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7385 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7387 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7389 memset(buf, 0x1, sizeof(buf));
7391 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7394 String::NO_NULL_TERMINATION);
7396 CHECK_EQ('X', buf[5]);
7397 CHECK_EQ(0, strncmp("abcde", buf, 5));
7398 CHECK_NE(0, strcmp("abcde", buf));
7400 CHECK_EQ(0, strcmp("abcde", buf));
7402 memset(utf8buf, 0x1, sizeof(utf8buf));
7404 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7405 String::NO_NULL_TERMINATION);
7407 CHECK_EQ('X', utf8buf[8]);
7408 CHECK_EQ(5, charlen);
7409 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7410 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7412 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7414 memset(utf8buf, 0x1, sizeof(utf8buf));
7416 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7417 String::NO_NULL_TERMINATION);
7419 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7420 CHECK_EQ(5, charlen);
7422 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7424 memset(buf, 0x1, sizeof(buf));
7425 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7427 CHECK_EQ(0, strcmp("abc", buf));
7428 CHECK_EQ(0, buf[3]);
7429 CHECK_EQ(0, strcmp("def", buf + 4));
7431 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7432 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7433 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7437 static void Utf16Helper(
7438 LocalContext& context,
7440 const char* lengths_name,
7442 Local<v8::Array> a =
7443 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7444 Local<v8::Array> alens =
7445 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7446 for (int i = 0; i < len; i++) {
7447 Local<v8::String> string =
7448 Local<v8::String>::Cast(a->Get(i));
7449 Local<v8::Number> expected_len =
7450 Local<v8::Number>::Cast(alens->Get(i));
7451 int length = GetUtf8Length(string);
7452 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7457 static uint16_t StringGet(Handle<String> str, int index) {
7458 i::Handle<i::String> istring =
7459 v8::Utils::OpenHandle(String::Cast(*str));
7460 return istring->Get(index);
7464 static void WriteUtf8Helper(
7465 LocalContext& context,
7467 const char* lengths_name,
7469 Local<v8::Array> b =
7470 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7471 Local<v8::Array> alens =
7472 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7475 for (int i = 0; i < len; i++) {
7476 Local<v8::String> string =
7477 Local<v8::String>::Cast(b->Get(i));
7478 Local<v8::Number> expected_len =
7479 Local<v8::Number>::Cast(alens->Get(i));
7480 int utf8_length = static_cast<int>(expected_len->Value());
7481 for (int j = utf8_length + 1; j >= 0; j--) {
7482 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7483 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7486 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7488 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7489 CHECK_GE(utf8_length + 1, utf8_written);
7490 CHECK_GE(utf8_length, utf8_written2);
7491 for (int k = 0; k < utf8_written2; k++) {
7492 CHECK_EQ(buffer[k], buffer2[k]);
7494 CHECK(nchars * 3 >= utf8_written - 1);
7495 CHECK(nchars <= utf8_written);
7496 if (j == utf8_length + 1) {
7497 CHECK_EQ(utf8_written2, utf8_length);
7498 CHECK_EQ(utf8_written2 + 1, utf8_written);
7500 CHECK_EQ(buffer[utf8_written], 42);
7501 if (j > utf8_length) {
7502 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7503 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7504 Handle<String> roundtrip = v8_str(buffer);
7505 CHECK(roundtrip->Equals(string));
7507 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7509 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7511 uint16_t trail = StringGet(string, nchars - 1);
7512 uint16_t lead = StringGet(string, nchars - 2);
7513 if (((lead & 0xfc00) == 0xd800) &&
7514 ((trail & 0xfc00) == 0xdc00)) {
7515 unsigned char u1 = buffer2[utf8_written2 - 4];
7516 unsigned char u2 = buffer2[utf8_written2 - 3];
7517 unsigned char u3 = buffer2[utf8_written2 - 2];
7518 unsigned char u4 = buffer2[utf8_written2 - 1];
7519 CHECK_EQ((u1 & 0xf8), 0xf0);
7520 CHECK_EQ((u2 & 0xc0), 0x80);
7521 CHECK_EQ((u3 & 0xc0), 0x80);
7522 CHECK_EQ((u4 & 0xc0), 0x80);
7523 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7524 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7525 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7526 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7527 CHECK_EQ((u1 & 0x3), c >> 18);
7535 THREADED_TEST(Utf16) {
7536 LocalContext context;
7537 v8::HandleScope scope(context->GetIsolate());
7539 "var pad = '01234567890123456789';"
7541 "var plens = [20, 3, 3];"
7542 "p.push('01234567890123456789');"
7543 "var lead = 0xd800;"
7544 "var trail = 0xdc00;"
7545 "p.push(String.fromCharCode(0xd800));"
7546 "p.push(String.fromCharCode(0xdc00));"
7551 "for (var i = 0; i < 3; i++) {"
7552 " p[1] = String.fromCharCode(lead++);"
7553 " for (var j = 0; j < 3; j++) {"
7554 " p[2] = String.fromCharCode(trail++);"
7555 " a.push(p[i] + p[j]);"
7556 " b.push(p[i] + p[j]);"
7557 " c.push(p[i] + p[j]);"
7558 " alens.push(plens[i] + plens[j]);"
7561 "alens[5] -= 2;" // Here the surrogate pairs match up.
7566 "for (var m = 0; m < 9; m++) {"
7567 " for (var n = 0; n < 9; n++) {"
7568 " a2.push(a[m] + a[n]);"
7569 " b2.push(b[m] + b[n]);"
7570 " var newc = 'x' + c[m] + c[n] + 'y';"
7571 " c2.push(newc.substring(1, newc.length - 1));"
7572 " var utf = alens[m] + alens[n];" // And here.
7573 // The 'n's that start with 0xdc.. are 6-8
7574 // The 'm's that end with 0xd8.. are 1, 4 and 7
7575 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
7576 " a2lens.push(utf);"
7579 Utf16Helper(context, "a", "alens", 9);
7580 Utf16Helper(context, "a2", "a2lens", 81);
7581 WriteUtf8Helper(context, "b", "alens", 9);
7582 WriteUtf8Helper(context, "b2", "a2lens", 81);
7583 WriteUtf8Helper(context, "c2", "a2lens", 81);
7587 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7588 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7589 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7590 return *is1 == *is2;
7594 static void SameSymbolHelper(const char* a, const char* b) {
7595 Handle<String> symbol1 = v8::String::NewSymbol(a);
7596 Handle<String> symbol2 = v8::String::NewSymbol(b);
7597 CHECK(SameSymbol(symbol1, symbol2));
7601 THREADED_TEST(Utf16Symbol) {
7602 LocalContext context;
7603 v8::HandleScope scope(context->GetIsolate());
7605 Handle<String> symbol1 = v8::String::NewSymbol("abc");
7606 Handle<String> symbol2 = v8::String::NewSymbol("abc");
7607 CHECK(SameSymbol(symbol1, symbol2));
7609 SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
7610 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
7611 SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
7612 "\360\220\220\206"); // 4 byte encoding.
7613 SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
7614 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
7615 SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
7616 "x\360\220\220\206"); // 4 byte encoding.
7618 "var sym0 = 'benedictus';"
7619 "var sym0b = 'S\303\270ren';"
7620 "var sym1 = '\355\240\201\355\260\207';"
7621 "var sym2 = '\360\220\220\210';"
7622 "var sym3 = 'x\355\240\201\355\260\207';"
7623 "var sym4 = 'x\360\220\220\210';"
7624 "if (sym1.length != 2) throw sym1;"
7625 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
7626 "if (sym2.length != 2) throw sym2;"
7627 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
7628 "if (sym3.length != 3) throw sym3;"
7629 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
7630 "if (sym4.length != 3) throw sym4;"
7631 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
7632 Handle<String> sym0 = v8::String::NewSymbol("benedictus");
7633 Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
7634 Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
7635 Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
7636 Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
7637 Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
7638 v8::Local<v8::Object> global = context->Global();
7639 Local<Value> s0 = global->Get(v8_str("sym0"));
7640 Local<Value> s0b = global->Get(v8_str("sym0b"));
7641 Local<Value> s1 = global->Get(v8_str("sym1"));
7642 Local<Value> s2 = global->Get(v8_str("sym2"));
7643 Local<Value> s3 = global->Get(v8_str("sym3"));
7644 Local<Value> s4 = global->Get(v8_str("sym4"));
7645 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
7646 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
7647 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
7648 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
7649 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
7650 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
7654 THREADED_TEST(ToArrayIndex) {
7655 LocalContext context;
7656 v8::HandleScope scope(context->GetIsolate());
7658 v8::Handle<String> str = v8_str("42");
7659 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
7660 CHECK(!index.IsEmpty());
7661 CHECK_EQ(42.0, index->Uint32Value());
7662 str = v8_str("42asdf");
7663 index = str->ToArrayIndex();
7664 CHECK(index.IsEmpty());
7665 str = v8_str("-42");
7666 index = str->ToArrayIndex();
7667 CHECK(index.IsEmpty());
7668 str = v8_str("4294967295");
7669 index = str->ToArrayIndex();
7670 CHECK(!index.IsEmpty());
7671 CHECK_EQ(4294967295.0, index->Uint32Value());
7672 v8::Handle<v8::Number> num = v8::Number::New(1);
7673 index = num->ToArrayIndex();
7674 CHECK(!index.IsEmpty());
7675 CHECK_EQ(1.0, index->Uint32Value());
7676 num = v8::Number::New(-1);
7677 index = num->ToArrayIndex();
7678 CHECK(index.IsEmpty());
7679 v8::Handle<v8::Object> obj = v8::Object::New();
7680 index = obj->ToArrayIndex();
7681 CHECK(index.IsEmpty());
7685 THREADED_TEST(ErrorConstruction) {
7686 LocalContext context;
7687 v8::HandleScope scope(context->GetIsolate());
7689 v8::Handle<String> foo = v8_str("foo");
7690 v8::Handle<String> message = v8_str("message");
7691 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
7692 CHECK(range_error->IsObject());
7693 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
7694 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
7695 CHECK(reference_error->IsObject());
7696 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
7697 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
7698 CHECK(syntax_error->IsObject());
7699 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
7700 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
7701 CHECK(type_error->IsObject());
7702 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
7703 v8::Handle<Value> error = v8::Exception::Error(foo);
7704 CHECK(error->IsObject());
7705 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7709 static void YGetter(Local<String> name,
7710 const v8::PropertyCallbackInfo<v8::Value>& info) {
7711 ApiTestFuzzer::Fuzz();
7712 info.GetReturnValue().Set(v8_num(10));
7716 static void YSetter(Local<String> name,
7718 const v8::PropertyCallbackInfo<void>& info) {
7719 if (info.This()->Has(name)) {
7720 info.This()->Delete(name);
7722 info.This()->Set(name, value);
7726 THREADED_TEST(DeleteAccessor) {
7727 v8::HandleScope scope(v8::Isolate::GetCurrent());
7728 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7729 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
7730 LocalContext context;
7731 v8::Handle<v8::Object> holder = obj->NewInstance();
7732 context->Global()->Set(v8_str("holder"), holder);
7733 v8::Handle<Value> result = CompileRun(
7734 "holder.y = 11; holder.y = 12; holder.y");
7735 CHECK_EQ(12, result->Uint32Value());
7739 THREADED_TEST(TypeSwitch) {
7740 v8::HandleScope scope(v8::Isolate::GetCurrent());
7741 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
7742 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
7743 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
7744 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
7745 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
7746 LocalContext context;
7747 v8::Handle<v8::Object> obj0 = v8::Object::New();
7748 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
7749 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
7750 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
7751 for (int i = 0; i < 10; i++) {
7752 CHECK_EQ(0, type_switch->match(obj0));
7753 CHECK_EQ(1, type_switch->match(obj1));
7754 CHECK_EQ(2, type_switch->match(obj2));
7755 CHECK_EQ(3, type_switch->match(obj3));
7756 CHECK_EQ(3, type_switch->match(obj3));
7757 CHECK_EQ(2, type_switch->match(obj2));
7758 CHECK_EQ(1, type_switch->match(obj1));
7759 CHECK_EQ(0, type_switch->match(obj0));
7764 // For use within the TestSecurityHandler() test.
7765 static bool g_security_callback_result = false;
7766 static bool NamedSecurityTestCallback(Local<v8::Object> global,
7768 v8::AccessType type,
7769 Local<Value> data) {
7770 // Always allow read access.
7771 if (type == v8::ACCESS_GET)
7774 // Sometimes allow other access.
7775 return g_security_callback_result;
7779 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
7781 v8::AccessType type,
7782 Local<Value> data) {
7783 // Always allow read access.
7784 if (type == v8::ACCESS_GET)
7787 // Sometimes allow other access.
7788 return g_security_callback_result;
7792 static int trouble_nesting = 0;
7793 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7794 ApiTestFuzzer::Fuzz();
7797 // Call a JS function that throws an uncaught exception.
7798 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
7799 Local<Value> trouble_callee = (trouble_nesting == 3) ?
7800 arg_this->Get(v8_str("trouble_callee")) :
7801 arg_this->Get(v8_str("trouble_caller"));
7802 CHECK(trouble_callee->IsFunction());
7803 args.GetReturnValue().Set(
7804 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
7808 static int report_count = 0;
7809 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
7810 v8::Handle<Value>) {
7815 // Counts uncaught exceptions, but other tests running in parallel
7816 // also have uncaught exceptions.
7817 TEST(ApiUncaughtException) {
7820 v8::HandleScope scope(env->GetIsolate());
7821 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7823 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
7824 v8::Local<v8::Object> global = env->Global();
7825 global->Set(v8_str("trouble"), fun->GetFunction());
7827 Script::Compile(v8_str("function trouble_callee() {"
7831 "function trouble_caller() {"
7834 Local<Value> trouble = global->Get(v8_str("trouble"));
7835 CHECK(trouble->IsFunction());
7836 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
7837 CHECK(trouble_callee->IsFunction());
7838 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
7839 CHECK(trouble_caller->IsFunction());
7840 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
7841 CHECK_EQ(1, report_count);
7842 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7845 static const char* script_resource_name = "ExceptionInNativeScript.js";
7846 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
7847 v8::Handle<Value>) {
7848 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
7849 CHECK(!name_val.IsEmpty() && name_val->IsString());
7850 v8::String::Utf8Value name(message->GetScriptResourceName());
7851 CHECK_EQ(script_resource_name, *name);
7852 CHECK_EQ(3, message->GetLineNumber());
7853 v8::String::Utf8Value source_line(message->GetSourceLine());
7854 CHECK_EQ(" new o.foo();", *source_line);
7858 TEST(ExceptionInNativeScript) {
7860 v8::HandleScope scope(env->GetIsolate());
7861 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
7863 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
7864 v8::Local<v8::Object> global = env->Global();
7865 global->Set(v8_str("trouble"), fun->GetFunction());
7867 Script::Compile(v8_str("function trouble() {\n"
7870 "};"), v8::String::New(script_resource_name))->Run();
7871 Local<Value> trouble = global->Get(v8_str("trouble"));
7872 CHECK(trouble->IsFunction());
7873 Function::Cast(*trouble)->Call(global, 0, NULL);
7874 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
7878 TEST(CompilationErrorUsingTryCatchHandler) {
7880 v8::HandleScope scope(env->GetIsolate());
7881 v8::TryCatch try_catch;
7882 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
7883 CHECK_NE(NULL, *try_catch.Exception());
7884 CHECK(try_catch.HasCaught());
7888 TEST(TryCatchFinallyUsingTryCatchHandler) {
7890 v8::HandleScope scope(env->GetIsolate());
7891 v8::TryCatch try_catch;
7892 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
7893 CHECK(!try_catch.HasCaught());
7894 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
7895 CHECK(try_catch.HasCaught());
7897 Script::Compile(v8_str("(function() {"
7898 "try { throw ''; } finally { return; }"
7900 CHECK(!try_catch.HasCaught());
7901 Script::Compile(v8_str("(function()"
7902 " { try { throw ''; } finally { throw 0; }"
7904 CHECK(try_catch.HasCaught());
7908 // SecurityHandler can't be run twice
7909 TEST(SecurityHandler) {
7910 v8::HandleScope scope0(v8::Isolate::GetCurrent());
7911 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7912 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
7913 IndexedSecurityTestCallback);
7914 // Create an environment
7915 v8::Handle<Context> context0 =
7916 Context::New(v8::Isolate::GetCurrent(), NULL, global_template);
7919 v8::Handle<v8::Object> global0 = context0->Global();
7920 v8::Handle<Script> script0 = v8_compile("foo = 111");
7922 global0->Set(v8_str("0"), v8_num(999));
7923 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
7924 CHECK_EQ(111, foo0->Int32Value());
7925 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
7926 CHECK_EQ(999, z0->Int32Value());
7928 // Create another environment, should fail security checks.
7929 v8::HandleScope scope1(v8::Isolate::GetCurrent());
7931 v8::Handle<Context> context1 =
7932 Context::New(v8::Isolate::GetCurrent(), NULL, global_template);
7935 v8::Handle<v8::Object> global1 = context1->Global();
7936 global1->Set(v8_str("othercontext"), global0);
7937 // This set will fail the security check.
7938 v8::Handle<Script> script1 =
7939 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
7941 // This read will pass the security check.
7942 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
7943 CHECK_EQ(111, foo1->Int32Value());
7944 // This read will pass the security check.
7945 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
7946 CHECK_EQ(999, z1->Int32Value());
7948 // Create another environment, should pass security checks.
7949 { g_security_callback_result = true; // allow security handler to pass.
7950 v8::HandleScope scope2(v8::Isolate::GetCurrent());
7951 LocalContext context2;
7952 v8::Handle<v8::Object> global2 = context2->Global();
7953 global2->Set(v8_str("othercontext"), global0);
7954 v8::Handle<Script> script2 =
7955 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
7957 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
7958 CHECK_EQ(333, foo2->Int32Value());
7959 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
7960 CHECK_EQ(888, z2->Int32Value());
7968 THREADED_TEST(SecurityChecks) {
7970 v8::HandleScope handle_scope(env1->GetIsolate());
7971 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7973 Local<Value> foo = v8_str("foo");
7974 Local<Value> bar = v8_str("bar");
7976 // Set to the same domain.
7977 env1->SetSecurityToken(foo);
7979 // Create a function in env1.
7980 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
7981 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
7982 CHECK(spy->IsFunction());
7984 // Create another function accessing global objects.
7985 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
7986 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
7987 CHECK(spy2->IsFunction());
7989 // Switch to env2 in the same domain and invoke spy on env2.
7991 env2->SetSecurityToken(foo);
7993 Context::Scope scope_env2(env2);
7994 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
7995 CHECK(result->IsFunction());
7999 env2->SetSecurityToken(bar);
8000 Context::Scope scope_env2(env2);
8002 // Call cross_domain_call, it should throw an exception
8003 v8::TryCatch try_catch;
8004 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8005 CHECK(try_catch.HasCaught());
8010 // Regression test case for issue 1183439.
8011 THREADED_TEST(SecurityChecksForPrototypeChain) {
8012 LocalContext current;
8013 v8::HandleScope scope(current->GetIsolate());
8014 v8::Handle<Context> other = Context::New(current->GetIsolate());
8016 // Change context to be able to get to the Object function in the
8017 // other context without hitting the security checks.
8018 v8::Local<Value> other_object;
8019 { Context::Scope scope(other);
8020 other_object = other->Global()->Get(v8_str("Object"));
8021 other->Global()->Set(v8_num(42), v8_num(87));
8024 current->Global()->Set(v8_str("other"), other->Global());
8025 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8027 // Make sure the security check fails here and we get an undefined
8028 // result instead of getting the Object function. Repeat in a loop
8029 // to make sure to exercise the IC code.
8030 v8::Local<Script> access_other0 = v8_compile("other.Object");
8031 v8::Local<Script> access_other1 = v8_compile("other[42]");
8032 for (int i = 0; i < 5; i++) {
8033 CHECK(!access_other0->Run()->Equals(other_object));
8034 CHECK(access_other0->Run()->IsUndefined());
8035 CHECK(!access_other1->Run()->Equals(v8_num(87)));
8036 CHECK(access_other1->Run()->IsUndefined());
8039 // Create an object that has 'other' in its prototype chain and make
8040 // sure we cannot access the Object function indirectly through
8041 // that. Repeat in a loop to make sure to exercise the IC code.
8042 v8_compile("function F() { };"
8043 "F.prototype = other;"
8044 "var f = new F();")->Run();
8045 v8::Local<Script> access_f0 = v8_compile("f.Object");
8046 v8::Local<Script> access_f1 = v8_compile("f[42]");
8047 for (int j = 0; j < 5; j++) {
8048 CHECK(!access_f0->Run()->Equals(other_object));
8049 CHECK(access_f0->Run()->IsUndefined());
8050 CHECK(!access_f1->Run()->Equals(v8_num(87)));
8051 CHECK(access_f1->Run()->IsUndefined());
8054 // Now it gets hairy: Set the prototype for the other global object
8055 // to be the current global object. The prototype chain for 'f' now
8056 // goes through 'other' but ends up in the current global object.
8057 { Context::Scope scope(other);
8058 other->Global()->Set(v8_str("__proto__"), current->Global());
8060 // Set a named and an index property on the current global
8061 // object. To force the lookup to go through the other global object,
8062 // the properties must not exist in the other global object.
8063 current->Global()->Set(v8_str("foo"), v8_num(100));
8064 current->Global()->Set(v8_num(99), v8_num(101));
8065 // Try to read the properties from f and make sure that the access
8066 // gets stopped by the security checks on the other global object.
8067 Local<Script> access_f2 = v8_compile("f.foo");
8068 Local<Script> access_f3 = v8_compile("f[99]");
8069 for (int k = 0; k < 5; k++) {
8070 CHECK(!access_f2->Run()->Equals(v8_num(100)));
8071 CHECK(access_f2->Run()->IsUndefined());
8072 CHECK(!access_f3->Run()->Equals(v8_num(101)));
8073 CHECK(access_f3->Run()->IsUndefined());
8078 THREADED_TEST(CrossDomainDelete) {
8080 v8::HandleScope handle_scope(env1->GetIsolate());
8081 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8083 Local<Value> foo = v8_str("foo");
8084 Local<Value> bar = v8_str("bar");
8086 // Set to the same domain.
8087 env1->SetSecurityToken(foo);
8088 env2->SetSecurityToken(foo);
8090 env1->Global()->Set(v8_str("prop"), v8_num(3));
8091 env2->Global()->Set(v8_str("env1"), env1->Global());
8093 // Change env2 to a different domain and delete env1.prop.
8094 env2->SetSecurityToken(bar);
8096 Context::Scope scope_env2(env2);
8097 Local<Value> result =
8098 Script::Compile(v8_str("delete env1.prop"))->Run();
8099 CHECK(result->IsFalse());
8102 // Check that env1.prop still exists.
8103 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8104 CHECK(v->IsNumber());
8105 CHECK_EQ(3, v->Int32Value());
8109 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8111 v8::HandleScope handle_scope(env1->GetIsolate());
8112 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8114 Local<Value> foo = v8_str("foo");
8115 Local<Value> bar = v8_str("bar");
8117 // Set to the same domain.
8118 env1->SetSecurityToken(foo);
8119 env2->SetSecurityToken(foo);
8121 env1->Global()->Set(v8_str("prop"), v8_num(3));
8122 env2->Global()->Set(v8_str("env1"), env1->Global());
8124 // env1.prop is enumerable in env2.
8125 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8127 Context::Scope scope_env2(env2);
8128 Local<Value> result = Script::Compile(test)->Run();
8129 CHECK(result->IsTrue());
8132 // Change env2 to a different domain and test again.
8133 env2->SetSecurityToken(bar);
8135 Context::Scope scope_env2(env2);
8136 Local<Value> result = Script::Compile(test)->Run();
8137 CHECK(result->IsFalse());
8142 THREADED_TEST(CrossDomainForIn) {
8144 v8::HandleScope handle_scope(env1->GetIsolate());
8145 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8147 Local<Value> foo = v8_str("foo");
8148 Local<Value> bar = v8_str("bar");
8150 // Set to the same domain.
8151 env1->SetSecurityToken(foo);
8152 env2->SetSecurityToken(foo);
8154 env1->Global()->Set(v8_str("prop"), v8_num(3));
8155 env2->Global()->Set(v8_str("env1"), env1->Global());
8157 // Change env2 to a different domain and set env1's global object
8158 // as the __proto__ of an object in env2 and enumerate properties
8159 // in for-in. It shouldn't enumerate properties on env1's global
8161 env2->SetSecurityToken(bar);
8163 Context::Scope scope_env2(env2);
8164 Local<Value> result =
8165 CompileRun("(function(){var obj = {'__proto__':env1};"
8166 "for (var p in obj)"
8167 " if (p == 'prop') return false;"
8168 "return true;})()");
8169 CHECK(result->IsTrue());
8174 TEST(ContextDetachGlobal) {
8176 v8::HandleScope handle_scope(env1->GetIsolate());
8177 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8179 Local<v8::Object> global1 = env1->Global();
8181 Local<Value> foo = v8_str("foo");
8183 // Set to the same domain.
8184 env1->SetSecurityToken(foo);
8185 env2->SetSecurityToken(foo);
8190 // Create a function in env2 and add a reference to it in env1.
8191 Local<v8::Object> global2 = env2->Global();
8192 global2->Set(v8_str("prop"), v8::Integer::New(1));
8193 CompileRun("function getProp() {return prop;}");
8195 env1->Global()->Set(v8_str("getProp"),
8196 global2->Get(v8_str("getProp")));
8198 // Detach env2's global, and reuse the global object of env2
8200 env2->DetachGlobal();
8201 // env2 has a new global object.
8202 CHECK(!env2->Global()->Equals(global2));
8204 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8206 v8::Handle<v8::ObjectTemplate>(),
8208 env3->SetSecurityToken(v8_str("bar"));
8211 Local<v8::Object> global3 = env3->Global();
8212 CHECK_EQ(global2, global3);
8213 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8214 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8215 global3->Set(v8_str("prop"), v8::Integer::New(-1));
8216 global3->Set(v8_str("prop2"), v8::Integer::New(2));
8219 // Call getProp in env1, and it should return the value 1
8221 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8222 CHECK(get_prop->IsFunction());
8223 v8::TryCatch try_catch;
8224 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8225 CHECK(!try_catch.HasCaught());
8226 CHECK_EQ(1, r->Int32Value());
8229 // Check that env3 is not accessible from env1
8231 Local<Value> r = global3->Get(v8_str("prop2"));
8232 CHECK(r->IsUndefined());
8237 TEST(DetachAndReattachGlobal) {
8239 v8::HandleScope scope(env1->GetIsolate());
8241 // Create second environment.
8242 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8244 Local<Value> foo = v8_str("foo");
8246 // Set same security token for env1 and env2.
8247 env1->SetSecurityToken(foo);
8248 env2->SetSecurityToken(foo);
8250 // Create a property on the global object in env2.
8252 v8::Context::Scope scope(env2);
8253 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
8256 // Create a reference to env2 global from env1 global.
8257 env1->Global()->Set(v8_str("other"), env2->Global());
8259 // Check that we have access to other.p in env2 from env1.
8260 Local<Value> result = CompileRun("other.p");
8261 CHECK(result->IsInt32());
8262 CHECK_EQ(42, result->Int32Value());
8264 // Hold on to global from env2 and detach global from env2.
8265 Local<v8::Object> global2 = env2->Global();
8266 env2->DetachGlobal();
8268 // Check that the global has been detached. No other.p property can
8270 result = CompileRun("other.p");
8271 CHECK(result->IsUndefined());
8273 // Reuse global2 for env3.
8274 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8276 v8::Handle<v8::ObjectTemplate>(),
8278 CHECK_EQ(global2, env3->Global());
8280 // Start by using the same security token for env3 as for env1 and env2.
8281 env3->SetSecurityToken(foo);
8283 // Create a property on the global object in env3.
8285 v8::Context::Scope scope(env3);
8286 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
8289 // Check that other.p is now the property in env3 and that we have access.
8290 result = CompileRun("other.p");
8291 CHECK(result->IsInt32());
8292 CHECK_EQ(24, result->Int32Value());
8294 // Change security token for env3 to something different from env1 and env2.
8295 env3->SetSecurityToken(v8_str("bar"));
8297 // Check that we do not have access to other.p in env1. |other| is now
8298 // the global object for env3 which has a different security token,
8299 // so access should be blocked.
8300 result = CompileRun("other.p");
8301 CHECK(result->IsUndefined());
8303 // Detach the global for env3 and reattach it to env2.
8304 env3->DetachGlobal();
8305 env2->ReattachGlobal(global2);
8307 // Check that we have access to other.p again in env1. |other| is now
8308 // the global object for env2 which has the same security token as env1.
8309 result = CompileRun("other.p");
8310 CHECK(result->IsInt32());
8311 CHECK_EQ(42, result->Int32Value());
8315 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8316 static bool NamedAccessBlocker(Local<v8::Object> global,
8318 v8::AccessType type,
8319 Local<Value> data) {
8320 return Context::GetCurrent()->Global()->Equals(global) ||
8321 allowed_access_type[type];
8325 static bool IndexedAccessBlocker(Local<v8::Object> global,
8327 v8::AccessType type,
8328 Local<Value> data) {
8329 return Context::GetCurrent()->Global()->Equals(global) ||
8330 allowed_access_type[type];
8334 static int g_echo_value_1 = -1;
8335 static int g_echo_value_2 = -1;
8338 static void EchoGetter(
8340 const v8::PropertyCallbackInfo<v8::Value>& info) {
8341 info.GetReturnValue().Set(v8_num(g_echo_value_1));
8345 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8346 info.GetReturnValue().Set(v8_num(g_echo_value_2));
8350 static void EchoSetter(Local<String> name,
8352 const v8::PropertyCallbackInfo<void>&) {
8353 if (value->IsNumber())
8354 g_echo_value_1 = value->Int32Value();
8358 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8359 v8::Handle<v8::Value> value = info[0];
8360 if (value->IsNumber())
8361 g_echo_value_2 = value->Int32Value();
8365 static void UnreachableGetter(
8367 const v8::PropertyCallbackInfo<v8::Value>& info) {
8368 CHECK(false); // This function should not be called..
8372 static void UnreachableSetter(Local<String>,
8374 const v8::PropertyCallbackInfo<void>&) {
8375 CHECK(false); // This function should nto be called.
8379 static void UnreachableFunction(
8380 const v8::FunctionCallbackInfo<v8::Value>& info) {
8381 CHECK(false); // This function should not be called..
8385 TEST(AccessControl) {
8386 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8387 v8::HandleScope handle_scope(isolate);
8388 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8390 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8391 IndexedAccessBlocker);
8393 // Add an accessor accessible by cross-domain JS code.
8394 global_template->SetAccessor(
8395 v8_str("accessible_prop"),
8396 EchoGetter, EchoSetter,
8397 v8::Handle<Value>(),
8398 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8401 global_template->SetAccessorProperty(
8402 v8_str("accessible_js_prop"),
8403 v8::FunctionTemplate::New(EchoGetter),
8404 v8::FunctionTemplate::New(EchoSetter),
8406 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8408 // Add an accessor that is not accessible by cross-domain JS code.
8409 global_template->SetAccessor(v8_str("blocked_prop"),
8410 UnreachableGetter, UnreachableSetter,
8411 v8::Handle<Value>(),
8414 global_template->SetAccessorProperty(
8415 v8_str("blocked_js_prop"),
8416 v8::FunctionTemplate::New(UnreachableFunction),
8417 v8::FunctionTemplate::New(UnreachableFunction),
8421 // Create an environment
8422 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8425 v8::Handle<v8::Object> global0 = context0->Global();
8427 // Define a property with JS getter and setter.
8429 "function getter() { return 'getter'; };\n"
8430 "function setter() { return 'setter'; }\n"
8431 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8433 Local<Value> getter = global0->Get(v8_str("getter"));
8434 Local<Value> setter = global0->Get(v8_str("setter"));
8436 // And define normal element.
8437 global0->Set(239, v8_str("239"));
8439 // Define an element with JS getter and setter.
8441 "function el_getter() { return 'el_getter'; };\n"
8442 "function el_setter() { return 'el_setter'; };\n"
8443 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8445 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8446 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8448 v8::HandleScope scope1(isolate);
8450 v8::Local<Context> context1 = Context::New(isolate);
8453 v8::Handle<v8::Object> global1 = context1->Global();
8454 global1->Set(v8_str("other"), global0);
8456 // Access blocked property.
8457 CompileRun("other.blocked_prop = 1");
8459 ExpectUndefined("other.blocked_prop");
8461 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8462 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
8464 // Enable ACCESS_HAS
8465 allowed_access_type[v8::ACCESS_HAS] = true;
8466 ExpectUndefined("other.blocked_prop");
8467 // ... and now we can get the descriptor...
8469 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
8470 // ... and enumerate the property.
8471 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
8472 allowed_access_type[v8::ACCESS_HAS] = false;
8474 // Access blocked element.
8475 CompileRun("other[239] = 1");
8477 ExpectUndefined("other[239]");
8478 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
8479 ExpectFalse("propertyIsEnumerable.call(other, '239')");
8481 // Enable ACCESS_HAS
8482 allowed_access_type[v8::ACCESS_HAS] = true;
8483 ExpectUndefined("other[239]");
8484 // ... and now we can get the descriptor...
8485 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
8486 // ... and enumerate the property.
8487 ExpectTrue("propertyIsEnumerable.call(other, '239')");
8488 allowed_access_type[v8::ACCESS_HAS] = false;
8490 // Access a property with JS accessor.
8491 CompileRun("other.js_accessor_p = 2");
8493 ExpectUndefined("other.js_accessor_p");
8495 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
8497 // Enable ACCESS_HAS.
8498 allowed_access_type[v8::ACCESS_HAS] = true;
8499 ExpectUndefined("other.js_accessor_p");
8501 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
8503 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
8505 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8506 allowed_access_type[v8::ACCESS_HAS] = false;
8508 // Enable both ACCESS_HAS and ACCESS_GET.
8509 allowed_access_type[v8::ACCESS_HAS] = true;
8510 allowed_access_type[v8::ACCESS_GET] = true;
8512 ExpectString("other.js_accessor_p", "getter");
8514 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8516 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
8518 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8520 allowed_access_type[v8::ACCESS_GET] = false;
8521 allowed_access_type[v8::ACCESS_HAS] = false;
8523 // Enable both ACCESS_HAS and ACCESS_SET.
8524 allowed_access_type[v8::ACCESS_HAS] = true;
8525 allowed_access_type[v8::ACCESS_SET] = true;
8527 ExpectUndefined("other.js_accessor_p");
8529 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
8531 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8533 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8535 allowed_access_type[v8::ACCESS_SET] = false;
8536 allowed_access_type[v8::ACCESS_HAS] = false;
8538 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
8539 allowed_access_type[v8::ACCESS_HAS] = true;
8540 allowed_access_type[v8::ACCESS_GET] = true;
8541 allowed_access_type[v8::ACCESS_SET] = true;
8543 ExpectString("other.js_accessor_p", "getter");
8545 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8547 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8549 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8551 allowed_access_type[v8::ACCESS_SET] = false;
8552 allowed_access_type[v8::ACCESS_GET] = false;
8553 allowed_access_type[v8::ACCESS_HAS] = false;
8555 // Access an element with JS accessor.
8556 CompileRun("other[42] = 2");
8558 ExpectUndefined("other[42]");
8559 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
8561 // Enable ACCESS_HAS.
8562 allowed_access_type[v8::ACCESS_HAS] = true;
8563 ExpectUndefined("other[42]");
8564 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
8565 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
8566 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8567 allowed_access_type[v8::ACCESS_HAS] = false;
8569 // Enable both ACCESS_HAS and ACCESS_GET.
8570 allowed_access_type[v8::ACCESS_HAS] = true;
8571 allowed_access_type[v8::ACCESS_GET] = true;
8573 ExpectString("other[42]", "el_getter");
8574 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8575 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
8576 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8578 allowed_access_type[v8::ACCESS_GET] = false;
8579 allowed_access_type[v8::ACCESS_HAS] = false;
8581 // Enable both ACCESS_HAS and ACCESS_SET.
8582 allowed_access_type[v8::ACCESS_HAS] = true;
8583 allowed_access_type[v8::ACCESS_SET] = true;
8585 ExpectUndefined("other[42]");
8586 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
8587 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8588 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8590 allowed_access_type[v8::ACCESS_SET] = false;
8591 allowed_access_type[v8::ACCESS_HAS] = false;
8593 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
8594 allowed_access_type[v8::ACCESS_HAS] = true;
8595 allowed_access_type[v8::ACCESS_GET] = true;
8596 allowed_access_type[v8::ACCESS_SET] = true;
8598 ExpectString("other[42]", "el_getter");
8599 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8600 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8601 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8603 allowed_access_type[v8::ACCESS_SET] = false;
8604 allowed_access_type[v8::ACCESS_GET] = false;
8605 allowed_access_type[v8::ACCESS_HAS] = false;
8607 v8::Handle<Value> value;
8609 // Access accessible property
8610 value = CompileRun("other.accessible_prop = 3");
8611 CHECK(value->IsNumber());
8612 CHECK_EQ(3, value->Int32Value());
8613 CHECK_EQ(3, g_echo_value_1);
8615 // Access accessible js property
8616 value = CompileRun("other.accessible_js_prop = 3");
8617 CHECK(value->IsNumber());
8618 CHECK_EQ(3, value->Int32Value());
8619 CHECK_EQ(3, g_echo_value_2);
8621 value = CompileRun("other.accessible_prop");
8622 CHECK(value->IsNumber());
8623 CHECK_EQ(3, value->Int32Value());
8625 value = CompileRun("other.accessible_js_prop");
8626 CHECK(value->IsNumber());
8627 CHECK_EQ(3, value->Int32Value());
8630 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
8631 CHECK(value->IsNumber());
8632 CHECK_EQ(3, value->Int32Value());
8635 "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
8636 CHECK(value->IsNumber());
8637 CHECK_EQ(3, value->Int32Value());
8639 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
8640 CHECK(value->IsTrue());
8642 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
8643 CHECK(value->IsTrue());
8645 // Enumeration doesn't enumerate accessors from inaccessible objects in
8646 // the prototype chain even if the accessors are in themselves accessible.
8648 CompileRun("(function(){var obj = {'__proto__':other};"
8649 "for (var p in obj)"
8650 " if (p == 'accessible_prop' ||"
8651 " p == 'accessible_js_prop' ||"
8652 " p == 'blocked_js_prop' ||"
8653 " p == 'blocked_js_prop') {"
8656 "return true;})()");
8657 CHECK(value->IsTrue());
8664 TEST(AccessControlES5) {
8665 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8666 v8::HandleScope handle_scope(isolate);
8667 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8669 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8670 IndexedAccessBlocker);
8672 // Add accessible accessor.
8673 global_template->SetAccessor(
8674 v8_str("accessible_prop"),
8675 EchoGetter, EchoSetter,
8676 v8::Handle<Value>(),
8677 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8680 // Add an accessor that is not accessible by cross-domain JS code.
8681 global_template->SetAccessor(v8_str("blocked_prop"),
8682 UnreachableGetter, UnreachableSetter,
8683 v8::Handle<Value>(),
8686 // Create an environment
8687 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8690 v8::Handle<v8::Object> global0 = context0->Global();
8692 v8::Local<Context> context1 = Context::New(isolate);
8694 v8::Handle<v8::Object> global1 = context1->Global();
8695 global1->Set(v8_str("other"), global0);
8697 // Regression test for issue 1154.
8698 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
8700 ExpectUndefined("other.blocked_prop");
8702 // Regression test for issue 1027.
8703 CompileRun("Object.defineProperty(\n"
8704 " other, 'blocked_prop', {configurable: false})");
8705 ExpectUndefined("other.blocked_prop");
8707 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8709 // Regression test for issue 1171.
8710 ExpectTrue("Object.isExtensible(other)");
8711 CompileRun("Object.preventExtensions(other)");
8712 ExpectTrue("Object.isExtensible(other)");
8714 // Object.seal and Object.freeze.
8715 CompileRun("Object.freeze(other)");
8716 ExpectTrue("Object.isExtensible(other)");
8718 CompileRun("Object.seal(other)");
8719 ExpectTrue("Object.isExtensible(other)");
8721 // Regression test for issue 1250.
8722 // Make sure that we can set the accessible accessors value using normal
8724 CompileRun("other.accessible_prop = 42");
8725 CHECK_EQ(42, g_echo_value_1);
8727 v8::Handle<Value> value;
8728 // We follow Safari in ignoring assignments to host object accessors.
8729 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
8730 value = CompileRun("other.accessible_prop == 42");
8731 CHECK(value->IsTrue());
8735 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
8737 v8::AccessType type,
8738 Local<Value> data) {
8743 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
8745 v8::AccessType type,
8746 Local<Value> data) {
8751 THREADED_TEST(AccessControlGetOwnPropertyNames) {
8752 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8753 v8::HandleScope handle_scope(isolate);
8754 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
8756 obj_template->Set(v8_str("x"), v8::Integer::New(42));
8757 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
8758 GetOwnPropertyNamesIndexedBlocker);
8760 // Create an environment
8761 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
8764 v8::Handle<v8::Object> global0 = context0->Global();
8766 v8::HandleScope scope1(v8::Isolate::GetCurrent());
8768 v8::Local<Context> context1 = Context::New(isolate);
8771 v8::Handle<v8::Object> global1 = context1->Global();
8772 global1->Set(v8_str("other"), global0);
8773 global1->Set(v8_str("object"), obj_template->NewInstance());
8775 v8::Handle<Value> value;
8777 // Attempt to get the property names of the other global object and
8778 // of an object that requires access checks. Accessing the other
8779 // global object should be blocked by access checks on the global
8780 // proxy object. Accessing the object that requires access checks
8781 // is blocked by the access checks on the object itself.
8782 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
8783 CHECK(value->IsTrue());
8785 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
8786 CHECK(value->IsTrue());
8793 static void IndexedPropertyEnumerator(
8794 const v8::PropertyCallbackInfo<v8::Array>& info) {
8795 v8::Handle<v8::Array> result = v8::Array::New(2);
8796 result->Set(0, v8::Integer::New(7));
8797 result->Set(1, v8::Object::New());
8798 info.GetReturnValue().Set(result);
8802 static void NamedPropertyEnumerator(
8803 const v8::PropertyCallbackInfo<v8::Array>& info) {
8804 v8::Handle<v8::Array> result = v8::Array::New(2);
8805 result->Set(0, v8_str("x"));
8806 result->Set(1, v8::Object::New());
8807 info.GetReturnValue().Set(result);
8811 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
8812 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
8813 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
8815 obj_template->Set(v8_str("7"), v8::Integer::New(7));
8816 obj_template->Set(v8_str("x"), v8::Integer::New(42));
8817 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
8818 IndexedPropertyEnumerator);
8819 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
8820 NamedPropertyEnumerator);
8822 LocalContext context;
8823 v8::Handle<v8::Object> global = context->Global();
8824 global->Set(v8_str("object"), obj_template->NewInstance());
8826 v8::Handle<v8::Value> result =
8827 CompileRun("Object.getOwnPropertyNames(object)");
8828 CHECK(result->IsArray());
8829 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
8830 CHECK_EQ(3, result_array->Length());
8831 CHECK(result_array->Get(0)->IsString());
8832 CHECK(result_array->Get(1)->IsString());
8833 CHECK(result_array->Get(2)->IsString());
8834 CHECK_EQ(v8_str("7"), result_array->Get(0));
8835 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
8836 CHECK_EQ(v8_str("x"), result_array->Get(2));
8840 static void ConstTenGetter(Local<String> name,
8841 const v8::PropertyCallbackInfo<v8::Value>& info) {
8842 info.GetReturnValue().Set(v8_num(10));
8846 THREADED_TEST(CrossDomainAccessors) {
8847 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8848 v8::HandleScope handle_scope(isolate);
8850 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
8852 v8::Handle<v8::ObjectTemplate> global_template =
8853 func_template->InstanceTemplate();
8855 v8::Handle<v8::ObjectTemplate> proto_template =
8856 func_template->PrototypeTemplate();
8858 // Add an accessor to proto that's accessible by cross-domain JS code.
8859 proto_template->SetAccessor(v8_str("accessible"),
8861 v8::Handle<Value>(),
8864 // Add an accessor that is not accessible by cross-domain JS code.
8865 global_template->SetAccessor(v8_str("unreachable"),
8866 UnreachableGetter, 0,
8867 v8::Handle<Value>(),
8870 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8873 Local<v8::Object> global = context0->Global();
8874 // Add a normal property that shadows 'accessible'
8875 global->Set(v8_str("accessible"), v8_num(11));
8877 // Enter a new context.
8878 v8::HandleScope scope1(v8::Isolate::GetCurrent());
8879 v8::Local<Context> context1 = Context::New(isolate);
8882 v8::Handle<v8::Object> global1 = context1->Global();
8883 global1->Set(v8_str("other"), global);
8885 // Should return 10, instead of 11
8886 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
8887 CHECK(value->IsNumber());
8888 CHECK_EQ(10, value->Int32Value());
8890 value = v8_compile("other.unreachable")->Run();
8891 CHECK(value->IsUndefined());
8898 static int named_access_count = 0;
8899 static int indexed_access_count = 0;
8901 static bool NamedAccessCounter(Local<v8::Object> global,
8903 v8::AccessType type,
8904 Local<Value> data) {
8905 named_access_count++;
8910 static bool IndexedAccessCounter(Local<v8::Object> global,
8912 v8::AccessType type,
8913 Local<Value> data) {
8914 indexed_access_count++;
8919 // This one is too easily disturbed by other tests.
8920 TEST(AccessControlIC) {
8921 named_access_count = 0;
8922 indexed_access_count = 0;
8924 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8925 v8::HandleScope handle_scope(isolate);
8927 // Create an environment.
8928 v8::Local<Context> context0 = Context::New(isolate);
8931 // Create an object that requires access-check functions to be
8932 // called for cross-domain access.
8933 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
8934 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
8935 IndexedAccessCounter);
8936 Local<v8::Object> object = object_template->NewInstance();
8938 v8::HandleScope scope1(isolate);
8940 // Create another environment.
8941 v8::Local<Context> context1 = Context::New(isolate);
8944 // Make easy access to the object from the other environment.
8945 v8::Handle<v8::Object> global1 = context1->Global();
8946 global1->Set(v8_str("obj"), object);
8948 v8::Handle<Value> value;
8950 // Check that the named access-control function is called every time.
8951 CompileRun("function testProp(obj) {"
8952 " for (var i = 0; i < 10; i++) obj.prop = 1;"
8953 " for (var j = 0; j < 10; j++) obj.prop;"
8956 value = CompileRun("testProp(obj)");
8957 CHECK(value->IsNumber());
8958 CHECK_EQ(1, value->Int32Value());
8959 CHECK_EQ(21, named_access_count);
8961 // Check that the named access-control function is called every time.
8962 CompileRun("var p = 'prop';"
8963 "function testKeyed(obj) {"
8964 " for (var i = 0; i < 10; i++) obj[p] = 1;"
8965 " for (var j = 0; j < 10; j++) obj[p];"
8968 // Use obj which requires access checks. No inline caching is used
8970 value = CompileRun("testKeyed(obj)");
8971 CHECK(value->IsNumber());
8972 CHECK_EQ(1, value->Int32Value());
8973 CHECK_EQ(42, named_access_count);
8974 // Force the inline caches into generic state and try again.
8975 CompileRun("testKeyed({ a: 0 })");
8976 CompileRun("testKeyed({ b: 0 })");
8977 value = CompileRun("testKeyed(obj)");
8978 CHECK(value->IsNumber());
8979 CHECK_EQ(1, value->Int32Value());
8980 CHECK_EQ(63, named_access_count);
8982 // Check that the indexed access-control function is called every time.
8983 CompileRun("function testIndexed(obj) {"
8984 " for (var i = 0; i < 10; i++) obj[0] = 1;"
8985 " for (var j = 0; j < 10; j++) obj[0];"
8988 value = CompileRun("testIndexed(obj)");
8989 CHECK(value->IsNumber());
8990 CHECK_EQ(1, value->Int32Value());
8991 CHECK_EQ(21, indexed_access_count);
8992 // Force the inline caches into generic state.
8993 CompileRun("testIndexed(new Array(1))");
8994 // Test that the indexed access check is called.
8995 value = CompileRun("testIndexed(obj)");
8996 CHECK(value->IsNumber());
8997 CHECK_EQ(1, value->Int32Value());
8998 CHECK_EQ(42, indexed_access_count);
9000 // Check that the named access check is called when invoking
9001 // functions on an object that requires access checks.
9002 CompileRun("obj.f = function() {}");
9003 CompileRun("function testCallNormal(obj) {"
9004 " for (var i = 0; i < 10; i++) obj.f();"
9006 CompileRun("testCallNormal(obj)");
9007 CHECK_EQ(74, named_access_count);
9009 // Force obj into slow case.
9010 value = CompileRun("delete obj.prop");
9011 CHECK(value->BooleanValue());
9012 // Force inline caches into dictionary probing mode.
9013 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9014 // Test that the named access check is called.
9015 value = CompileRun("testProp(obj);");
9016 CHECK(value->IsNumber());
9017 CHECK_EQ(1, value->Int32Value());
9018 CHECK_EQ(96, named_access_count);
9020 // Force the call inline cache into dictionary probing mode.
9021 CompileRun("o.f = function() {}; testCallNormal(o)");
9022 // Test that the named access check is still called for each
9023 // invocation of the function.
9024 value = CompileRun("testCallNormal(obj)");
9025 CHECK_EQ(106, named_access_count);
9032 static bool NamedAccessFlatten(Local<v8::Object> global,
9034 v8::AccessType type,
9035 Local<Value> data) {
9039 CHECK(name->IsString());
9041 memset(buf, 0x1, sizeof(buf));
9042 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9047 memset(buf, 0x1, sizeof(buf));
9048 len = name.As<String>()->Write(buf2);
9055 static bool IndexedAccessFlatten(Local<v8::Object> global,
9057 v8::AccessType type,
9058 Local<Value> data) {
9063 // Regression test. In access checks, operations that may cause
9064 // garbage collection are not allowed. It used to be the case that
9065 // using the Write operation on a string could cause a garbage
9066 // collection due to flattening of the string. This is no longer the
9068 THREADED_TEST(AccessControlFlatten) {
9069 named_access_count = 0;
9070 indexed_access_count = 0;
9072 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9073 v8::HandleScope handle_scope(isolate);
9075 // Create an environment.
9076 v8::Local<Context> context0 = Context::New(isolate);
9079 // Create an object that requires access-check functions to be
9080 // called for cross-domain access.
9081 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
9082 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9083 IndexedAccessFlatten);
9084 Local<v8::Object> object = object_template->NewInstance();
9086 v8::HandleScope scope1(isolate);
9088 // Create another environment.
9089 v8::Local<Context> context1 = Context::New(isolate);
9092 // Make easy access to the object from the other environment.
9093 v8::Handle<v8::Object> global1 = context1->Global();
9094 global1->Set(v8_str("obj"), object);
9096 v8::Handle<Value> value;
9098 value = v8_compile("var p = 'as' + 'df';")->Run();
9099 value = v8_compile("obj[p];")->Run();
9106 static void AccessControlNamedGetter(
9108 const v8::PropertyCallbackInfo<v8::Value>& info) {
9109 info.GetReturnValue().Set(42);
9113 static void AccessControlNamedSetter(
9116 const v8::PropertyCallbackInfo<v8::Value>& info) {
9117 info.GetReturnValue().Set(value);
9121 static void AccessControlIndexedGetter(
9123 const v8::PropertyCallbackInfo<v8::Value>& info) {
9124 info.GetReturnValue().Set(v8_num(42));
9128 static void AccessControlIndexedSetter(
9131 const v8::PropertyCallbackInfo<v8::Value>& info) {
9132 info.GetReturnValue().Set(value);
9136 THREADED_TEST(AccessControlInterceptorIC) {
9137 named_access_count = 0;
9138 indexed_access_count = 0;
9140 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9141 v8::HandleScope handle_scope(isolate);
9143 // Create an environment.
9144 v8::Local<Context> context0 = Context::New(isolate);
9147 // Create an object that requires access-check functions to be
9148 // called for cross-domain access. The object also has interceptors
9150 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
9151 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9152 IndexedAccessCounter);
9153 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9154 AccessControlNamedSetter);
9155 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9156 AccessControlIndexedSetter);
9157 Local<v8::Object> object = object_template->NewInstance();
9159 v8::HandleScope scope1(isolate);
9161 // Create another environment.
9162 v8::Local<Context> context1 = Context::New(isolate);
9165 // Make easy access to the object from the other environment.
9166 v8::Handle<v8::Object> global1 = context1->Global();
9167 global1->Set(v8_str("obj"), object);
9169 v8::Handle<Value> value;
9171 // Check that the named access-control function is called every time
9172 // eventhough there is an interceptor on the object.
9173 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9174 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9176 CHECK(value->IsNumber());
9177 CHECK_EQ(42, value->Int32Value());
9178 CHECK_EQ(21, named_access_count);
9180 value = v8_compile("var p = 'x';")->Run();
9181 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9182 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9184 CHECK(value->IsNumber());
9185 CHECK_EQ(42, value->Int32Value());
9186 CHECK_EQ(42, named_access_count);
9188 // Check that the indexed access-control function is called every
9189 // time eventhough there is an interceptor on the object.
9190 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9191 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9193 CHECK(value->IsNumber());
9194 CHECK_EQ(42, value->Int32Value());
9195 CHECK_EQ(21, indexed_access_count);
9202 THREADED_TEST(Version) {
9203 v8::V8::GetVersion();
9207 static void InstanceFunctionCallback(
9208 const v8::FunctionCallbackInfo<v8::Value>& args) {
9209 ApiTestFuzzer::Fuzz();
9210 args.GetReturnValue().Set(v8_num(12));
9214 THREADED_TEST(InstanceProperties) {
9215 LocalContext context;
9216 v8::HandleScope handle_scope(context->GetIsolate());
9218 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9219 Local<ObjectTemplate> instance = t->InstanceTemplate();
9221 instance->Set(v8_str("x"), v8_num(42));
9222 instance->Set(v8_str("f"),
9223 v8::FunctionTemplate::New(InstanceFunctionCallback));
9225 Local<Value> o = t->GetFunction()->NewInstance();
9227 context->Global()->Set(v8_str("i"), o);
9228 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
9229 CHECK_EQ(42, value->Int32Value());
9231 value = Script::Compile(v8_str("i.f()"))->Run();
9232 CHECK_EQ(12, value->Int32Value());
9236 static void GlobalObjectInstancePropertiesGet(
9238 const v8::PropertyCallbackInfo<v8::Value>&) {
9239 ApiTestFuzzer::Fuzz();
9243 THREADED_TEST(GlobalObjectInstanceProperties) {
9244 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
9246 Local<Value> global_object;
9248 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9249 t->InstanceTemplate()->SetNamedPropertyHandler(
9250 GlobalObjectInstancePropertiesGet);
9251 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9252 instance_template->Set(v8_str("x"), v8_num(42));
9253 instance_template->Set(v8_str("f"),
9254 v8::FunctionTemplate::New(InstanceFunctionCallback));
9256 // The script to check how Crankshaft compiles missing global function
9257 // invocations. function g is not defined and should throw on call.
9258 const char* script =
9259 "function wrapper(call) {"
9260 " var x = 0, y = 1;"
9261 " for (var i = 0; i < 1000; i++) {"
9267 "for (var i = 0; i < 17; i++) wrapper(false);"
9269 "try { wrapper(true); } catch (e) { thrown = 1; };"
9273 LocalContext env(NULL, instance_template);
9274 // Hold on to the global object so it can be used again in another
9275 // environment initialization.
9276 global_object = env->Global();
9278 Local<Value> value = Script::Compile(v8_str("x"))->Run();
9279 CHECK_EQ(42, value->Int32Value());
9280 value = Script::Compile(v8_str("f()"))->Run();
9281 CHECK_EQ(12, value->Int32Value());
9282 value = Script::Compile(v8_str(script))->Run();
9283 CHECK_EQ(1, value->Int32Value());
9287 // Create new environment reusing the global object.
9288 LocalContext env(NULL, instance_template, global_object);
9289 Local<Value> value = Script::Compile(v8_str("x"))->Run();
9290 CHECK_EQ(42, value->Int32Value());
9291 value = Script::Compile(v8_str("f()"))->Run();
9292 CHECK_EQ(12, value->Int32Value());
9293 value = Script::Compile(v8_str(script))->Run();
9294 CHECK_EQ(1, value->Int32Value());
9299 THREADED_TEST(CallKnownGlobalReceiver) {
9300 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
9302 Local<Value> global_object;
9304 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9305 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9307 // The script to check that we leave global object not
9308 // global object proxy on stack when we deoptimize from inside
9309 // arguments evaluation.
9310 // To provoke error we need to both force deoptimization
9311 // from arguments evaluation and to force CallIC to take
9312 // CallIC_Miss code path that can't cope with global proxy.
9313 const char* script =
9314 "function bar(x, y) { try { } finally { } }"
9315 "function baz(x) { try { } finally { } }"
9316 "function bom(x) { try { } finally { } }"
9317 "function foo(x) { bar([x], bom(2)); }"
9318 "for (var i = 0; i < 10000; i++) foo(1);"
9323 LocalContext env(NULL, instance_template);
9324 // Hold on to the global object so it can be used again in another
9325 // environment initialization.
9326 global_object = env->Global();
9327 foo = Script::Compile(v8_str(script))->Run();
9331 // Create new environment reusing the global object.
9332 LocalContext env(NULL, instance_template, global_object);
9333 env->Global()->Set(v8_str("foo"), foo);
9334 Script::Compile(v8_str("foo()"))->Run();
9339 static void ShadowFunctionCallback(
9340 const v8::FunctionCallbackInfo<v8::Value>& args) {
9341 ApiTestFuzzer::Fuzz();
9342 args.GetReturnValue().Set(v8_num(42));
9346 static int shadow_y;
9347 static int shadow_y_setter_call_count;
9348 static int shadow_y_getter_call_count;
9351 static void ShadowYSetter(Local<String>,
9353 const v8::PropertyCallbackInfo<void>&) {
9354 shadow_y_setter_call_count++;
9359 static void ShadowYGetter(Local<String> name,
9360 const v8::PropertyCallbackInfo<v8::Value>& info) {
9361 ApiTestFuzzer::Fuzz();
9362 shadow_y_getter_call_count++;
9363 info.GetReturnValue().Set(v8_num(shadow_y));
9367 static void ShadowIndexedGet(uint32_t index,
9368 const v8::PropertyCallbackInfo<v8::Value>&) {
9372 static void ShadowNamedGet(Local<String> key,
9373 const v8::PropertyCallbackInfo<v8::Value>&) {
9377 THREADED_TEST(ShadowObject) {
9378 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9379 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
9381 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
9382 LocalContext context(NULL, global_template);
9384 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9385 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
9386 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
9387 Local<ObjectTemplate> proto = t->PrototypeTemplate();
9388 Local<ObjectTemplate> instance = t->InstanceTemplate();
9390 proto->Set(v8_str("f"),
9391 v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>()));
9392 proto->Set(v8_str("x"), v8_num(12));
9394 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9396 Local<Value> o = t->GetFunction()->NewInstance();
9397 context->Global()->Set(v8_str("__proto__"), o);
9399 Local<Value> value =
9400 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
9401 CHECK(value->IsBoolean());
9402 CHECK(!value->BooleanValue());
9404 value = Script::Compile(v8_str("x"))->Run();
9405 CHECK_EQ(12, value->Int32Value());
9407 value = Script::Compile(v8_str("f()"))->Run();
9408 CHECK_EQ(42, value->Int32Value());
9410 Script::Compile(v8_str("y = 43"))->Run();
9411 CHECK_EQ(1, shadow_y_setter_call_count);
9412 value = Script::Compile(v8_str("y"))->Run();
9413 CHECK_EQ(1, shadow_y_getter_call_count);
9414 CHECK_EQ(42, value->Int32Value());
9418 THREADED_TEST(HiddenPrototype) {
9419 LocalContext context;
9420 v8::HandleScope handle_scope(context->GetIsolate());
9422 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
9423 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9424 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9425 t1->SetHiddenPrototype(true);
9426 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9427 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9428 t2->SetHiddenPrototype(true);
9429 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9430 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9431 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9433 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9434 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9435 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9436 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9438 // Setting the prototype on an object skips hidden prototypes.
9439 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9440 o0->Set(v8_str("__proto__"), o1);
9441 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9442 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9443 o0->Set(v8_str("__proto__"), o2);
9444 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9445 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9446 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9447 o0->Set(v8_str("__proto__"), o3);
9448 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9449 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9450 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9451 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9453 // Getting the prototype of o0 should get the first visible one
9454 // which is o3. Therefore, z should not be defined on the prototype
9456 Local<Value> proto = o0->Get(v8_str("__proto__"));
9457 CHECK(proto->IsObject());
9458 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
9462 THREADED_TEST(HiddenPrototypeSet) {
9463 LocalContext context;
9464 v8::HandleScope handle_scope(context->GetIsolate());
9466 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New();
9467 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New();
9468 ht->SetHiddenPrototype(true);
9469 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New();
9470 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9472 Local<v8::Object> o = ot->GetFunction()->NewInstance();
9473 Local<v8::Object> h = ht->GetFunction()->NewInstance();
9474 Local<v8::Object> p = pt->GetFunction()->NewInstance();
9475 o->Set(v8_str("__proto__"), h);
9476 h->Set(v8_str("__proto__"), p);
9478 // Setting a property that exists on the hidden prototype goes there.
9479 o->Set(v8_str("x"), v8_num(7));
9480 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
9481 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
9482 CHECK(p->Get(v8_str("x"))->IsUndefined());
9484 // Setting a new property should not be forwarded to the hidden prototype.
9485 o->Set(v8_str("y"), v8_num(6));
9486 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
9487 CHECK(h->Get(v8_str("y"))->IsUndefined());
9488 CHECK(p->Get(v8_str("y"))->IsUndefined());
9490 // Setting a property that only exists on a prototype of the hidden prototype
9491 // is treated normally again.
9492 p->Set(v8_str("z"), v8_num(8));
9493 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
9494 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9495 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9496 o->Set(v8_str("z"), v8_num(9));
9497 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
9498 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9499 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9503 // Regression test for issue 2457.
9504 THREADED_TEST(HiddenPrototypeIdentityHash) {
9505 LocalContext context;
9506 v8::HandleScope handle_scope(context->GetIsolate());
9508 Handle<FunctionTemplate> t = FunctionTemplate::New();
9509 t->SetHiddenPrototype(true);
9510 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
9511 Handle<Object> p = t->GetFunction()->NewInstance();
9512 Handle<Object> o = Object::New();
9515 int hash = o->GetIdentityHash();
9517 o->Set(v8_str("foo"), v8_num(42));
9518 ASSERT_EQ(hash, o->GetIdentityHash());
9522 THREADED_TEST(SetPrototype) {
9523 LocalContext context;
9524 v8::HandleScope handle_scope(context->GetIsolate());
9526 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
9527 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9528 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9529 t1->SetHiddenPrototype(true);
9530 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9531 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9532 t2->SetHiddenPrototype(true);
9533 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9534 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9535 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9537 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9538 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9539 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9540 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9542 // Setting the prototype on an object does not skip hidden prototypes.
9543 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9544 CHECK(o0->SetPrototype(o1));
9545 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9546 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9547 CHECK(o1->SetPrototype(o2));
9548 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9549 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9550 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9551 CHECK(o2->SetPrototype(o3));
9552 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9553 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9554 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9555 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9557 // Getting the prototype of o0 should get the first visible one
9558 // which is o3. Therefore, z should not be defined on the prototype
9560 Local<Value> proto = o0->Get(v8_str("__proto__"));
9561 CHECK(proto->IsObject());
9562 CHECK_EQ(proto.As<v8::Object>(), o3);
9564 // However, Object::GetPrototype ignores hidden prototype.
9565 Local<Value> proto0 = o0->GetPrototype();
9566 CHECK(proto0->IsObject());
9567 CHECK_EQ(proto0.As<v8::Object>(), o1);
9569 Local<Value> proto1 = o1->GetPrototype();
9570 CHECK(proto1->IsObject());
9571 CHECK_EQ(proto1.As<v8::Object>(), o2);
9573 Local<Value> proto2 = o2->GetPrototype();
9574 CHECK(proto2->IsObject());
9575 CHECK_EQ(proto2.As<v8::Object>(), o3);
9579 // Getting property names of an object with a prototype chain that
9580 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
9581 // crash the runtime.
9582 THREADED_TEST(Regress91517) {
9583 i::FLAG_allow_natives_syntax = true;
9584 LocalContext context;
9585 v8::HandleScope handle_scope(context->GetIsolate());
9587 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9588 t1->SetHiddenPrototype(true);
9589 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
9590 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9591 t2->SetHiddenPrototype(true);
9592 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
9593 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
9594 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
9595 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9596 t3->SetHiddenPrototype(true);
9597 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
9598 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
9599 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
9601 // Force dictionary-based properties.
9602 i::ScopedVector<char> name_buf(1024);
9603 for (int i = 1; i <= 1000; i++) {
9604 i::OS::SNPrintF(name_buf, "sdf%d", i);
9605 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
9608 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9609 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9610 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9611 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
9613 // Create prototype chain of hidden prototypes.
9614 CHECK(o4->SetPrototype(o3));
9615 CHECK(o3->SetPrototype(o2));
9616 CHECK(o2->SetPrototype(o1));
9618 // Call the runtime version of GetLocalPropertyNames() on the natively
9619 // created object through JavaScript.
9620 context->Global()->Set(v8_str("obj"), o4);
9621 CompileRun("var names = %GetLocalPropertyNames(obj, true);");
9623 ExpectInt32("names.length", 1006);
9624 ExpectTrue("names.indexOf(\"baz\") >= 0");
9625 ExpectTrue("names.indexOf(\"boo\") >= 0");
9626 ExpectTrue("names.indexOf(\"foo\") >= 0");
9627 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
9628 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
9629 ExpectFalse("names[1005] == undefined");
9633 THREADED_TEST(FunctionReadOnlyPrototype) {
9634 LocalContext context;
9635 v8::HandleScope handle_scope(context->GetIsolate());
9637 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9638 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
9639 t1->ReadOnlyPrototype();
9640 context->Global()->Set(v8_str("func1"), t1->GetFunction());
9641 // Configured value of ReadOnly flag.
9644 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
9645 " return (descriptor['writable'] == false);"
9646 "})()")->BooleanValue());
9647 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
9649 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
9651 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9652 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
9653 context->Global()->Set(v8_str("func2"), t2->GetFunction());
9654 // Default value of ReadOnly flag.
9657 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
9658 " return (descriptor['writable'] == true);"
9659 "})()")->BooleanValue());
9660 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
9664 THREADED_TEST(SetPrototypeThrows) {
9665 LocalContext context;
9666 v8::HandleScope handle_scope(context->GetIsolate());
9668 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9670 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
9671 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
9673 CHECK(o0->SetPrototype(o1));
9674 // If setting the prototype leads to the cycle, SetPrototype should
9675 // return false and keep VM in sane state.
9676 v8::TryCatch try_catch;
9677 CHECK(!o1->SetPrototype(o0));
9678 CHECK(!try_catch.HasCaught());
9679 ASSERT(!i::Isolate::Current()->has_pending_exception());
9681 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
9685 THREADED_TEST(FunctionRemovePrototype) {
9686 LocalContext context;
9687 v8::HandleScope handle_scope(context->GetIsolate());
9689 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9690 t1->RemovePrototype();
9691 Local<v8::Function> fun = t1->GetFunction();
9692 context->Global()->Set(v8_str("fun"), fun);
9693 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
9695 v8::TryCatch try_catch;
9696 CompileRun("new fun()");
9697 CHECK(try_catch.HasCaught());
9701 CHECK(try_catch.HasCaught());
9705 THREADED_TEST(GetterSetterExceptions) {
9706 LocalContext context;
9707 v8::HandleScope handle_scope(context->GetIsolate());
9709 "function Foo() { };"
9710 "function Throw() { throw 5; };"
9712 "x.__defineSetter__('set', Throw);"
9713 "x.__defineGetter__('get', Throw);");
9714 Local<v8::Object> x =
9715 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
9716 v8::TryCatch try_catch;
9717 x->Set(v8_str("set"), v8::Integer::New(8));
9718 x->Get(v8_str("get"));
9719 x->Set(v8_str("set"), v8::Integer::New(8));
9720 x->Get(v8_str("get"));
9721 x->Set(v8_str("set"), v8::Integer::New(8));
9722 x->Get(v8_str("get"));
9723 x->Set(v8_str("set"), v8::Integer::New(8));
9724 x->Get(v8_str("get"));
9728 THREADED_TEST(Constructor) {
9729 LocalContext context;
9730 v8::HandleScope handle_scope(context->GetIsolate());
9731 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9732 templ->SetClassName(v8_str("Fun"));
9733 Local<Function> cons = templ->GetFunction();
9734 context->Global()->Set(v8_str("Fun"), cons);
9735 Local<v8::Object> inst = cons->NewInstance();
9736 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
9737 CHECK(obj->IsJSObject());
9738 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
9739 CHECK(value->BooleanValue());
9743 static void ConstructorCallback(
9744 const v8::FunctionCallbackInfo<v8::Value>& args) {
9745 ApiTestFuzzer::Fuzz();
9748 if (args.IsConstructCall()) {
9749 Local<Object> Holder = args.Holder();
9750 This = Object::New();
9751 Local<Value> proto = Holder->GetPrototype();
9752 if (proto->IsObject()) {
9753 This->SetPrototype(proto);
9759 This->Set(v8_str("a"), args[0]);
9760 args.GetReturnValue().Set(This);
9764 static void FakeConstructorCallback(
9765 const v8::FunctionCallbackInfo<v8::Value>& args) {
9766 ApiTestFuzzer::Fuzz();
9767 args.GetReturnValue().Set(args[0]);
9771 THREADED_TEST(ConstructorForObject) {
9772 LocalContext context;
9773 v8::HandleScope handle_scope(context->GetIsolate());
9775 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9776 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
9777 Local<Object> instance = instance_template->NewInstance();
9778 context->Global()->Set(v8_str("obj"), instance);
9779 v8::TryCatch try_catch;
9781 CHECK(!try_catch.HasCaught());
9783 // Call the Object's constructor with a 32-bit signed integer.
9784 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
9785 CHECK(!try_catch.HasCaught());
9786 CHECK(value->IsInt32());
9787 CHECK_EQ(28, value->Int32Value());
9789 Local<Value> args1[] = { v8_num(28) };
9790 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
9791 CHECK(value_obj1->IsObject());
9792 Local<Object> object1 = Local<Object>::Cast(value_obj1);
9793 value = object1->Get(v8_str("a"));
9794 CHECK(value->IsInt32());
9795 CHECK(!try_catch.HasCaught());
9796 CHECK_EQ(28, value->Int32Value());
9798 // Call the Object's constructor with a String.
9800 "(function() { var o = new obj('tipli'); return o.a; })()");
9801 CHECK(!try_catch.HasCaught());
9802 CHECK(value->IsString());
9803 String::Utf8Value string_value1(value->ToString());
9804 CHECK_EQ("tipli", *string_value1);
9806 Local<Value> args2[] = { v8_str("tipli") };
9807 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
9808 CHECK(value_obj2->IsObject());
9809 Local<Object> object2 = Local<Object>::Cast(value_obj2);
9810 value = object2->Get(v8_str("a"));
9811 CHECK(!try_catch.HasCaught());
9812 CHECK(value->IsString());
9813 String::Utf8Value string_value2(value->ToString());
9814 CHECK_EQ("tipli", *string_value2);
9816 // Call the Object's constructor with a Boolean.
9817 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
9818 CHECK(!try_catch.HasCaught());
9819 CHECK(value->IsBoolean());
9820 CHECK_EQ(true, value->BooleanValue());
9822 Handle<Value> args3[] = { v8::True() };
9823 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
9824 CHECK(value_obj3->IsObject());
9825 Local<Object> object3 = Local<Object>::Cast(value_obj3);
9826 value = object3->Get(v8_str("a"));
9827 CHECK(!try_catch.HasCaught());
9828 CHECK(value->IsBoolean());
9829 CHECK_EQ(true, value->BooleanValue());
9831 // Call the Object's constructor with undefined.
9832 Handle<Value> args4[] = { v8::Undefined() };
9833 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
9834 CHECK(value_obj4->IsObject());
9835 Local<Object> object4 = Local<Object>::Cast(value_obj4);
9836 value = object4->Get(v8_str("a"));
9837 CHECK(!try_catch.HasCaught());
9838 CHECK(value->IsUndefined());
9840 // Call the Object's constructor with null.
9841 Handle<Value> args5[] = { v8::Null() };
9842 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
9843 CHECK(value_obj5->IsObject());
9844 Local<Object> object5 = Local<Object>::Cast(value_obj5);
9845 value = object5->Get(v8_str("a"));
9846 CHECK(!try_catch.HasCaught());
9847 CHECK(value->IsNull());
9850 // Check exception handling when there is no constructor set for the Object.
9851 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9852 Local<Object> instance = instance_template->NewInstance();
9853 context->Global()->Set(v8_str("obj2"), instance);
9854 v8::TryCatch try_catch;
9856 CHECK(!try_catch.HasCaught());
9858 value = CompileRun("new obj2(28)");
9859 CHECK(try_catch.HasCaught());
9860 String::Utf8Value exception_value1(try_catch.Exception());
9861 CHECK_EQ("TypeError: object is not a function", *exception_value1);
9864 Local<Value> args[] = { v8_num(29) };
9865 value = instance->CallAsConstructor(1, args);
9866 CHECK(try_catch.HasCaught());
9867 String::Utf8Value exception_value2(try_catch.Exception());
9868 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
9872 // Check the case when constructor throws exception.
9873 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9874 instance_template->SetCallAsFunctionHandler(ThrowValue);
9875 Local<Object> instance = instance_template->NewInstance();
9876 context->Global()->Set(v8_str("obj3"), instance);
9877 v8::TryCatch try_catch;
9879 CHECK(!try_catch.HasCaught());
9881 value = CompileRun("new obj3(22)");
9882 CHECK(try_catch.HasCaught());
9883 String::Utf8Value exception_value1(try_catch.Exception());
9884 CHECK_EQ("22", *exception_value1);
9887 Local<Value> args[] = { v8_num(23) };
9888 value = instance->CallAsConstructor(1, args);
9889 CHECK(try_catch.HasCaught());
9890 String::Utf8Value exception_value2(try_catch.Exception());
9891 CHECK_EQ("23", *exception_value2);
9895 // Check whether constructor returns with an object or non-object.
9896 { Local<FunctionTemplate> function_template =
9897 FunctionTemplate::New(FakeConstructorCallback);
9898 Local<Function> function = function_template->GetFunction();
9899 Local<Object> instance1 = function;
9900 context->Global()->Set(v8_str("obj4"), instance1);
9901 v8::TryCatch try_catch;
9903 CHECK(!try_catch.HasCaught());
9905 CHECK(instance1->IsObject());
9906 CHECK(instance1->IsFunction());
9908 value = CompileRun("new obj4(28)");
9909 CHECK(!try_catch.HasCaught());
9910 CHECK(value->IsObject());
9912 Local<Value> args1[] = { v8_num(28) };
9913 value = instance1->CallAsConstructor(1, args1);
9914 CHECK(!try_catch.HasCaught());
9915 CHECK(value->IsObject());
9917 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9918 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
9919 Local<Object> instance2 = instance_template->NewInstance();
9920 context->Global()->Set(v8_str("obj5"), instance2);
9921 CHECK(!try_catch.HasCaught());
9923 CHECK(instance2->IsObject());
9924 CHECK(!instance2->IsFunction());
9926 value = CompileRun("new obj5(28)");
9927 CHECK(!try_catch.HasCaught());
9928 CHECK(!value->IsObject());
9930 Local<Value> args2[] = { v8_num(28) };
9931 value = instance2->CallAsConstructor(1, args2);
9932 CHECK(!try_catch.HasCaught());
9933 CHECK(!value->IsObject());
9938 THREADED_TEST(FunctionDescriptorException) {
9939 LocalContext context;
9940 v8::HandleScope handle_scope(context->GetIsolate());
9941 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9942 templ->SetClassName(v8_str("Fun"));
9943 Local<Function> cons = templ->GetFunction();
9944 context->Global()->Set(v8_str("Fun"), cons);
9945 Local<Value> value = CompileRun(
9948 " (new Fun()).blah()"
9950 " var str = String(e);"
9951 " if (str.indexOf('TypeError') == -1) return 1;"
9952 " if (str.indexOf('[object Fun]') != -1) return 2;"
9953 " if (str.indexOf('#<Fun>') == -1) return 3;"
9959 CHECK_EQ(0, value->Int32Value());
9963 THREADED_TEST(EvalAliasedDynamic) {
9964 LocalContext current;
9965 v8::HandleScope scope(current->GetIsolate());
9967 // Tests where aliased eval can only be resolved dynamically.
9968 Local<Script> script =
9969 Script::Compile(v8_str("function f(x) { "
9971 " with (x) { return eval('foo'); }"
9974 "result1 = f(new Object());"
9975 "result2 = f(this);"
9976 "var x = new Object();"
9977 "x.eval = function(x) { return 1; };"
9978 "result3 = f(x);"));
9980 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
9981 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
9982 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
9984 v8::TryCatch try_catch;
9986 Script::Compile(v8_str("function f(x) { "
9988 " with (x) { return eval('bar'); }"
9990 "result4 = f(this)"));
9992 CHECK(!try_catch.HasCaught());
9993 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
9999 THREADED_TEST(CrossEval) {
10000 v8::HandleScope scope(v8::Isolate::GetCurrent());
10001 LocalContext other;
10002 LocalContext current;
10004 Local<String> token = v8_str("<security token>");
10005 other->SetSecurityToken(token);
10006 current->SetSecurityToken(token);
10008 // Set up reference from current to other.
10009 current->Global()->Set(v8_str("other"), other->Global());
10011 // Check that new variables are introduced in other context.
10012 Local<Script> script =
10013 Script::Compile(v8_str("other.eval('var foo = 1234')"));
10015 Local<Value> foo = other->Global()->Get(v8_str("foo"));
10016 CHECK_EQ(1234, foo->Int32Value());
10017 CHECK(!current->Global()->Has(v8_str("foo")));
10019 // Check that writing to non-existing properties introduces them in
10020 // the other context.
10022 Script::Compile(v8_str("other.eval('na = 1234')"));
10024 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10025 CHECK(!current->Global()->Has(v8_str("na")));
10027 // Check that global variables in current context are not visible in other
10029 v8::TryCatch try_catch;
10031 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
10032 Local<Value> result = script->Run();
10033 CHECK(try_catch.HasCaught());
10036 // Check that local variables in current context are not visible in other
10039 Script::Compile(v8_str("(function() { "
10041 " return other.eval('baz');"
10043 result = script->Run();
10044 CHECK(try_catch.HasCaught());
10047 // Check that global variables in the other environment are visible
10048 // when evaluting code.
10049 other->Global()->Set(v8_str("bis"), v8_num(1234));
10050 script = Script::Compile(v8_str("other.eval('bis')"));
10051 CHECK_EQ(1234, script->Run()->Int32Value());
10052 CHECK(!try_catch.HasCaught());
10054 // Check that the 'this' pointer points to the global object evaluating
10056 other->Global()->Set(v8_str("t"), other->Global());
10057 script = Script::Compile(v8_str("other.eval('this == t')"));
10058 result = script->Run();
10059 CHECK(result->IsTrue());
10060 CHECK(!try_catch.HasCaught());
10062 // Check that variables introduced in with-statement are not visible in
10065 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
10066 result = script->Run();
10067 CHECK(try_catch.HasCaught());
10070 // Check that you cannot use 'eval.call' with another object than the
10071 // current global object.
10073 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
10074 result = script->Run();
10075 CHECK(try_catch.HasCaught());
10079 // Test that calling eval in a context which has been detached from
10080 // its global throws an exception. This behavior is consistent with
10081 // other JavaScript implementations.
10082 THREADED_TEST(EvalInDetachedGlobal) {
10083 v8::Isolate* isolate = v8::Isolate::GetCurrent();
10084 v8::HandleScope scope(isolate);
10086 v8::Local<Context> context0 = Context::New(isolate);
10087 v8::Local<Context> context1 = Context::New(isolate);
10089 // Set up function in context0 that uses eval from context0.
10091 v8::Handle<v8::Value> fun =
10092 CompileRun("var x = 42;"
10095 " return function(s) { return e(s); }"
10099 // Put the function into context1 and call it before and after
10100 // detaching the global. Before detaching, the call succeeds and
10101 // after detaching and exception is thrown.
10103 context1->Global()->Set(v8_str("fun"), fun);
10104 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10105 CHECK_EQ(42, x_value->Int32Value());
10106 context0->DetachGlobal();
10107 v8::TryCatch catcher;
10108 x_value = CompileRun("fun('x')");
10109 CHECK(x_value.IsEmpty());
10110 CHECK(catcher.HasCaught());
10115 THREADED_TEST(CrossLazyLoad) {
10116 v8::HandleScope scope(v8::Isolate::GetCurrent());
10117 LocalContext other;
10118 LocalContext current;
10120 Local<String> token = v8_str("<security token>");
10121 other->SetSecurityToken(token);
10122 current->SetSecurityToken(token);
10124 // Set up reference from current to other.
10125 current->Global()->Set(v8_str("other"), other->Global());
10127 // Trigger lazy loading in other context.
10128 Local<Script> script =
10129 Script::Compile(v8_str("other.eval('new Date(42)')"));
10130 Local<Value> value = script->Run();
10131 CHECK_EQ(42.0, value->NumberValue());
10135 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10136 ApiTestFuzzer::Fuzz();
10137 if (args.IsConstructCall()) {
10138 if (args[0]->IsInt32()) {
10139 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10144 args.GetReturnValue().Set(args[0]);
10148 // Test that a call handler can be set for objects which will allow
10149 // non-function objects created through the API to be called as
10151 THREADED_TEST(CallAsFunction) {
10152 LocalContext context;
10153 v8::HandleScope scope(context->GetIsolate());
10155 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
10156 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10157 instance_template->SetCallAsFunctionHandler(call_as_function);
10158 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10159 context->Global()->Set(v8_str("obj"), instance);
10160 v8::TryCatch try_catch;
10161 Local<Value> value;
10162 CHECK(!try_catch.HasCaught());
10164 value = CompileRun("obj(42)");
10165 CHECK(!try_catch.HasCaught());
10166 CHECK_EQ(42, value->Int32Value());
10168 value = CompileRun("(function(o){return o(49)})(obj)");
10169 CHECK(!try_catch.HasCaught());
10170 CHECK_EQ(49, value->Int32Value());
10172 // test special case of call as function
10173 value = CompileRun("[obj]['0'](45)");
10174 CHECK(!try_catch.HasCaught());
10175 CHECK_EQ(45, value->Int32Value());
10177 value = CompileRun("obj.call = Function.prototype.call;"
10178 "obj.call(null, 87)");
10179 CHECK(!try_catch.HasCaught());
10180 CHECK_EQ(87, value->Int32Value());
10182 // Regression tests for bug #1116356: Calling call through call/apply
10183 // must work for non-function receivers.
10184 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10185 value = CompileRun(apply_99);
10186 CHECK(!try_catch.HasCaught());
10187 CHECK_EQ(99, value->Int32Value());
10189 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10190 value = CompileRun(call_17);
10191 CHECK(!try_catch.HasCaught());
10192 CHECK_EQ(17, value->Int32Value());
10194 // Check that the call-as-function handler can be called through
10196 value = CompileRun("new obj(43)");
10197 CHECK(!try_catch.HasCaught());
10198 CHECK_EQ(-43, value->Int32Value());
10200 // Check that the call-as-function handler can be called through
10202 v8::Handle<Value> args[] = { v8_num(28) };
10203 value = instance->CallAsFunction(instance, 1, args);
10204 CHECK(!try_catch.HasCaught());
10205 CHECK_EQ(28, value->Int32Value());
10208 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
10209 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10210 USE(instance_template);
10211 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10212 context->Global()->Set(v8_str("obj2"), instance);
10213 v8::TryCatch try_catch;
10214 Local<Value> value;
10215 CHECK(!try_catch.HasCaught());
10217 // Call an object without call-as-function handler through the JS
10218 value = CompileRun("obj2(28)");
10219 CHECK(value.IsEmpty());
10220 CHECK(try_catch.HasCaught());
10221 String::Utf8Value exception_value1(try_catch.Exception());
10222 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
10223 *exception_value1);
10226 // Call an object without call-as-function handler through the API
10227 value = CompileRun("obj2(28)");
10228 v8::Handle<Value> args[] = { v8_num(28) };
10229 value = instance->CallAsFunction(instance, 1, args);
10230 CHECK(value.IsEmpty());
10231 CHECK(try_catch.HasCaught());
10232 String::Utf8Value exception_value2(try_catch.Exception());
10233 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10237 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
10238 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10239 instance_template->SetCallAsFunctionHandler(ThrowValue);
10240 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10241 context->Global()->Set(v8_str("obj3"), instance);
10242 v8::TryCatch try_catch;
10243 Local<Value> value;
10244 CHECK(!try_catch.HasCaught());
10246 // Catch the exception which is thrown by call-as-function handler
10247 value = CompileRun("obj3(22)");
10248 CHECK(try_catch.HasCaught());
10249 String::Utf8Value exception_value1(try_catch.Exception());
10250 CHECK_EQ("22", *exception_value1);
10253 v8::Handle<Value> args[] = { v8_num(23) };
10254 value = instance->CallAsFunction(instance, 1, args);
10255 CHECK(try_catch.HasCaught());
10256 String::Utf8Value exception_value2(try_catch.Exception());
10257 CHECK_EQ("23", *exception_value2);
10263 // Check whether a non-function object is callable.
10264 THREADED_TEST(CallableObject) {
10265 LocalContext context;
10266 v8::HandleScope scope(context->GetIsolate());
10268 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10269 instance_template->SetCallAsFunctionHandler(call_as_function);
10270 Local<Object> instance = instance_template->NewInstance();
10271 v8::TryCatch try_catch;
10273 CHECK(instance->IsCallable());
10274 CHECK(!try_catch.HasCaught());
10277 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10278 Local<Object> instance = instance_template->NewInstance();
10279 v8::TryCatch try_catch;
10281 CHECK(!instance->IsCallable());
10282 CHECK(!try_catch.HasCaught());
10285 { Local<FunctionTemplate> function_template =
10286 FunctionTemplate::New(call_as_function);
10287 Local<Function> function = function_template->GetFunction();
10288 Local<Object> instance = function;
10289 v8::TryCatch try_catch;
10291 CHECK(instance->IsCallable());
10292 CHECK(!try_catch.HasCaught());
10295 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
10296 Local<Function> function = function_template->GetFunction();
10297 Local<Object> instance = function;
10298 v8::TryCatch try_catch;
10300 CHECK(instance->IsCallable());
10301 CHECK(!try_catch.HasCaught());
10306 static int CountHandles() {
10307 return v8::HandleScope::NumberOfHandles();
10311 static int Recurse(int depth, int iterations) {
10312 v8::HandleScope scope(v8::Isolate::GetCurrent());
10313 if (depth == 0) return CountHandles();
10314 for (int i = 0; i < iterations; i++) {
10315 Local<v8::Number> n(v8::Integer::New(42));
10317 return Recurse(depth - 1, iterations);
10321 THREADED_TEST(HandleIteration) {
10322 static const int kIterations = 500;
10323 static const int kNesting = 200;
10324 CHECK_EQ(0, CountHandles());
10326 v8::HandleScope scope1(v8::Isolate::GetCurrent());
10327 CHECK_EQ(0, CountHandles());
10328 for (int i = 0; i < kIterations; i++) {
10329 Local<v8::Number> n(v8::Integer::New(42));
10330 CHECK_EQ(i + 1, CountHandles());
10333 CHECK_EQ(kIterations, CountHandles());
10335 v8::HandleScope scope2(v8::Isolate::GetCurrent());
10336 for (int j = 0; j < kIterations; j++) {
10337 Local<v8::Number> n(v8::Integer::New(42));
10338 CHECK_EQ(j + 1 + kIterations, CountHandles());
10341 CHECK_EQ(kIterations, CountHandles());
10343 CHECK_EQ(0, CountHandles());
10344 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
10348 static void InterceptorHasOwnPropertyGetter(
10349 Local<String> name,
10350 const v8::PropertyCallbackInfo<v8::Value>& info) {
10351 ApiTestFuzzer::Fuzz();
10355 THREADED_TEST(InterceptorHasOwnProperty) {
10356 LocalContext context;
10357 v8::HandleScope scope(context->GetIsolate());
10358 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10359 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
10360 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
10361 Local<Function> function = fun_templ->GetFunction();
10362 context->Global()->Set(v8_str("constructor"), function);
10363 v8::Handle<Value> value = CompileRun(
10364 "var o = new constructor();"
10365 "o.hasOwnProperty('ostehaps');");
10366 CHECK_EQ(false, value->BooleanValue());
10367 value = CompileRun(
10369 "o.hasOwnProperty('ostehaps');");
10370 CHECK_EQ(true, value->BooleanValue());
10371 value = CompileRun(
10372 "var p = new constructor();"
10373 "p.hasOwnProperty('ostehaps');");
10374 CHECK_EQ(false, value->BooleanValue());
10378 static void InterceptorHasOwnPropertyGetterGC(
10379 Local<String> name,
10380 const v8::PropertyCallbackInfo<v8::Value>& info) {
10381 ApiTestFuzzer::Fuzz();
10382 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10386 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
10387 LocalContext context;
10388 v8::HandleScope scope(context->GetIsolate());
10389 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10390 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
10391 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
10392 Local<Function> function = fun_templ->GetFunction();
10393 context->Global()->Set(v8_str("constructor"), function);
10394 // Let's first make some stuff so we can be sure to get a good GC.
10396 "function makestr(size) {"
10398 " case 1: return 'f';"
10399 " case 2: return 'fo';"
10400 " case 3: return 'foo';"
10402 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
10404 "var x = makestr(12345);"
10405 "x = makestr(31415);"
10406 "x = makestr(23456);");
10407 v8::Handle<Value> value = CompileRun(
10408 "var o = new constructor();"
10409 "o.__proto__ = new String(x);"
10410 "o.hasOwnProperty('ostehaps');");
10411 CHECK_EQ(false, value->BooleanValue());
10415 typedef void (*NamedPropertyGetter)(
10416 Local<String> property,
10417 const v8::PropertyCallbackInfo<v8::Value>& info);
10420 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
10421 const char* source,
10423 v8::HandleScope scope(v8::Isolate::GetCurrent());
10424 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10425 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
10426 LocalContext context;
10427 context->Global()->Set(v8_str("o"), templ->NewInstance());
10428 v8::Handle<Value> value = CompileRun(source);
10429 CHECK_EQ(expected, value->Int32Value());
10433 static void InterceptorLoadICGetter(
10434 Local<String> name,
10435 const v8::PropertyCallbackInfo<v8::Value>& info) {
10436 ApiTestFuzzer::Fuzz();
10437 v8::Isolate* isolate = v8::Isolate::GetCurrent();
10438 CHECK_EQ(isolate, info.GetIsolate());
10439 CHECK_EQ(v8_str("data"), info.Data());
10440 CHECK_EQ(v8_str("x"), name);
10441 info.GetReturnValue().Set(v8::Integer::New(42));
10445 // This test should hit the load IC for the interceptor case.
10446 THREADED_TEST(InterceptorLoadIC) {
10447 CheckInterceptorLoadIC(InterceptorLoadICGetter,
10449 "for (var i = 0; i < 1000; i++) {"
10456 // Below go several tests which verify that JITing for various
10457 // configurations of interceptor and explicit fields works fine
10458 // (those cases are special cased to get better performance).
10460 static void InterceptorLoadXICGetter(
10461 Local<String> name,
10462 const v8::PropertyCallbackInfo<v8::Value>& info) {
10463 ApiTestFuzzer::Fuzz();
10464 info.GetReturnValue().Set(
10465 v8_str("x")->Equals(name) ?
10466 v8::Handle<v8::Value>(v8::Integer::New(42)) :
10467 v8::Handle<v8::Value>());
10471 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
10472 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10475 "for (var i = 0; i < 1000; i++) {"
10482 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
10483 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10485 "o.__proto__ = { 'y': 239 };"
10486 "for (var i = 0; i < 1000; i++) {"
10487 " result = o.y + o.x;"
10493 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
10494 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10496 "o.__proto__.y = 239;"
10497 "for (var i = 0; i < 1000; i++) {"
10498 " result = o.y + o.x;"
10504 THREADED_TEST(InterceptorLoadICUndefined) {
10505 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10507 "for (var i = 0; i < 1000; i++) {"
10508 " result = (o.y == undefined) ? 239 : 42;"
10514 THREADED_TEST(InterceptorLoadICWithOverride) {
10515 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10516 "fst = new Object(); fst.__proto__ = o;"
10517 "snd = new Object(); snd.__proto__ = fst;"
10519 "for (var i = 0; i < 1000; i++) {"
10520 " result1 = snd.x;"
10524 "for (var i = 0; i < 1000; i++) {"
10527 "result + result1",
10532 // Test the case when we stored field into
10533 // a stub, but interceptor produced value on its own.
10534 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
10535 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10536 "proto = new Object();"
10537 "o.__proto__ = proto;"
10539 "for (var i = 0; i < 1000; i++) {"
10541 // Now it should be ICed and keep a reference to x defined on proto
10544 "for (var i = 0; i < 1000; i++) {"
10552 // Test the case when we stored field into
10553 // a stub, but it got invalidated later on.
10554 THREADED_TEST(InterceptorLoadICInvalidatedField) {
10555 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10556 "proto1 = new Object();"
10557 "proto2 = new Object();"
10558 "o.__proto__ = proto1;"
10559 "proto1.__proto__ = proto2;"
10561 "for (var i = 0; i < 1000; i++) {"
10563 // Now it should be ICed and keep a reference to y defined on proto2
10567 "for (var i = 0; i < 1000; i++) {"
10575 static int interceptor_load_not_handled_calls = 0;
10576 static void InterceptorLoadNotHandled(
10577 Local<String> name,
10578 const v8::PropertyCallbackInfo<v8::Value>& info) {
10579 ++interceptor_load_not_handled_calls;
10583 // Test how post-interceptor lookups are done in the non-cacheable
10584 // case: the interceptor should not be invoked during this lookup.
10585 THREADED_TEST(InterceptorLoadICPostInterceptor) {
10586 interceptor_load_not_handled_calls = 0;
10587 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
10588 "receiver = new Object();"
10589 "receiver.__proto__ = o;"
10590 "proto = new Object();"
10591 "/* Make proto a slow-case object. */"
10592 "for (var i = 0; i < 1000; i++) {"
10593 " proto[\"xxxxxxxx\" + i] = [];"
10596 "o.__proto__ = proto;"
10598 "for (var i = 0; i < 1000; i++) {"
10599 " result += receiver.x;"
10603 CHECK_EQ(1000, interceptor_load_not_handled_calls);
10607 // Test the case when we stored field into
10608 // a stub, but it got invalidated later on due to override on
10609 // global object which is between interceptor and fields' holders.
10610 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
10611 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10612 "o.__proto__ = this;" // set a global to be a proto of o.
10613 "this.__proto__.y = 239;"
10614 "for (var i = 0; i < 10; i++) {"
10615 " if (o.y != 239) throw 'oops: ' + o.y;"
10616 // Now it should be ICed and keep a reference to y defined on field_holder.
10618 "this.y = 42;" // Assign on a global.
10620 "for (var i = 0; i < 10; i++) {"
10628 static void SetOnThis(Local<String> name,
10629 Local<Value> value,
10630 const v8::PropertyCallbackInfo<void>& info) {
10631 info.This()->ForceSet(name, value);
10635 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
10636 v8::HandleScope scope(v8::Isolate::GetCurrent());
10637 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10638 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10639 templ->SetAccessor(v8_str("y"), Return239Callback);
10640 LocalContext context;
10641 context->Global()->Set(v8_str("o"), templ->NewInstance());
10643 // Check the case when receiver and interceptor's holder
10644 // are the same objects.
10645 v8::Handle<Value> value = CompileRun(
10647 "for (var i = 0; i < 7; i++) {"
10650 CHECK_EQ(239, value->Int32Value());
10652 // Check the case when interceptor's holder is in proto chain
10654 value = CompileRun(
10655 "r = { __proto__: o };"
10657 "for (var i = 0; i < 7; i++) {"
10660 CHECK_EQ(239, value->Int32Value());
10664 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
10665 v8::HandleScope scope(v8::Isolate::GetCurrent());
10666 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10667 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10668 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10669 templ_p->SetAccessor(v8_str("y"), Return239Callback);
10671 LocalContext context;
10672 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10673 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10675 // Check the case when receiver and interceptor's holder
10676 // are the same objects.
10677 v8::Handle<Value> value = CompileRun(
10680 "for (var i = 0; i < 7; i++) {"
10681 " result = o.x + o.y;"
10683 CHECK_EQ(239 + 42, value->Int32Value());
10685 // Check the case when interceptor's holder is in proto chain
10687 value = CompileRun(
10688 "r = { __proto__: o };"
10690 "for (var i = 0; i < 7; i++) {"
10691 " result = r.x + r.y;"
10693 CHECK_EQ(239 + 42, value->Int32Value());
10697 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
10698 v8::HandleScope scope(v8::Isolate::GetCurrent());
10699 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10700 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10701 templ->SetAccessor(v8_str("y"), Return239Callback);
10703 LocalContext context;
10704 context->Global()->Set(v8_str("o"), templ->NewInstance());
10706 v8::Handle<Value> value = CompileRun(
10707 "fst = new Object(); fst.__proto__ = o;"
10708 "snd = new Object(); snd.__proto__ = fst;"
10710 "for (var i = 0; i < 7; i++) {"
10711 " result1 = snd.x;"
10715 "for (var i = 0; i < 7; i++) {"
10718 "result + result1");
10719 CHECK_EQ(239 + 42, value->Int32Value());
10723 // Test the case when we stored callback into
10724 // a stub, but interceptor produced value on its own.
10725 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
10726 v8::HandleScope scope(v8::Isolate::GetCurrent());
10727 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10728 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10729 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10730 templ_p->SetAccessor(v8_str("y"), Return239Callback);
10732 LocalContext context;
10733 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10734 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10736 v8::Handle<Value> value = CompileRun(
10738 "for (var i = 0; i < 7; i++) {"
10740 // Now it should be ICed and keep a reference to x defined on p
10743 "for (var i = 0; i < 7; i++) {"
10747 CHECK_EQ(42 * 7, value->Int32Value());
10751 // Test the case when we stored callback into
10752 // a stub, but it got invalidated later on.
10753 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
10754 v8::HandleScope scope(v8::Isolate::GetCurrent());
10755 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10756 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10757 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10758 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
10760 LocalContext context;
10761 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10762 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10764 v8::Handle<Value> value = CompileRun(
10765 "inbetween = new Object();"
10766 "o.__proto__ = inbetween;"
10767 "inbetween.__proto__ = p;"
10768 "for (var i = 0; i < 10; i++) {"
10770 // Now it should be ICed and keep a reference to y defined on p
10772 "inbetween.y = 42;"
10774 "for (var i = 0; i < 10; i++) {"
10778 CHECK_EQ(42 * 10, value->Int32Value());
10782 // Test the case when we stored callback into
10783 // a stub, but it got invalidated later on due to override on
10784 // global object which is between interceptor and callbacks' holders.
10785 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
10786 v8::HandleScope scope(v8::Isolate::GetCurrent());
10787 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10788 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10789 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10790 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
10792 LocalContext context;
10793 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10794 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10796 v8::Handle<Value> value = CompileRun(
10797 "o.__proto__ = this;"
10798 "this.__proto__ = p;"
10799 "for (var i = 0; i < 10; i++) {"
10800 " if (o.y != 239) throw 'oops: ' + o.y;"
10801 // Now it should be ICed and keep a reference to y defined on p
10805 "for (var i = 0; i < 10; i++) {"
10809 CHECK_EQ(42 * 10, value->Int32Value());
10813 static void InterceptorLoadICGetter0(
10814 Local<String> name,
10815 const v8::PropertyCallbackInfo<v8::Value>& info) {
10816 ApiTestFuzzer::Fuzz();
10817 CHECK(v8_str("x")->Equals(name));
10818 info.GetReturnValue().Set(v8::Integer::New(0));
10822 THREADED_TEST(InterceptorReturningZero) {
10823 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
10824 "o.x == undefined ? 1 : 0",
10829 static void InterceptorStoreICSetter(
10831 Local<Value> value,
10832 const v8::PropertyCallbackInfo<v8::Value>& info) {
10833 CHECK(v8_str("x")->Equals(key));
10834 CHECK_EQ(42, value->Int32Value());
10835 info.GetReturnValue().Set(value);
10839 // This test should hit the store IC for the interceptor case.
10840 THREADED_TEST(InterceptorStoreIC) {
10841 v8::HandleScope scope(v8::Isolate::GetCurrent());
10842 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10843 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
10844 InterceptorStoreICSetter,
10845 0, 0, 0, v8_str("data"));
10846 LocalContext context;
10847 context->Global()->Set(v8_str("o"), templ->NewInstance());
10849 "for (var i = 0; i < 1000; i++) {"
10855 THREADED_TEST(InterceptorStoreICWithNoSetter) {
10856 v8::HandleScope scope(v8::Isolate::GetCurrent());
10857 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10858 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10859 LocalContext context;
10860 context->Global()->Set(v8_str("o"), templ->NewInstance());
10861 v8::Handle<Value> value = CompileRun(
10862 "for (var i = 0; i < 1000; i++) {"
10866 CHECK_EQ(239 + 42, value->Int32Value());
10872 v8::Handle<Value> call_ic_function;
10873 v8::Handle<Value> call_ic_function2;
10874 v8::Handle<Value> call_ic_function3;
10876 static void InterceptorCallICGetter(
10877 Local<String> name,
10878 const v8::PropertyCallbackInfo<v8::Value>& info) {
10879 ApiTestFuzzer::Fuzz();
10880 CHECK(v8_str("x")->Equals(name));
10881 info.GetReturnValue().Set(call_ic_function);
10885 // This test should hit the call IC for the interceptor case.
10886 THREADED_TEST(InterceptorCallIC) {
10887 v8::HandleScope scope(v8::Isolate::GetCurrent());
10888 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10889 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
10890 LocalContext context;
10891 context->Global()->Set(v8_str("o"), templ->NewInstance());
10893 v8_compile("function f(x) { return x + 1; }; f")->Run();
10894 v8::Handle<Value> value = CompileRun(
10896 "for (var i = 0; i < 1000; i++) {"
10897 " result = o.x(41);"
10899 CHECK_EQ(42, value->Int32Value());
10903 // This test checks that if interceptor doesn't provide
10904 // a value, we can fetch regular value.
10905 THREADED_TEST(InterceptorCallICSeesOthers) {
10906 v8::HandleScope scope(v8::Isolate::GetCurrent());
10907 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10908 templ->SetNamedPropertyHandler(NoBlockGetterX);
10909 LocalContext context;
10910 context->Global()->Set(v8_str("o"), templ->NewInstance());
10911 v8::Handle<Value> value = CompileRun(
10912 "o.x = function f(x) { return x + 1; };"
10914 "for (var i = 0; i < 7; i++) {"
10915 " result = o.x(41);"
10917 CHECK_EQ(42, value->Int32Value());
10921 static v8::Handle<Value> call_ic_function4;
10922 static void InterceptorCallICGetter4(
10923 Local<String> name,
10924 const v8::PropertyCallbackInfo<v8::Value>& info) {
10925 ApiTestFuzzer::Fuzz();
10926 CHECK(v8_str("x")->Equals(name));
10927 info.GetReturnValue().Set(call_ic_function4);
10931 // This test checks that if interceptor provides a function,
10932 // even if we cached shadowed variant, interceptor's function
10934 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
10935 v8::HandleScope scope(v8::Isolate::GetCurrent());
10936 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10937 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
10938 LocalContext context;
10939 context->Global()->Set(v8_str("o"), templ->NewInstance());
10940 call_ic_function4 =
10941 v8_compile("function f(x) { return x - 1; }; f")->Run();
10942 v8::Handle<Value> value = CompileRun(
10943 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
10945 "for (var i = 0; i < 1000; i++) {"
10946 " result = o.x(42);"
10948 CHECK_EQ(41, value->Int32Value());
10952 // Test the case when we stored cacheable lookup into
10953 // a stub, but it got invalidated later on
10954 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
10955 v8::HandleScope scope(v8::Isolate::GetCurrent());
10956 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10957 templ->SetNamedPropertyHandler(NoBlockGetterX);
10958 LocalContext context;
10959 context->Global()->Set(v8_str("o"), templ->NewInstance());
10960 v8::Handle<Value> value = CompileRun(
10961 "proto1 = new Object();"
10962 "proto2 = new Object();"
10963 "o.__proto__ = proto1;"
10964 "proto1.__proto__ = proto2;"
10965 "proto2.y = function(x) { return x + 1; };"
10966 // Invoke it many times to compile a stub
10967 "for (var i = 0; i < 7; i++) {"
10970 "proto1.y = function(x) { return x - 1; };"
10972 "for (var i = 0; i < 7; i++) {"
10973 " result += o.y(42);"
10975 CHECK_EQ(41 * 7, value->Int32Value());
10979 // This test checks that if interceptor doesn't provide a function,
10980 // cached constant function is used
10981 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
10982 v8::HandleScope scope(v8::Isolate::GetCurrent());
10983 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10984 templ->SetNamedPropertyHandler(NoBlockGetterX);
10985 LocalContext context;
10986 context->Global()->Set(v8_str("o"), templ->NewInstance());
10987 v8::Handle<Value> value = CompileRun(
10988 "function inc(x) { return x + 1; };"
10992 "for (var i = 0; i < 1000; i++) {"
10993 " result = o.x(42);"
10995 CHECK_EQ(43, value->Int32Value());
10999 static v8::Handle<Value> call_ic_function5;
11000 static void InterceptorCallICGetter5(
11001 Local<String> name,
11002 const v8::PropertyCallbackInfo<v8::Value>& info) {
11003 ApiTestFuzzer::Fuzz();
11004 if (v8_str("x")->Equals(name))
11005 info.GetReturnValue().Set(call_ic_function5);
11009 // This test checks that if interceptor provides a function,
11010 // even if we cached constant function, interceptor's function
11012 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11013 v8::HandleScope scope(v8::Isolate::GetCurrent());
11014 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11015 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11016 LocalContext context;
11017 context->Global()->Set(v8_str("o"), templ->NewInstance());
11018 call_ic_function5 =
11019 v8_compile("function f(x) { return x - 1; }; f")->Run();
11020 v8::Handle<Value> value = CompileRun(
11021 "function inc(x) { return x + 1; };"
11025 "for (var i = 0; i < 1000; i++) {"
11026 " result = o.x(42);"
11028 CHECK_EQ(41, value->Int32Value());
11032 static v8::Handle<Value> call_ic_function6;
11033 static void InterceptorCallICGetter6(
11034 Local<String> name,
11035 const v8::PropertyCallbackInfo<v8::Value>& info) {
11036 ApiTestFuzzer::Fuzz();
11037 if (v8_str("x")->Equals(name))
11038 info.GetReturnValue().Set(call_ic_function6);
11042 // Same test as above, except the code is wrapped in a function
11043 // to test the optimized compiler.
11044 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11045 i::FLAG_allow_natives_syntax = true;
11046 v8::HandleScope scope(v8::Isolate::GetCurrent());
11047 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11048 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11049 LocalContext context;
11050 context->Global()->Set(v8_str("o"), templ->NewInstance());
11051 call_ic_function6 =
11052 v8_compile("function f(x) { return x - 1; }; f")->Run();
11053 v8::Handle<Value> value = CompileRun(
11054 "function inc(x) { return x + 1; };"
11057 "function test() {"
11059 " for (var i = 0; i < 1000; i++) {"
11060 " result = o.x(42);"
11067 "%OptimizeFunctionOnNextCall(test);"
11069 CHECK_EQ(41, value->Int32Value());
11073 // Test the case when we stored constant function into
11074 // a stub, but it got invalidated later on
11075 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11076 v8::HandleScope scope(v8::Isolate::GetCurrent());
11077 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11078 templ->SetNamedPropertyHandler(NoBlockGetterX);
11079 LocalContext context;
11080 context->Global()->Set(v8_str("o"), templ->NewInstance());
11081 v8::Handle<Value> value = CompileRun(
11082 "function inc(x) { return x + 1; };"
11084 "proto1 = new Object();"
11085 "proto2 = new Object();"
11086 "o.__proto__ = proto1;"
11087 "proto1.__proto__ = proto2;"
11089 // Invoke it many times to compile a stub
11090 "for (var i = 0; i < 7; i++) {"
11093 "proto1.y = function(x) { return x - 1; };"
11095 "for (var i = 0; i < 7; i++) {"
11096 " result += o.y(42);"
11098 CHECK_EQ(41 * 7, value->Int32Value());
11102 // Test the case when we stored constant function into
11103 // a stub, but it got invalidated later on due to override on
11104 // global object which is between interceptor and constant function' holders.
11105 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11106 v8::HandleScope scope(v8::Isolate::GetCurrent());
11107 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11108 templ->SetNamedPropertyHandler(NoBlockGetterX);
11109 LocalContext context;
11110 context->Global()->Set(v8_str("o"), templ->NewInstance());
11111 v8::Handle<Value> value = CompileRun(
11112 "function inc(x) { return x + 1; };"
11114 "o.__proto__ = this;"
11115 "this.__proto__.y = inc;"
11116 // Invoke it many times to compile a stub
11117 "for (var i = 0; i < 7; i++) {"
11118 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11120 "this.y = function(x) { return x - 1; };"
11122 "for (var i = 0; i < 7; i++) {"
11123 " result += o.y(42);"
11125 CHECK_EQ(41 * 7, value->Int32Value());
11129 // Test the case when actual function to call sits on global object.
11130 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11131 v8::HandleScope scope(v8::Isolate::GetCurrent());
11132 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11133 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11135 LocalContext context;
11136 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11138 v8::Handle<Value> value = CompileRun(
11140 " o.__proto__ = this;"
11141 " for (var i = 0; i < 10; i++) {"
11142 " var v = o.parseFloat('239');"
11143 " if (v != 239) throw v;"
11144 // Now it should be ICed and keep a reference to parseFloat.
11147 " for (var i = 0; i < 10; i++) {"
11148 " result += o.parseFloat('239');"
11154 CHECK_EQ(239 * 10, value->Int32Value());
11157 static void InterceptorCallICFastApi(
11158 Local<String> name,
11159 const v8::PropertyCallbackInfo<v8::Value>& info) {
11160 ApiTestFuzzer::Fuzz();
11161 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
11163 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
11165 if ((*call_count) % 20 == 0) {
11166 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11170 static void FastApiCallback_TrivialSignature(
11171 const v8::FunctionCallbackInfo<v8::Value>& args) {
11172 ApiTestFuzzer::Fuzz();
11173 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
11174 v8::Isolate* isolate = v8::Isolate::GetCurrent();
11175 CHECK_EQ(isolate, args.GetIsolate());
11176 CHECK_EQ(args.This(), args.Holder());
11177 CHECK(args.Data()->Equals(v8_str("method_data")));
11178 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11181 static void FastApiCallback_SimpleSignature(
11182 const v8::FunctionCallbackInfo<v8::Value>& args) {
11183 ApiTestFuzzer::Fuzz();
11184 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
11185 v8::Isolate* isolate = v8::Isolate::GetCurrent();
11186 CHECK_EQ(isolate, args.GetIsolate());
11187 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
11188 CHECK(args.Data()->Equals(v8_str("method_data")));
11189 // Note, we're using HasRealNamedProperty instead of Has to avoid
11190 // invoking the interceptor again.
11191 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
11192 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11196 // Helper to maximize the odds of object moving.
11197 static void GenerateSomeGarbage() {
11200 "for (var i = 0; i < 1000; i++) {"
11201 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
11203 "garbage = undefined;");
11207 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11208 static int count = 0;
11209 if (count++ % 3 == 0) {
11210 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11211 // This should move the stub
11212 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
11217 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
11218 LocalContext context;
11219 v8::HandleScope scope(context->GetIsolate());
11220 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
11221 nativeobject_templ->Set("callback",
11222 v8::FunctionTemplate::New(DirectApiCallback));
11223 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11224 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11225 // call the api function multiple times to ensure direct call stub creation.
11228 " for (var i = 1; i <= 30; i++) {"
11229 " nativeobject.callback();"
11236 void ThrowingDirectApiCallback(
11237 const v8::FunctionCallbackInfo<v8::Value>& args) {
11238 v8::ThrowException(v8_str("g"));
11242 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
11243 LocalContext context;
11244 v8::HandleScope scope(context->GetIsolate());
11245 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
11246 nativeobject_templ->Set("callback",
11247 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
11248 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11249 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11250 // call the api function multiple times to ensure direct call stub creation.
11251 v8::Handle<Value> result = CompileRun(
11254 " for (var i = 1; i <= 5; i++) {"
11255 " try { nativeobject.callback(); } catch (e) { result += e; }"
11259 CHECK_EQ(v8_str("ggggg"), result);
11263 static Handle<Value> DoDirectGetter() {
11264 if (++p_getter_count % 3 == 0) {
11265 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11266 GenerateSomeGarbage();
11268 return v8_str("Direct Getter Result");
11271 static void DirectGetterCallback(
11272 Local<String> name,
11273 const v8::PropertyCallbackInfo<v8::Value>& info) {
11274 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
11275 info.GetReturnValue().Set(DoDirectGetter());
11279 template<typename Accessor>
11280 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
11281 LocalContext context;
11282 v8::HandleScope scope(context->GetIsolate());
11283 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
11284 obj->SetAccessor(v8_str("p1"), accessor);
11285 context->Global()->Set(v8_str("o1"), obj->NewInstance());
11286 p_getter_count = 0;
11287 v8::Handle<v8::Value> result = CompileRun(
11289 " for (var i = 0; i < 30; i++) o1.p1;"
11293 CHECK_EQ(v8_str("Direct Getter Result"), result);
11294 CHECK_EQ(31, p_getter_count);
11298 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
11299 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
11303 void ThrowingDirectGetterCallback(
11304 Local<String> name,
11305 const v8::PropertyCallbackInfo<v8::Value>& info) {
11306 v8::ThrowException(v8_str("g"));
11310 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
11311 LocalContext context;
11312 v8::HandleScope scope(context->GetIsolate());
11313 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
11314 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
11315 context->Global()->Set(v8_str("o1"), obj->NewInstance());
11316 v8::Handle<Value> result = CompileRun(
11318 "for (var i = 0; i < 5; i++) {"
11319 " try { o1.p1; } catch (e) { result += e; }"
11322 CHECK_EQ(v8_str("ggggg"), result);
11326 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
11327 int interceptor_call_count = 0;
11328 v8::HandleScope scope(v8::Isolate::GetCurrent());
11329 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11330 v8::Handle<v8::FunctionTemplate> method_templ =
11331 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
11332 v8_str("method_data"),
11333 v8::Handle<v8::Signature>());
11334 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11335 proto_templ->Set(v8_str("method"), method_templ);
11336 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11337 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11338 NULL, NULL, NULL, NULL,
11339 v8::External::New(&interceptor_call_count));
11340 LocalContext context;
11341 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11342 GenerateSomeGarbage();
11343 context->Global()->Set(v8_str("o"), fun->NewInstance());
11346 "for (var i = 0; i < 100; i++) {"
11347 " result = o.method(41);"
11349 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11350 CHECK_EQ(100, interceptor_call_count);
11354 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
11355 int interceptor_call_count = 0;
11356 v8::HandleScope scope(v8::Isolate::GetCurrent());
11357 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11358 v8::Handle<v8::FunctionTemplate> method_templ =
11359 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11360 v8_str("method_data"),
11361 v8::Signature::New(fun_templ));
11362 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11363 proto_templ->Set(v8_str("method"), method_templ);
11364 fun_templ->SetHiddenPrototype(true);
11365 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11366 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11367 NULL, NULL, NULL, NULL,
11368 v8::External::New(&interceptor_call_count));
11369 LocalContext context;
11370 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11371 GenerateSomeGarbage();
11372 context->Global()->Set(v8_str("o"), fun->NewInstance());
11375 "var receiver = {};"
11376 "receiver.__proto__ = o;"
11378 "for (var i = 0; i < 100; i++) {"
11379 " result = receiver.method(41);"
11381 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11382 CHECK_EQ(100, interceptor_call_count);
11386 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
11387 int interceptor_call_count = 0;
11388 v8::HandleScope scope(v8::Isolate::GetCurrent());
11389 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11390 v8::Handle<v8::FunctionTemplate> method_templ =
11391 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11392 v8_str("method_data"),
11393 v8::Signature::New(fun_templ));
11394 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11395 proto_templ->Set(v8_str("method"), method_templ);
11396 fun_templ->SetHiddenPrototype(true);
11397 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11398 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11399 NULL, NULL, NULL, NULL,
11400 v8::External::New(&interceptor_call_count));
11401 LocalContext context;
11402 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11403 GenerateSomeGarbage();
11404 context->Global()->Set(v8_str("o"), fun->NewInstance());
11407 "var receiver = {};"
11408 "receiver.__proto__ = o;"
11410 "var saved_result = 0;"
11411 "for (var i = 0; i < 100; i++) {"
11412 " result = receiver.method(41);"
11414 " saved_result = result;"
11415 " receiver = {method: function(x) { return x - 1 }};"
11418 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11419 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11420 CHECK_GE(interceptor_call_count, 50);
11424 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
11425 int interceptor_call_count = 0;
11426 v8::HandleScope scope(v8::Isolate::GetCurrent());
11427 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11428 v8::Handle<v8::FunctionTemplate> method_templ =
11429 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11430 v8_str("method_data"),
11431 v8::Signature::New(fun_templ));
11432 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11433 proto_templ->Set(v8_str("method"), method_templ);
11434 fun_templ->SetHiddenPrototype(true);
11435 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11436 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11437 NULL, NULL, NULL, NULL,
11438 v8::External::New(&interceptor_call_count));
11439 LocalContext context;
11440 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11441 GenerateSomeGarbage();
11442 context->Global()->Set(v8_str("o"), fun->NewInstance());
11445 "var receiver = {};"
11446 "receiver.__proto__ = o;"
11448 "var saved_result = 0;"
11449 "for (var i = 0; i < 100; i++) {"
11450 " result = receiver.method(41);"
11452 " saved_result = result;"
11453 " o.method = function(x) { return x - 1 };"
11456 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11457 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11458 CHECK_GE(interceptor_call_count, 50);
11462 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
11463 int interceptor_call_count = 0;
11464 v8::HandleScope scope(v8::Isolate::GetCurrent());
11465 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11466 v8::Handle<v8::FunctionTemplate> method_templ =
11467 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11468 v8_str("method_data"),
11469 v8::Signature::New(fun_templ));
11470 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11471 proto_templ->Set(v8_str("method"), method_templ);
11472 fun_templ->SetHiddenPrototype(true);
11473 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11474 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11475 NULL, NULL, NULL, NULL,
11476 v8::External::New(&interceptor_call_count));
11477 LocalContext context;
11478 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11479 GenerateSomeGarbage();
11480 context->Global()->Set(v8_str("o"), fun->NewInstance());
11481 v8::TryCatch try_catch;
11484 "var receiver = {};"
11485 "receiver.__proto__ = o;"
11487 "var saved_result = 0;"
11488 "for (var i = 0; i < 100; i++) {"
11489 " result = receiver.method(41);"
11491 " saved_result = result;"
11495 CHECK(try_catch.HasCaught());
11496 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
11497 try_catch.Exception()->ToString());
11498 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11499 CHECK_GE(interceptor_call_count, 50);
11503 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
11504 int interceptor_call_count = 0;
11505 v8::HandleScope scope(v8::Isolate::GetCurrent());
11506 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11507 v8::Handle<v8::FunctionTemplate> method_templ =
11508 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11509 v8_str("method_data"),
11510 v8::Signature::New(fun_templ));
11511 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11512 proto_templ->Set(v8_str("method"), method_templ);
11513 fun_templ->SetHiddenPrototype(true);
11514 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11515 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11516 NULL, NULL, NULL, NULL,
11517 v8::External::New(&interceptor_call_count));
11518 LocalContext context;
11519 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11520 GenerateSomeGarbage();
11521 context->Global()->Set(v8_str("o"), fun->NewInstance());
11522 v8::TryCatch try_catch;
11525 "var receiver = {};"
11526 "receiver.__proto__ = o;"
11528 "var saved_result = 0;"
11529 "for (var i = 0; i < 100; i++) {"
11530 " result = receiver.method(41);"
11532 " saved_result = result;"
11533 " receiver = {method: receiver.method};"
11536 CHECK(try_catch.HasCaught());
11537 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
11538 try_catch.Exception()->ToString());
11539 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11540 CHECK_GE(interceptor_call_count, 50);
11544 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
11545 v8::HandleScope scope(v8::Isolate::GetCurrent());
11546 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11547 v8::Handle<v8::FunctionTemplate> method_templ =
11548 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
11549 v8_str("method_data"),
11550 v8::Handle<v8::Signature>());
11551 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11552 proto_templ->Set(v8_str("method"), method_templ);
11553 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11555 LocalContext context;
11556 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11557 GenerateSomeGarbage();
11558 context->Global()->Set(v8_str("o"), fun->NewInstance());
11561 "for (var i = 0; i < 100; i++) {"
11562 " result = o.method(41);"
11565 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11569 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
11570 v8::HandleScope scope(v8::Isolate::GetCurrent());
11571 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11572 v8::Handle<v8::FunctionTemplate> method_templ =
11573 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11574 v8_str("method_data"),
11575 v8::Signature::New(fun_templ));
11576 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11577 proto_templ->Set(v8_str("method"), method_templ);
11578 fun_templ->SetHiddenPrototype(true);
11579 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11580 CHECK(!templ.IsEmpty());
11581 LocalContext context;
11582 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11583 GenerateSomeGarbage();
11584 context->Global()->Set(v8_str("o"), fun->NewInstance());
11587 "var receiver = {};"
11588 "receiver.__proto__ = o;"
11590 "for (var i = 0; i < 100; i++) {"
11591 " result = receiver.method(41);"
11594 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11598 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
11599 v8::HandleScope scope(v8::Isolate::GetCurrent());
11600 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11601 v8::Handle<v8::FunctionTemplate> method_templ =
11602 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11603 v8_str("method_data"),
11604 v8::Signature::New(fun_templ));
11605 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11606 proto_templ->Set(v8_str("method"), method_templ);
11607 fun_templ->SetHiddenPrototype(true);
11608 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11609 CHECK(!templ.IsEmpty());
11610 LocalContext context;
11611 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11612 GenerateSomeGarbage();
11613 context->Global()->Set(v8_str("o"), fun->NewInstance());
11616 "var receiver = {};"
11617 "receiver.__proto__ = o;"
11619 "var saved_result = 0;"
11620 "for (var i = 0; i < 100; i++) {"
11621 " result = receiver.method(41);"
11623 " saved_result = result;"
11624 " receiver = {method: function(x) { return x - 1 }};"
11627 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11628 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11632 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
11633 v8::HandleScope scope(v8::Isolate::GetCurrent());
11634 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11635 v8::Handle<v8::FunctionTemplate> method_templ =
11636 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11637 v8_str("method_data"),
11638 v8::Signature::New(fun_templ));
11639 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11640 proto_templ->Set(v8_str("method"), method_templ);
11641 fun_templ->SetHiddenPrototype(true);
11642 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11643 CHECK(!templ.IsEmpty());
11644 LocalContext context;
11645 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11646 GenerateSomeGarbage();
11647 context->Global()->Set(v8_str("o"), fun->NewInstance());
11648 v8::TryCatch try_catch;
11651 "var receiver = {};"
11652 "receiver.__proto__ = o;"
11654 "var saved_result = 0;"
11655 "for (var i = 0; i < 100; i++) {"
11656 " result = receiver.method(41);"
11658 " saved_result = result;"
11662 CHECK(try_catch.HasCaught());
11663 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
11664 try_catch.Exception()->ToString());
11665 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11669 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
11670 v8::HandleScope scope(v8::Isolate::GetCurrent());
11671 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11672 v8::Handle<v8::FunctionTemplate> method_templ =
11673 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11674 v8_str("method_data"),
11675 v8::Signature::New(fun_templ));
11676 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11677 proto_templ->Set(v8_str("method"), method_templ);
11678 fun_templ->SetHiddenPrototype(true);
11679 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11680 CHECK(!templ.IsEmpty());
11681 LocalContext context;
11682 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11683 GenerateSomeGarbage();
11684 context->Global()->Set(v8_str("o"), fun->NewInstance());
11685 v8::TryCatch try_catch;
11688 "var receiver = {};"
11689 "receiver.__proto__ = o;"
11691 "var saved_result = 0;"
11692 "for (var i = 0; i < 100; i++) {"
11693 " result = receiver.method(41);"
11695 " saved_result = result;"
11696 " receiver = Object.create(receiver);"
11699 CHECK(try_catch.HasCaught());
11700 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
11701 try_catch.Exception()->ToString());
11702 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11706 v8::Handle<Value> keyed_call_ic_function;
11708 static void InterceptorKeyedCallICGetter(
11709 Local<String> name,
11710 const v8::PropertyCallbackInfo<v8::Value>& info) {
11711 ApiTestFuzzer::Fuzz();
11712 if (v8_str("x")->Equals(name)) {
11713 info.GetReturnValue().Set(keyed_call_ic_function);
11718 // Test the case when we stored cacheable lookup into
11719 // a stub, but the function name changed (to another cacheable function).
11720 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
11721 v8::HandleScope scope(v8::Isolate::GetCurrent());
11722 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11723 templ->SetNamedPropertyHandler(NoBlockGetterX);
11724 LocalContext context;
11725 context->Global()->Set(v8_str("o"), templ->NewInstance());
11727 "proto = new Object();"
11728 "proto.y = function(x) { return x + 1; };"
11729 "proto.z = function(x) { return x - 1; };"
11730 "o.__proto__ = proto;"
11732 "var method = 'y';"
11733 "for (var i = 0; i < 10; i++) {"
11734 " if (i == 5) { method = 'z'; };"
11735 " result += o[method](41);"
11737 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11741 // Test the case when we stored cacheable lookup into
11742 // a stub, but the function name changed (and the new function is present
11743 // both before and after the interceptor in the prototype chain).
11744 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
11745 v8::HandleScope scope(v8::Isolate::GetCurrent());
11746 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11747 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
11748 LocalContext context;
11749 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
11750 keyed_call_ic_function =
11751 v8_compile("function f(x) { return x - 1; }; f")->Run();
11753 "o = new Object();"
11754 "proto2 = new Object();"
11755 "o.y = function(x) { return x + 1; };"
11756 "proto2.y = function(x) { return x + 2; };"
11757 "o.__proto__ = proto1;"
11758 "proto1.__proto__ = proto2;"
11760 "var method = 'x';"
11761 "for (var i = 0; i < 10; i++) {"
11762 " if (i == 5) { method = 'y'; };"
11763 " result += o[method](41);"
11765 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11769 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
11770 // on the global object.
11771 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
11772 v8::HandleScope scope(v8::Isolate::GetCurrent());
11773 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11774 templ->SetNamedPropertyHandler(NoBlockGetterX);
11775 LocalContext context;
11776 context->Global()->Set(v8_str("o"), templ->NewInstance());
11778 "function inc(x) { return x + 1; };"
11780 "function dec(x) { return x - 1; };"
11782 "o.__proto__ = this;"
11783 "this.__proto__.x = inc;"
11784 "this.__proto__.y = dec;"
11786 "var method = 'x';"
11787 "for (var i = 0; i < 10; i++) {"
11788 " if (i == 5) { method = 'y'; };"
11789 " result += o[method](41);"
11791 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11795 // Test the case when actual function to call sits on global object.
11796 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
11797 v8::HandleScope scope(v8::Isolate::GetCurrent());
11798 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11799 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11800 LocalContext context;
11801 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11804 "function len(x) { return x.length; };"
11805 "o.__proto__ = this;"
11806 "var m = 'parseFloat';"
11808 "for (var i = 0; i < 10; i++) {"
11811 " saved_result = result;"
11813 " result = o[m]('239');"
11815 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
11816 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11820 // Test the map transition before the interceptor.
11821 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
11822 v8::HandleScope scope(v8::Isolate::GetCurrent());
11823 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11824 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11825 LocalContext context;
11826 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
11829 "var o = new Object();"
11830 "o.__proto__ = proto;"
11831 "o.method = function(x) { return x + 1; };"
11832 "var m = 'method';"
11834 "for (var i = 0; i < 10; i++) {"
11835 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
11836 " result += o[m](41);"
11838 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11842 // Test the map transition after the interceptor.
11843 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
11844 v8::HandleScope scope(v8::Isolate::GetCurrent());
11845 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11846 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11847 LocalContext context;
11848 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11851 "var proto = new Object();"
11852 "o.__proto__ = proto;"
11853 "proto.method = function(x) { return x + 1; };"
11854 "var m = 'method';"
11856 "for (var i = 0; i < 10; i++) {"
11857 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
11858 " result += o[m](41);"
11860 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11864 static int interceptor_call_count = 0;
11866 static void InterceptorICRefErrorGetter(
11867 Local<String> name,
11868 const v8::PropertyCallbackInfo<v8::Value>& info) {
11869 ApiTestFuzzer::Fuzz();
11870 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
11871 info.GetReturnValue().Set(call_ic_function2);
11876 // This test should hit load and call ICs for the interceptor case.
11877 // Once in a while, the interceptor will reply that a property was not
11878 // found in which case we should get a reference error.
11879 THREADED_TEST(InterceptorICReferenceErrors) {
11880 v8::HandleScope scope(v8::Isolate::GetCurrent());
11881 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11882 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
11883 LocalContext context(0, templ, v8::Handle<Value>());
11884 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
11885 v8::Handle<Value> value = CompileRun(
11887 " for (var i = 0; i < 1000; i++) {"
11888 " try { x; } catch(e) { return true; }"
11893 CHECK_EQ(true, value->BooleanValue());
11894 interceptor_call_count = 0;
11895 value = CompileRun(
11897 " for (var i = 0; i < 1000; i++) {"
11898 " try { x(42); } catch(e) { return true; }"
11903 CHECK_EQ(true, value->BooleanValue());
11907 static int interceptor_ic_exception_get_count = 0;
11909 static void InterceptorICExceptionGetter(
11910 Local<String> name,
11911 const v8::PropertyCallbackInfo<v8::Value>& info) {
11912 ApiTestFuzzer::Fuzz();
11913 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
11914 info.GetReturnValue().Set(call_ic_function3);
11916 if (interceptor_ic_exception_get_count == 20) {
11917 v8::ThrowException(v8_num(42));
11923 // Test interceptor load/call IC where the interceptor throws an
11924 // exception once in a while.
11925 THREADED_TEST(InterceptorICGetterExceptions) {
11926 interceptor_ic_exception_get_count = 0;
11927 v8::HandleScope scope(v8::Isolate::GetCurrent());
11928 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11929 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
11930 LocalContext context(0, templ, v8::Handle<Value>());
11931 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
11932 v8::Handle<Value> value = CompileRun(
11934 " for (var i = 0; i < 100; i++) {"
11935 " try { x; } catch(e) { return true; }"
11940 CHECK_EQ(true, value->BooleanValue());
11941 interceptor_ic_exception_get_count = 0;
11942 value = CompileRun(
11944 " for (var i = 0; i < 100; i++) {"
11945 " try { x(42); } catch(e) { return true; }"
11950 CHECK_EQ(true, value->BooleanValue());
11954 static int interceptor_ic_exception_set_count = 0;
11956 static void InterceptorICExceptionSetter(
11958 Local<Value> value,
11959 const v8::PropertyCallbackInfo<v8::Value>& info) {
11960 ApiTestFuzzer::Fuzz();
11961 if (++interceptor_ic_exception_set_count > 20) {
11962 v8::ThrowException(v8_num(42));
11967 // Test interceptor store IC where the interceptor throws an exception
11968 // once in a while.
11969 THREADED_TEST(InterceptorICSetterExceptions) {
11970 interceptor_ic_exception_set_count = 0;
11971 v8::HandleScope scope(v8::Isolate::GetCurrent());
11972 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11973 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
11974 LocalContext context(0, templ, v8::Handle<Value>());
11975 v8::Handle<Value> value = CompileRun(
11977 " for (var i = 0; i < 100; i++) {"
11978 " try { x = 42; } catch(e) { return true; }"
11983 CHECK_EQ(true, value->BooleanValue());
11987 // Test that we ignore null interceptors.
11988 THREADED_TEST(NullNamedInterceptor) {
11989 v8::HandleScope scope(v8::Isolate::GetCurrent());
11990 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11991 templ->SetNamedPropertyHandler(
11992 static_cast<v8::NamedPropertyGetterCallback>(0));
11993 LocalContext context;
11994 templ->Set("x", v8_num(42));
11995 v8::Handle<v8::Object> obj = templ->NewInstance();
11996 context->Global()->Set(v8_str("obj"), obj);
11997 v8::Handle<Value> value = CompileRun("obj.x");
11998 CHECK(value->IsInt32());
11999 CHECK_EQ(42, value->Int32Value());
12003 // Test that we ignore null interceptors.
12004 THREADED_TEST(NullIndexedInterceptor) {
12005 v8::HandleScope scope(v8::Isolate::GetCurrent());
12006 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12007 templ->SetIndexedPropertyHandler(
12008 static_cast<v8::IndexedPropertyGetterCallback>(0));
12009 LocalContext context;
12010 templ->Set("42", v8_num(42));
12011 v8::Handle<v8::Object> obj = templ->NewInstance();
12012 context->Global()->Set(v8_str("obj"), obj);
12013 v8::Handle<Value> value = CompileRun("obj[42]");
12014 CHECK(value->IsInt32());
12015 CHECK_EQ(42, value->Int32Value());
12019 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12020 v8::HandleScope scope(v8::Isolate::GetCurrent());
12021 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
12022 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12024 env->Global()->Set(v8_str("obj"),
12025 templ->GetFunction()->NewInstance());
12026 ExpectTrue("obj.x === 42");
12027 ExpectTrue("!obj.propertyIsEnumerable('x')");
12031 static void ThrowingGetter(Local<String> name,
12032 const v8::PropertyCallbackInfo<v8::Value>& info) {
12033 ApiTestFuzzer::Fuzz();
12034 ThrowException(Handle<Value>());
12035 info.GetReturnValue().SetUndefined();
12039 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12040 LocalContext context;
12041 HandleScope scope(context->GetIsolate());
12043 Local<FunctionTemplate> templ = FunctionTemplate::New();
12044 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12045 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12047 Local<Object> instance = templ->GetFunction()->NewInstance();
12049 Local<Object> another = Object::New();
12050 another->SetPrototype(instance);
12052 Local<Object> with_js_getter = CompileRun(
12054 "o.__defineGetter__('f', function() { throw undefined; });\n"
12055 "o\n").As<Object>();
12056 CHECK(!with_js_getter.IsEmpty());
12058 TryCatch try_catch;
12060 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12061 CHECK(try_catch.HasCaught());
12063 CHECK(result.IsEmpty());
12065 result = another->GetRealNamedProperty(v8_str("f"));
12066 CHECK(try_catch.HasCaught());
12068 CHECK(result.IsEmpty());
12070 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12071 CHECK(try_catch.HasCaught());
12073 CHECK(result.IsEmpty());
12075 result = another->Get(v8_str("f"));
12076 CHECK(try_catch.HasCaught());
12078 CHECK(result.IsEmpty());
12080 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12081 CHECK(try_catch.HasCaught());
12083 CHECK(result.IsEmpty());
12085 result = with_js_getter->Get(v8_str("f"));
12086 CHECK(try_catch.HasCaught());
12088 CHECK(result.IsEmpty());
12092 static void ThrowingCallbackWithTryCatch(
12093 const v8::FunctionCallbackInfo<v8::Value>& args) {
12094 TryCatch try_catch;
12095 // Verboseness is important: it triggers message delivery which can call into
12097 try_catch.SetVerbose(true);
12098 CompileRun("throw 'from JS';");
12099 CHECK(try_catch.HasCaught());
12100 CHECK(!i::Isolate::Current()->has_pending_exception());
12101 CHECK(!i::Isolate::Current()->has_scheduled_exception());
12105 static int call_depth;
12108 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
12109 TryCatch try_catch;
12113 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
12114 if (--call_depth) CompileRun("throw 'ThrowInJS';");
12118 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
12119 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
12123 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
12124 Handle<String> errorMessageString = message->Get();
12125 CHECK(!errorMessageString.IsEmpty());
12126 message->GetStackTrace();
12127 message->GetScriptResourceName();
12131 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12132 LocalContext context;
12133 HandleScope scope(context->GetIsolate());
12135 Local<Function> func =
12136 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
12137 context->Global()->Set(v8_str("func"), func);
12139 MessageCallback callbacks[] =
12140 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
12141 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12142 MessageCallback callback = callbacks[i];
12143 if (callback != NULL) {
12144 V8::AddMessageListener(callback);
12146 // Some small number to control number of times message handler should
12147 // throw an exception.
12150 "var thrown = false;\n"
12151 "try { func(); } catch(e) { thrown = true; }\n"
12153 if (callback != NULL) {
12154 V8::RemoveMessageListeners(callback);
12160 static void ParentGetter(Local<String> name,
12161 const v8::PropertyCallbackInfo<v8::Value>& info) {
12162 ApiTestFuzzer::Fuzz();
12163 info.GetReturnValue().Set(v8_num(1));
12167 static void ChildGetter(Local<String> name,
12168 const v8::PropertyCallbackInfo<v8::Value>& info) {
12169 ApiTestFuzzer::Fuzz();
12170 info.GetReturnValue().Set(v8_num(42));
12174 THREADED_TEST(Overriding) {
12175 i::FLAG_es5_readonly = true;
12176 LocalContext context;
12177 v8::HandleScope scope(context->GetIsolate());
12179 // Parent template.
12180 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
12181 Local<ObjectTemplate> parent_instance_templ =
12182 parent_templ->InstanceTemplate();
12183 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
12185 // Template that inherits from the parent template.
12186 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
12187 Local<ObjectTemplate> child_instance_templ =
12188 child_templ->InstanceTemplate();
12189 child_templ->Inherit(parent_templ);
12190 // Override 'f'. The child version of 'f' should get called for child
12192 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
12193 // Add 'g' twice. The 'g' added last should get called for instances.
12194 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
12195 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
12197 // Add 'h' as an accessor to the proto template with ReadOnly attributes
12198 // so 'h' can be shadowed on the instance object.
12199 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
12200 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
12201 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12203 // Add 'i' as an accessor to the instance template with ReadOnly attributes
12204 // but the attribute does not have effect because it is duplicated with
12206 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
12207 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12211 // Instantiate the child template.
12212 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
12214 // Check that the child function overrides the parent one.
12215 context->Global()->Set(v8_str("o"), instance);
12216 Local<Value> value = v8_compile("o.f")->Run();
12217 // Check that the 'g' that was added last is hit.
12218 CHECK_EQ(42, value->Int32Value());
12219 value = v8_compile("o.g")->Run();
12220 CHECK_EQ(42, value->Int32Value());
12222 // Check that 'h' cannot be shadowed.
12223 value = v8_compile("o.h = 3; o.h")->Run();
12224 CHECK_EQ(1, value->Int32Value());
12226 // Check that 'i' cannot be shadowed or changed.
12227 value = v8_compile("o.i = 3; o.i")->Run();
12228 CHECK_EQ(42, value->Int32Value());
12232 static void IsConstructHandler(
12233 const v8::FunctionCallbackInfo<v8::Value>& args) {
12234 ApiTestFuzzer::Fuzz();
12235 args.GetReturnValue().Set(args.IsConstructCall());
12239 THREADED_TEST(IsConstructCall) {
12240 v8::HandleScope scope(v8::Isolate::GetCurrent());
12242 // Function template with call handler.
12243 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
12244 templ->SetCallHandler(IsConstructHandler);
12246 LocalContext context;
12248 context->Global()->Set(v8_str("f"), templ->GetFunction());
12249 Local<Value> value = v8_compile("f()")->Run();
12250 CHECK(!value->BooleanValue());
12251 value = v8_compile("new f()")->Run();
12252 CHECK(value->BooleanValue());
12256 THREADED_TEST(ObjectProtoToString) {
12257 v8::HandleScope scope(v8::Isolate::GetCurrent());
12258 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
12259 templ->SetClassName(v8_str("MyClass"));
12261 LocalContext context;
12263 Local<String> customized_tostring = v8_str("customized toString");
12265 // Replace Object.prototype.toString
12266 v8_compile("Object.prototype.toString = function() {"
12267 " return 'customized toString';"
12270 // Normal ToString call should call replaced Object.prototype.toString
12271 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
12272 Local<String> value = instance->ToString();
12273 CHECK(value->IsString() && value->Equals(customized_tostring));
12275 // ObjectProtoToString should not call replace toString function.
12276 value = instance->ObjectProtoToString();
12277 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
12280 value = context->Global()->ObjectProtoToString();
12281 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
12283 // Check ordinary object
12284 Local<Value> object = v8_compile("new Object()")->Run();
12285 value = object.As<v8::Object>()->ObjectProtoToString();
12286 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
12290 THREADED_TEST(ObjectGetConstructorName) {
12291 LocalContext context;
12292 v8::HandleScope scope(context->GetIsolate());
12293 v8_compile("function Parent() {};"
12294 "function Child() {};"
12295 "Child.prototype = new Parent();"
12296 "var outer = { inner: function() { } };"
12297 "var p = new Parent();"
12298 "var c = new Child();"
12299 "var x = new outer.inner();")->Run();
12301 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
12302 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
12303 v8_str("Parent")));
12305 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
12306 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
12309 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
12310 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
12311 v8_str("outer.inner")));
12315 bool ApiTestFuzzer::fuzzing_ = false;
12316 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
12317 int ApiTestFuzzer::active_tests_;
12318 int ApiTestFuzzer::tests_being_run_;
12319 int ApiTestFuzzer::current_;
12322 // We are in a callback and want to switch to another thread (if we
12323 // are currently running the thread fuzzing test).
12324 void ApiTestFuzzer::Fuzz() {
12325 if (!fuzzing_) return;
12326 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
12327 test->ContextSwitch();
12331 // Let the next thread go. Since it is also waiting on the V8 lock it may
12332 // not start immediately.
12333 bool ApiTestFuzzer::NextThread() {
12334 int test_position = GetNextTestNumber();
12335 const char* test_name = RegisterThreadedTest::nth(current_)->name();
12336 if (test_position == current_) {
12338 printf("Stay with %s\n", test_name);
12341 if (kLogThreading) {
12342 printf("Switch from %s to %s\n",
12344 RegisterThreadedTest::nth(test_position)->name());
12346 current_ = test_position;
12347 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
12352 void ApiTestFuzzer::Run() {
12353 // When it is our turn...
12356 // ... get the V8 lock and start running the test.
12357 v8::Locker locker(CcTest::default_isolate());
12360 // This test finished.
12363 // If it was the last then signal that fact.
12364 if (active_tests_ == 0) {
12365 all_tests_done_.Signal();
12367 // Otherwise select a new test and start that.
12373 static unsigned linear_congruential_generator;
12376 void ApiTestFuzzer::SetUp(PartOfTest part) {
12377 linear_congruential_generator = i::FLAG_testing_prng_seed;
12379 int count = RegisterThreadedTest::count();
12380 int start = count * part / (LAST_PART + 1);
12381 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
12382 active_tests_ = tests_being_run_ = end - start + 1;
12383 for (int i = 0; i < tests_being_run_; i++) {
12384 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
12386 for (int i = 0; i < active_tests_; i++) {
12387 RegisterThreadedTest::nth(i)->fuzzer_->Start();
12392 static void CallTestNumber(int test_number) {
12393 (RegisterThreadedTest::nth(test_number)->callback())();
12397 void ApiTestFuzzer::RunAllTests() {
12398 // Set off the first test.
12401 // Wait till they are all done.
12402 all_tests_done_.Wait();
12406 int ApiTestFuzzer::GetNextTestNumber() {
12409 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
12410 linear_congruential_generator *= 1664525u;
12411 linear_congruential_generator += 1013904223u;
12412 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
12417 void ApiTestFuzzer::ContextSwitch() {
12418 // If the new thread is the same as the current thread there is nothing to do.
12419 if (NextThread()) {
12420 // Now it can start.
12421 v8::Unlocker unlocker(CcTest::default_isolate());
12422 // Wait till someone starts us again.
12429 void ApiTestFuzzer::TearDown() {
12431 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
12432 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
12433 if (fuzzer != NULL) fuzzer->Join();
12438 // Lets not be needlessly self-referential.
12440 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
12441 ApiTestFuzzer::RunAllTests();
12442 ApiTestFuzzer::TearDown();
12447 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
12448 ApiTestFuzzer::RunAllTests();
12449 ApiTestFuzzer::TearDown();
12454 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
12455 ApiTestFuzzer::RunAllTests();
12456 ApiTestFuzzer::TearDown();
12461 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
12462 ApiTestFuzzer::RunAllTests();
12463 ApiTestFuzzer::TearDown();
12467 void ApiTestFuzzer::CallTest() {
12469 printf("Start test %d\n", test_number_);
12470 CallTestNumber(test_number_);
12472 printf("End test %d\n", test_number_);
12476 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
12477 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12478 ApiTestFuzzer::Fuzz();
12479 v8::Unlocker unlocker(CcTest::default_isolate());
12480 const char* code = "throw 7;";
12482 v8::Locker nested_locker(CcTest::default_isolate());
12483 v8::HandleScope scope(args.GetIsolate());
12484 v8::Handle<Value> exception;
12485 { v8::TryCatch try_catch;
12486 v8::Handle<Value> value = CompileRun(code);
12487 CHECK(value.IsEmpty());
12488 CHECK(try_catch.HasCaught());
12489 // Make sure to wrap the exception in a new handle because
12490 // the handle returned from the TryCatch is destroyed
12491 // when the TryCatch is destroyed.
12492 exception = Local<Value>::New(try_catch.Exception());
12494 v8::ThrowException(exception);
12499 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
12500 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12501 ApiTestFuzzer::Fuzz();
12502 v8::Unlocker unlocker(CcTest::default_isolate());
12503 const char* code = "throw 7;";
12505 v8::Locker nested_locker(CcTest::default_isolate());
12506 v8::HandleScope scope(args.GetIsolate());
12507 v8::Handle<Value> value = CompileRun(code);
12508 CHECK(value.IsEmpty());
12509 args.GetReturnValue().Set(v8_str("foo"));
12514 // These are locking tests that don't need to be run again
12515 // as part of the locking aggregation tests.
12516 TEST(NestedLockers) {
12517 v8::Locker locker(CcTest::default_isolate());
12518 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12520 v8::HandleScope scope(env->GetIsolate());
12521 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
12522 Local<Function> fun = fun_templ->GetFunction();
12523 env->Global()->Set(v8_str("throw_in_js"), fun);
12524 Local<Script> script = v8_compile("(function () {"
12532 CHECK_EQ(91, script->Run()->Int32Value());
12536 // These are locking tests that don't need to be run again
12537 // as part of the locking aggregation tests.
12538 TEST(NestedLockersNoTryCatch) {
12539 v8::Locker locker(CcTest::default_isolate());
12541 v8::HandleScope scope(env->GetIsolate());
12542 Local<v8::FunctionTemplate> fun_templ =
12543 v8::FunctionTemplate::New(ThrowInJSNoCatch);
12544 Local<Function> fun = fun_templ->GetFunction();
12545 env->Global()->Set(v8_str("throw_in_js"), fun);
12546 Local<Script> script = v8_compile("(function () {"
12554 CHECK_EQ(91, script->Run()->Int32Value());
12558 THREADED_TEST(RecursiveLocking) {
12559 v8::Locker locker(CcTest::default_isolate());
12561 v8::Locker locker2(CcTest::default_isolate());
12562 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12567 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
12568 ApiTestFuzzer::Fuzz();
12569 v8::Unlocker unlocker(CcTest::default_isolate());
12573 THREADED_TEST(LockUnlockLock) {
12575 v8::Locker locker(CcTest::default_isolate());
12576 v8::HandleScope scope(CcTest::default_isolate());
12578 Local<v8::FunctionTemplate> fun_templ =
12579 v8::FunctionTemplate::New(UnlockForAMoment);
12580 Local<Function> fun = fun_templ->GetFunction();
12581 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
12582 Local<Script> script = v8_compile("(function () {"
12583 " unlock_for_a_moment();"
12586 CHECK_EQ(42, script->Run()->Int32Value());
12589 v8::Locker locker(CcTest::default_isolate());
12590 v8::HandleScope scope(CcTest::default_isolate());
12592 Local<v8::FunctionTemplate> fun_templ =
12593 v8::FunctionTemplate::New(UnlockForAMoment);
12594 Local<Function> fun = fun_templ->GetFunction();
12595 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
12596 Local<Script> script = v8_compile("(function () {"
12597 " unlock_for_a_moment();"
12600 CHECK_EQ(42, script->Run()->Int32Value());
12605 static int GetGlobalObjectsCount() {
12606 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
12608 i::HeapIterator it(HEAP);
12609 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
12610 if (object->IsJSGlobalObject()) count++;
12615 static void CheckSurvivingGlobalObjectsCount(int expected) {
12616 // We need to collect all garbage twice to be sure that everything
12617 // has been collected. This is because inline caches are cleared in
12618 // the first garbage collection but some of the maps have already
12619 // been marked at that point. Therefore some of the maps are not
12620 // collected until the second garbage collection.
12621 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12622 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
12623 int count = GetGlobalObjectsCount();
12625 if (count != expected) HEAP->TracePathToGlobal();
12627 CHECK_EQ(expected, count);
12631 TEST(DontLeakGlobalObjects) {
12632 // Regression test for issues 1139850 and 1174891.
12634 v8::V8::Initialize();
12636 for (int i = 0; i < 5; i++) {
12637 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12638 LocalContext context;
12640 v8::V8::ContextDisposedNotification();
12641 CheckSurvivingGlobalObjectsCount(0);
12643 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12644 LocalContext context;
12645 v8_compile("Date")->Run();
12647 v8::V8::ContextDisposedNotification();
12648 CheckSurvivingGlobalObjectsCount(0);
12650 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12651 LocalContext context;
12652 v8_compile("/aaa/")->Run();
12654 v8::V8::ContextDisposedNotification();
12655 CheckSurvivingGlobalObjectsCount(0);
12657 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12658 const char* extension_list[] = { "v8/gc" };
12659 v8::ExtensionConfiguration extensions(1, extension_list);
12660 LocalContext context(&extensions);
12661 v8_compile("gc();")->Run();
12663 v8::V8::ContextDisposedNotification();
12664 CheckSurvivingGlobalObjectsCount(0);
12669 struct CopyablePersistentTraits {
12670 typedef Persistent<T, CopyablePersistentTraits<T> > CopyablePersistent;
12671 static const bool kResetInDestructor = true;
12672 template<class S, class M>
12673 static V8_INLINE void Copy(const Persistent<S, M>& source,
12674 CopyablePersistent* dest) {
12675 // do nothing, just allow copy
12680 TEST(CopyablePersistent) {
12681 LocalContext context;
12682 v8::Isolate* isolate = context->GetIsolate();
12683 i::GlobalHandles* globals =
12684 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
12685 int initial_handles = globals->global_handles_count();
12687 v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> > handle1;
12689 v8::HandleScope scope(isolate);
12690 handle1.Reset(isolate, v8::Object::New());
12692 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
12693 v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> > handle2;
12695 CHECK(handle1 == handle2);
12696 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
12697 v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> >
12699 CHECK(handle1 == handle3);
12700 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
12702 // Verify autodispose
12703 CHECK_EQ(initial_handles, globals->global_handles_count());
12707 static void WeakApiCallback(
12708 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
12709 Local<Value> value = data.GetValue()->Get(v8_str("key"));
12710 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
12711 data.GetParameter()->Reset();
12712 delete data.GetParameter();
12716 TEST(WeakCallbackApi) {
12717 LocalContext context;
12718 v8::Isolate* isolate = context->GetIsolate();
12719 i::GlobalHandles* globals =
12720 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
12721 int initial_handles = globals->global_handles_count();
12723 v8::HandleScope scope(isolate);
12724 v8::Local<v8::Object> obj = v8::Object::New();
12725 obj->Set(v8_str("key"), v8::Integer::New(231, isolate));
12726 v8::Persistent<v8::Object>* handle =
12727 new v8::Persistent<v8::Object>(isolate, obj);
12728 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
12731 reinterpret_cast<i::Isolate*>(isolate)->heap()->
12732 CollectAllGarbage(i::Heap::kNoGCFlags);
12733 // Verify disposed.
12734 CHECK_EQ(initial_handles, globals->global_handles_count());
12738 v8::Persistent<v8::Object> some_object;
12739 v8::Persistent<v8::Object> bad_handle;
12741 void NewPersistentHandleCallback(v8::Isolate* isolate,
12742 v8::Persistent<v8::Value>* handle,
12744 v8::HandleScope scope(isolate);
12745 bad_handle.Reset(isolate, some_object);
12750 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
12751 LocalContext context;
12752 v8::Isolate* isolate = context->GetIsolate();
12754 v8::Persistent<v8::Object> handle1, handle2;
12756 v8::HandleScope scope(isolate);
12757 some_object.Reset(isolate, v8::Object::New());
12758 handle1.Reset(isolate, v8::Object::New());
12759 handle2.Reset(isolate, v8::Object::New());
12761 // Note: order is implementation dependent alas: currently
12762 // global handle nodes are processed by PostGarbageCollectionProcessing
12763 // in reverse allocation order, so if second allocated handle is deleted,
12764 // weak callback of the first handle would be able to 'reallocate' it.
12765 handle1.MakeWeak<v8::Value, void>(NULL, NewPersistentHandleCallback);
12767 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12771 v8::Persistent<v8::Object> to_be_disposed;
12773 void DisposeAndForceGcCallback(v8::Isolate* isolate,
12774 v8::Persistent<v8::Value>* handle,
12776 to_be_disposed.Dispose();
12777 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12782 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
12783 LocalContext context;
12784 v8::Isolate* isolate = context->GetIsolate();
12786 v8::Persistent<v8::Object> handle1, handle2;
12788 v8::HandleScope scope(isolate);
12789 handle1.Reset(isolate, v8::Object::New());
12790 handle2.Reset(isolate, v8::Object::New());
12792 handle1.MakeWeak<v8::Value, void>(NULL, DisposeAndForceGcCallback);
12793 to_be_disposed.Reset(isolate, handle2);
12794 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12797 void DisposingCallback(v8::Isolate* isolate,
12798 v8::Persistent<v8::Value>* handle,
12803 void HandleCreatingCallback(v8::Isolate* isolate,
12804 v8::Persistent<v8::Value>* handle,
12806 v8::HandleScope scope(isolate);
12807 v8::Persistent<v8::Object>(isolate, v8::Object::New());
12812 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
12813 LocalContext context;
12814 v8::Isolate* isolate = context->GetIsolate();
12816 v8::Persistent<v8::Object> handle1, handle2, handle3;
12818 v8::HandleScope scope(isolate);
12819 handle3.Reset(isolate, v8::Object::New());
12820 handle2.Reset(isolate, v8::Object::New());
12821 handle1.Reset(isolate, v8::Object::New());
12823 handle2.MakeWeak<v8::Value, void>(NULL, DisposingCallback);
12824 handle3.MakeWeak<v8::Value, void>(NULL, HandleCreatingCallback);
12825 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12829 THREADED_TEST(CheckForCrossContextObjectLiterals) {
12830 v8::V8::Initialize();
12833 const char* sources[nof] = {
12834 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
12838 for (int i = 0; i < nof; i++) {
12839 const char* source = sources[i];
12840 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12841 LocalContext context;
12842 CompileRun(source);
12844 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12845 LocalContext context;
12846 CompileRun(source);
12852 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
12853 v8::HandleScope inner(env->GetIsolate());
12855 v8::Handle<Value> three = v8_num(3);
12856 v8::Handle<Value> value = inner.Close(three);
12862 THREADED_TEST(NestedHandleScopeAndContexts) {
12863 v8::Isolate* isolate = v8::Isolate::GetCurrent();
12864 v8::HandleScope outer(isolate);
12865 v8::Local<Context> env = Context::New(isolate);
12867 v8::Handle<Value> value = NestedScope(env);
12868 v8::Handle<String> str(value->ToString());
12869 CHECK(!str.IsEmpty());
12874 static bool MatchPointers(void* key1, void* key2) {
12875 return key1 == key2;
12879 struct SymbolInfo {
12886 class SetFunctionEntryHookTest {
12888 SetFunctionEntryHookTest() {
12889 CHECK(instance_ == NULL);
12892 ~SetFunctionEntryHookTest() {
12893 CHECK(instance_ == this);
12898 symbol_locations_.clear();
12899 invocations_.clear();
12902 void OnJitEvent(const v8::JitCodeEvent* event);
12903 static void JitEvent(const v8::JitCodeEvent* event) {
12904 CHECK(instance_ != NULL);
12905 instance_->OnJitEvent(event);
12908 void OnEntryHook(uintptr_t function,
12909 uintptr_t return_addr_location);
12910 static void EntryHook(uintptr_t function,
12911 uintptr_t return_addr_location) {
12912 CHECK(instance_ != NULL);
12913 instance_->OnEntryHook(function, return_addr_location);
12916 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12917 CHECK(instance_ != NULL);
12918 args.GetReturnValue().Set(v8_num(42));
12920 void RunLoopInNewEnv(v8::Isolate* isolate);
12922 // Records addr as location of symbol.
12923 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
12925 // Finds the symbol containing addr
12926 SymbolInfo* FindSymbolForAddr(i::Address addr);
12927 // Returns the number of invocations where the caller name contains
12928 // \p caller_name and the function name contains \p function_name.
12929 int CountInvocations(const char* caller_name,
12930 const char* function_name);
12932 i::Handle<i::JSFunction> foo_func_;
12933 i::Handle<i::JSFunction> bar_func_;
12935 typedef std::map<size_t, SymbolInfo> SymbolMap;
12936 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
12937 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
12938 SymbolMap symbols_;
12939 SymbolLocationMap symbol_locations_;
12940 InvocationMap invocations_;
12942 static SetFunctionEntryHookTest* instance_;
12944 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
12947 // Returns true if addr is in the range [start, start+len).
12948 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
12949 if (start <= addr && start + len > addr)
12955 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
12956 SymbolInfo* symbol) {
12957 // Insert the symbol at the new location.
12958 SymbolLocationMap::iterator it =
12959 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
12960 // Now erase symbols to the left and right that overlap this one.
12961 while (it != symbol_locations_.begin()) {
12962 SymbolLocationMap::iterator left = it;
12964 if (!Overlaps(left->first, left->second->size, addr))
12966 symbol_locations_.erase(left);
12969 // Now erase symbols to the left and right that overlap this one.
12971 SymbolLocationMap::iterator right = it;
12973 if (right == symbol_locations_.end())
12975 if (!Overlaps(addr, symbol->size, right->first))
12977 symbol_locations_.erase(right);
12982 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
12983 switch (event->type) {
12984 case v8::JitCodeEvent::CODE_ADDED: {
12985 CHECK(event->code_start != NULL);
12986 CHECK_NE(0, static_cast<int>(event->code_len));
12987 CHECK(event->name.str != NULL);
12988 size_t symbol_id = symbols_.size();
12990 // Record the new symbol.
12991 SymbolInfo& info = symbols_[symbol_id];
12992 info.id = symbol_id;
12993 info.size = event->code_len;
12994 info.name.assign(event->name.str, event->name.str + event->name.len);
12996 // And record it's location.
12997 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13001 case v8::JitCodeEvent::CODE_MOVED: {
13002 // We would like to never see code move that we haven't seen before,
13003 // but the code creation event does not happen until the line endings
13004 // have been calculated (this is so that we can report the line in the
13005 // script at which the function source is found, see
13006 // Compiler::RecordFunctionCompilation) and the line endings
13007 // calculations can cause a GC, which can move the newly created code
13008 // before its existence can be logged.
13009 SymbolLocationMap::iterator it(
13010 symbol_locations_.find(
13011 reinterpret_cast<i::Address>(event->code_start)));
13012 if (it != symbol_locations_.end()) {
13013 // Found a symbol at this location, move it.
13014 SymbolInfo* info = it->second;
13015 symbol_locations_.erase(it);
13016 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13025 void SetFunctionEntryHookTest::OnEntryHook(
13026 uintptr_t function, uintptr_t return_addr_location) {
13027 // Get the function's code object.
13028 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13029 reinterpret_cast<i::Address>(function));
13030 CHECK(function_code != NULL);
13032 // Then try and look up the caller's code object.
13033 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13035 // Count the invocation.
13036 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13037 SymbolInfo* function_symbol =
13038 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13039 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13041 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13042 // Check that we have a symbol for the "bar" function at the right location.
13043 SymbolLocationMap::iterator it(
13044 symbol_locations_.find(function_code->instruction_start()));
13045 CHECK(it != symbol_locations_.end());
13048 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13049 // Check that we have a symbol for "foo" at the right location.
13050 SymbolLocationMap::iterator it(
13051 symbol_locations_.find(function_code->instruction_start()));
13052 CHECK(it != symbol_locations_.end());
13057 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13058 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13059 // Do we have a direct hit on a symbol?
13060 if (it != symbol_locations_.end()) {
13061 if (it->first == addr)
13065 // If not a direct hit, it'll have to be the previous symbol.
13066 if (it == symbol_locations_.begin())
13070 size_t offs = addr - it->first;
13071 if (offs < it->second->size)
13078 int SetFunctionEntryHookTest::CountInvocations(
13079 const char* caller_name, const char* function_name) {
13080 InvocationMap::iterator it(invocations_.begin());
13081 int invocations = 0;
13082 for (; it != invocations_.end(); ++it) {
13083 SymbolInfo* caller = it->first.first;
13084 SymbolInfo* function = it->first.second;
13086 // Filter out non-matching functions.
13087 if (function_name != NULL) {
13088 if (function->name.find(function_name) == std::string::npos)
13092 // Filter out non-matching callers.
13093 if (caller_name != NULL) {
13094 if (caller == NULL)
13096 if (caller->name.find(caller_name) == std::string::npos)
13100 // It matches add the invocation count to the tally.
13101 invocations += it->second;
13104 return invocations;
13108 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13109 v8::HandleScope outer(isolate);
13110 v8::Local<Context> env = Context::New(isolate);
13113 Local<ObjectTemplate> t = ObjectTemplate::New();
13114 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(RuntimeCallback));
13115 env->Global()->Set(v8_str("obj"), t->NewInstance());
13117 const char* script =
13118 "function bar() {\n"
13120 " for (i = 0; i < 100; ++i)\n"
13124 "function foo(i) { return i * i; }\n"
13125 "// Invoke on the runtime function.\n"
13127 CompileRun(script);
13128 bar_func_ = i::Handle<i::JSFunction>::cast(
13129 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
13130 ASSERT(!bar_func_.is_null());
13133 i::Handle<i::JSFunction>::cast(
13134 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
13135 ASSERT(!foo_func_.is_null());
13137 v8::Handle<v8::Value> value = CompileRun("bar();");
13138 CHECK(value->IsNumber());
13139 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13141 // Test the optimized codegen path.
13142 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
13144 CHECK(value->IsNumber());
13145 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13151 void SetFunctionEntryHookTest::RunTest() {
13152 // Work in a new isolate throughout.
13153 v8::Isolate* isolate = v8::Isolate::New();
13155 // Test setting the entry hook on the new isolate.
13156 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13158 // Replacing the hook, once set should fail.
13159 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13162 v8::Isolate::Scope scope(isolate);
13164 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
13166 RunLoopInNewEnv(isolate);
13168 // Check the exepected invocation counts.
13169 CHECK_EQ(2, CountInvocations(NULL, "bar"));
13170 CHECK_EQ(200, CountInvocations("bar", "foo"));
13171 CHECK_EQ(200, CountInvocations(NULL, "foo"));
13173 // Verify that we have an entry hook on some specific stubs.
13174 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
13175 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
13176 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
13178 isolate->Dispose();
13182 // Make sure a second isolate is unaffected by the previous entry hook.
13183 isolate = v8::Isolate::New();
13185 v8::Isolate::Scope scope(isolate);
13187 // Reset the entry count to zero and set the entry hook.
13188 RunLoopInNewEnv(isolate);
13190 // We should record no invocations in this isolate.
13191 CHECK_EQ(0, static_cast<int>(invocations_.size()));
13193 // Since the isolate has been used, we shouldn't be able to set an entry
13195 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13197 isolate->Dispose();
13201 TEST(SetFunctionEntryHook) {
13202 // FunctionEntryHook does not work well with experimental natives.
13203 // Experimental natives are compiled during snapshot deserialization.
13204 // This test breaks because InstallGetter (function from snapshot that
13205 // only gets called from experimental natives) is compiled with entry hooks.
13206 i::FLAG_allow_natives_syntax = true;
13207 i::FLAG_use_inlining = false;
13209 SetFunctionEntryHookTest test;
13214 static i::HashMap* code_map = NULL;
13215 static i::HashMap* jitcode_line_info = NULL;
13216 static int saw_bar = 0;
13217 static int move_events = 0;
13220 static bool FunctionNameIs(const char* expected,
13221 const v8::JitCodeEvent* event) {
13222 // Log lines for functions are of the general form:
13223 // "LazyCompile:<type><function_name>", where the type is one of
13225 static const char kPreamble[] = "LazyCompile:";
13226 static size_t kPreambleLen = sizeof(kPreamble) - 1;
13228 if (event->name.len < sizeof(kPreamble) - 1 ||
13229 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
13233 const char* tail = event->name.str + kPreambleLen;
13234 size_t tail_len = event->name.len - kPreambleLen;
13235 size_t expected_len = strlen(expected);
13236 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
13241 // Check for tails like 'bar :1'.
13242 if (tail_len > expected_len + 2 &&
13243 tail[expected_len] == ' ' &&
13244 tail[expected_len + 1] == ':' &&
13245 tail[expected_len + 2] &&
13246 !strncmp(tail, expected, expected_len)) {
13250 if (tail_len != expected_len)
13253 return strncmp(tail, expected, expected_len) == 0;
13257 static void event_handler(const v8::JitCodeEvent* event) {
13258 CHECK(event != NULL);
13259 CHECK(code_map != NULL);
13260 CHECK(jitcode_line_info != NULL);
13262 class DummyJitCodeLineInfo {
13265 switch (event->type) {
13266 case v8::JitCodeEvent::CODE_ADDED: {
13267 CHECK(event->code_start != NULL);
13268 CHECK_NE(0, static_cast<int>(event->code_len));
13269 CHECK(event->name.str != NULL);
13270 i::HashMap::Entry* entry =
13271 code_map->Lookup(event->code_start,
13272 i::ComputePointerHash(event->code_start),
13274 entry->value = reinterpret_cast<void*>(event->code_len);
13276 if (FunctionNameIs("bar", event)) {
13282 case v8::JitCodeEvent::CODE_MOVED: {
13283 uint32_t hash = i::ComputePointerHash(event->code_start);
13284 // We would like to never see code move that we haven't seen before,
13285 // but the code creation event does not happen until the line endings
13286 // have been calculated (this is so that we can report the line in the
13287 // script at which the function source is found, see
13288 // Compiler::RecordFunctionCompilation) and the line endings
13289 // calculations can cause a GC, which can move the newly created code
13290 // before its existence can be logged.
13291 i::HashMap::Entry* entry =
13292 code_map->Lookup(event->code_start, hash, false);
13293 if (entry != NULL) {
13296 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
13297 code_map->Remove(event->code_start, hash);
13299 entry = code_map->Lookup(event->new_code_start,
13300 i::ComputePointerHash(event->new_code_start),
13302 CHECK(entry != NULL);
13303 entry->value = reinterpret_cast<void*>(event->code_len);
13308 case v8::JitCodeEvent::CODE_REMOVED:
13309 // Object/code removal events are currently not dispatched from the GC.
13313 // For CODE_START_LINE_INFO_RECORDING event, we will create one
13314 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
13315 // record it in jitcode_line_info.
13316 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
13317 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
13318 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
13319 temp_event->user_data = line_info;
13320 i::HashMap::Entry* entry =
13321 jitcode_line_info->Lookup(line_info,
13322 i::ComputePointerHash(line_info),
13324 entry->value = reinterpret_cast<void*>(line_info);
13327 // For these two events, we will check whether the event->user_data
13328 // data structure is created before during CODE_START_LINE_INFO_RECORDING
13329 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
13330 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
13331 CHECK(event->user_data != NULL);
13332 uint32_t hash = i::ComputePointerHash(event->user_data);
13333 i::HashMap::Entry* entry =
13334 jitcode_line_info->Lookup(event->user_data, hash, false);
13335 CHECK(entry != NULL);
13336 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
13340 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
13341 CHECK(event->user_data != NULL);
13342 uint32_t hash = i::ComputePointerHash(event->user_data);
13343 i::HashMap::Entry* entry =
13344 jitcode_line_info->Lookup(event->user_data, hash, false);
13345 CHECK(entry != NULL);
13350 // Impossible event.
13357 TEST(SetJitCodeEventHandler) {
13358 i::FLAG_stress_compaction = true;
13359 i::FLAG_incremental_marking = false;
13360 const char* script =
13363 " for (i = 0; i < 100; ++i)"
13367 "function foo(i) { return i * i; };"
13370 // Run this test in a new isolate to make sure we don't
13371 // have remnants of state from other code.
13372 v8::Isolate* isolate = v8::Isolate::New();
13376 v8::HandleScope scope(isolate);
13377 i::HashMap code(MatchPointers);
13380 i::HashMap lineinfo(MatchPointers);
13381 jitcode_line_info = &lineinfo;
13386 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
13388 // Generate new code objects sparsely distributed across several
13389 // different fragmented code-space pages.
13390 const int kIterations = 10;
13391 for (int i = 0; i < kIterations; ++i) {
13393 i::AlwaysAllocateScope always_allocate;
13394 SimulateFullSpace(HEAP->code_space());
13395 CompileRun(script);
13397 // Keep a strong reference to the code object in the handle scope.
13398 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
13399 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
13400 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
13401 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
13403 // Clear the compilation cache to get more wastage.
13404 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
13407 // Force code movement.
13408 HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
13410 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
13412 CHECK_LE(kIterations, saw_bar);
13413 CHECK_LT(0, move_events);
13416 jitcode_line_info = NULL;
13420 isolate->Dispose();
13422 // Do this in a new isolate.
13423 isolate = v8::Isolate::New();
13426 // Verify that we get callbacks for existing code objects when we
13427 // request enumeration of existing code.
13429 v8::HandleScope scope(isolate);
13431 CompileRun(script);
13433 // Now get code through initial iteration.
13434 i::HashMap code(MatchPointers);
13437 i::HashMap lineinfo(MatchPointers);
13438 jitcode_line_info = &lineinfo;
13440 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
13441 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
13443 jitcode_line_info = NULL;
13444 // We expect that we got some events. Note that if we could get code removal
13445 // notifications, we could compare two collections, one created by listening
13446 // from the time of creation of an isolate, and the other by subscribing
13447 // with EnumExisting.
13448 CHECK_LT(0, code.occupancy());
13454 isolate->Dispose();
13458 static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
13461 THREADED_TEST(ExternalAllocatedMemory) {
13462 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13463 v8::HandleScope outer(isolate);
13464 v8::Local<Context> env(Context::New(isolate));
13465 CHECK(!env.IsEmpty());
13466 const intptr_t kSize = 1024*1024;
13467 int64_t baseline = cast(isolate->AdjustAmountOfExternalAllocatedMemory(0));
13468 CHECK_EQ(baseline + cast(kSize),
13469 cast(isolate->AdjustAmountOfExternalAllocatedMemory(kSize)));
13471 cast(isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)));
13475 THREADED_TEST(DisposeEnteredContext) {
13476 LocalContext outer;
13477 v8::Isolate* isolate = outer->GetIsolate();
13478 v8::Persistent<v8::Context> inner;
13480 v8::HandleScope scope(isolate);
13481 inner.Reset(isolate, v8::Context::New(isolate));
13483 v8::HandleScope scope(isolate);
13485 // Don't want a handle here, so do this unsafely
13486 v8::Handle<v8::Context> inner_local =
13487 v8::Utils::Convert<i::Object, v8::Context>(
13488 v8::Utils::OpenPersistent(inner));
13489 inner_local->Enter();
13492 inner_local->Exit();
13497 // Regression test for issue 54, object templates with internal fields
13498 // but no accessors or interceptors did not get their internal field
13499 // count set on instances.
13500 THREADED_TEST(Regress54) {
13501 LocalContext context;
13502 v8::Isolate* isolate = context->GetIsolate();
13503 v8::HandleScope outer(isolate);
13504 static v8::Persistent<v8::ObjectTemplate> templ;
13505 if (templ.IsEmpty()) {
13506 v8::HandleScope inner(isolate);
13507 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
13508 local->SetInternalFieldCount(1);
13509 templ.Reset(isolate, inner.Close(local));
13511 v8::Handle<v8::Object> result =
13512 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
13513 CHECK_EQ(1, result->InternalFieldCount());
13517 // If part of the threaded tests, this test makes ThreadingTest fail
13519 TEST(CatchStackOverflow) {
13520 LocalContext context;
13521 v8::HandleScope scope(context->GetIsolate());
13522 v8::TryCatch try_catch;
13523 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
13529 v8::Handle<v8::Value> result = script->Run();
13530 CHECK(result.IsEmpty());
13534 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
13535 const char* resource_name,
13537 v8::HandleScope scope(v8::Isolate::GetCurrent());
13538 v8::TryCatch try_catch;
13539 v8::Handle<v8::Value> result = script->Run();
13540 CHECK(result.IsEmpty());
13541 CHECK(try_catch.HasCaught());
13542 v8::Handle<v8::Message> message = try_catch.Message();
13543 CHECK(!message.IsEmpty());
13544 CHECK_EQ(10 + line_offset, message->GetLineNumber());
13545 CHECK_EQ(91, message->GetStartPosition());
13546 CHECK_EQ(92, message->GetEndPosition());
13547 CHECK_EQ(2, message->GetStartColumn());
13548 CHECK_EQ(3, message->GetEndColumn());
13549 v8::String::Utf8Value line(message->GetSourceLine());
13550 CHECK_EQ(" throw 'nirk';", *line);
13551 v8::String::Utf8Value name(message->GetScriptResourceName());
13552 CHECK_EQ(resource_name, *name);
13556 THREADED_TEST(TryCatchSourceInfo) {
13557 LocalContext context;
13558 v8::HandleScope scope(context->GetIsolate());
13559 v8::Handle<v8::String> source = v8::String::New(
13560 "function Foo() {\n"
13564 "function Bar() {\n"
13568 "function Baz() {\n"
13574 const char* resource_name;
13575 v8::Handle<v8::Script> script;
13576 resource_name = "test.js";
13577 script = v8::Script::Compile(source, v8::String::New(resource_name));
13578 CheckTryCatchSourceInfo(script, resource_name, 0);
13580 resource_name = "test1.js";
13581 v8::ScriptOrigin origin1(v8::String::New(resource_name));
13582 script = v8::Script::Compile(source, &origin1);
13583 CheckTryCatchSourceInfo(script, resource_name, 0);
13585 resource_name = "test2.js";
13586 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
13587 script = v8::Script::Compile(source, &origin2);
13588 CheckTryCatchSourceInfo(script, resource_name, 7);
13592 THREADED_TEST(CompilationCache) {
13593 LocalContext context;
13594 v8::HandleScope scope(context->GetIsolate());
13595 v8::Handle<v8::String> source0 = v8::String::New("1234");
13596 v8::Handle<v8::String> source1 = v8::String::New("1234");
13597 v8::Handle<v8::Script> script0 =
13598 v8::Script::Compile(source0, v8::String::New("test.js"));
13599 v8::Handle<v8::Script> script1 =
13600 v8::Script::Compile(source1, v8::String::New("test.js"));
13601 v8::Handle<v8::Script> script2 =
13602 v8::Script::Compile(source0); // different origin
13603 CHECK_EQ(1234, script0->Run()->Int32Value());
13604 CHECK_EQ(1234, script1->Run()->Int32Value());
13605 CHECK_EQ(1234, script2->Run()->Int32Value());
13609 static void FunctionNameCallback(
13610 const v8::FunctionCallbackInfo<v8::Value>& args) {
13611 ApiTestFuzzer::Fuzz();
13612 args.GetReturnValue().Set(v8_num(42));
13616 THREADED_TEST(CallbackFunctionName) {
13617 LocalContext context;
13618 v8::HandleScope scope(context->GetIsolate());
13619 Local<ObjectTemplate> t = ObjectTemplate::New();
13620 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
13621 context->Global()->Set(v8_str("obj"), t->NewInstance());
13622 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
13623 CHECK(value->IsString());
13624 v8::String::Utf8Value name(value);
13625 CHECK_EQ("asdf", *name);
13629 THREADED_TEST(DateAccess) {
13630 LocalContext context;
13631 v8::HandleScope scope(context->GetIsolate());
13632 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
13633 CHECK(date->IsDate());
13634 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
13638 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
13639 v8::Handle<v8::Object> obj = val.As<v8::Object>();
13640 v8::Handle<v8::Array> props = obj->GetPropertyNames();
13641 CHECK_EQ(elmc, props->Length());
13642 for (int i = 0; i < elmc; i++) {
13643 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
13644 CHECK_EQ(elmv[i], *elm);
13649 void CheckOwnProperties(v8::Handle<v8::Value> val,
13651 const char* elmv[]) {
13652 v8::Handle<v8::Object> obj = val.As<v8::Object>();
13653 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
13654 CHECK_EQ(elmc, props->Length());
13655 for (int i = 0; i < elmc; i++) {
13656 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
13657 CHECK_EQ(elmv[i], *elm);
13662 THREADED_TEST(PropertyEnumeration) {
13663 LocalContext context;
13664 v8::HandleScope scope(context->GetIsolate());
13665 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
13668 "result[1] = {a: 1, b: 2};"
13669 "result[2] = [1, 2, 3];"
13670 "var proto = {x: 1, y: 2, z: 3};"
13671 "var x = { __proto__: proto, w: 0, z: 1 };"
13673 "result;"))->Run();
13674 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
13675 CHECK_EQ(4, elms->Length());
13677 const char** elmv0 = NULL;
13678 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13679 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13681 const char* elmv1[] = {"a", "b"};
13682 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
13683 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
13685 const char* elmv2[] = {"0", "1", "2"};
13686 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
13687 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
13689 const char* elmv3[] = {"w", "z", "x", "y"};
13690 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
13692 const char* elmv4[] = {"w", "z"};
13693 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
13697 THREADED_TEST(PropertyEnumeration2) {
13698 LocalContext context;
13699 v8::HandleScope scope(context->GetIsolate());
13700 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
13703 "result[1] = {a: 1, b: 2};"
13704 "result[2] = [1, 2, 3];"
13705 "var proto = {x: 1, y: 2, z: 3};"
13706 "var x = { __proto__: proto, w: 0, z: 1 };"
13708 "result;"))->Run();
13709 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
13710 CHECK_EQ(4, elms->Length());
13712 const char** elmv0 = NULL;
13713 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13715 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
13716 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
13717 CHECK_EQ(0, props->Length());
13718 for (uint32_t i = 0; i < props->Length(); i++) {
13719 printf("p[%d]\n", i);
13723 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
13725 v8::AccessType type,
13726 Local<Value> data) {
13727 return type != v8::ACCESS_SET;
13731 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
13733 v8::AccessType type,
13734 Local<Value> data) {
13735 return type != v8::ACCESS_SET;
13739 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
13740 LocalContext context;
13741 v8::HandleScope scope(context->GetIsolate());
13742 Local<ObjectTemplate> templ = ObjectTemplate::New();
13743 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
13744 IndexedSetAccessBlocker);
13745 templ->Set(v8_str("x"), v8::True());
13746 Local<v8::Object> instance = templ->NewInstance();
13747 context->Global()->Set(v8_str("obj"), instance);
13748 Local<Value> value = CompileRun("obj.x");
13749 CHECK(value->BooleanValue());
13753 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
13755 v8::AccessType type,
13756 Local<Value> data) {
13761 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
13763 v8::AccessType type,
13764 Local<Value> data) {
13770 THREADED_TEST(AccessChecksReenabledCorrectly) {
13771 LocalContext context;
13772 v8::HandleScope scope(context->GetIsolate());
13773 Local<ObjectTemplate> templ = ObjectTemplate::New();
13774 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13775 IndexedGetAccessBlocker);
13776 templ->Set(v8_str("a"), v8_str("a"));
13777 // Add more than 8 (see kMaxFastProperties) properties
13778 // so that the constructor will force copying map.
13779 // Cannot sprintf, gcc complains unsafety.
13781 for (char i = '0'; i <= '9' ; i++) {
13783 for (char j = '0'; j <= '9'; j++) {
13785 for (char k = '0'; k <= '9'; k++) {
13788 templ->Set(v8_str(buf), v8::Number::New(k));
13793 Local<v8::Object> instance_1 = templ->NewInstance();
13794 context->Global()->Set(v8_str("obj_1"), instance_1);
13796 Local<Value> value_1 = CompileRun("obj_1.a");
13797 CHECK(value_1->IsUndefined());
13799 Local<v8::Object> instance_2 = templ->NewInstance();
13800 context->Global()->Set(v8_str("obj_2"), instance_2);
13802 Local<Value> value_2 = CompileRun("obj_2.a");
13803 CHECK(value_2->IsUndefined());
13807 // This tests that access check information remains on the global
13808 // object template when creating contexts.
13809 THREADED_TEST(AccessControlRepeatedContextCreation) {
13810 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13811 v8::HandleScope handle_scope(isolate);
13812 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13813 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
13814 IndexedSetAccessBlocker);
13815 i::Handle<i::ObjectTemplateInfo> internal_template =
13816 v8::Utils::OpenHandle(*global_template);
13817 CHECK(!internal_template->constructor()->IsUndefined());
13818 i::Handle<i::FunctionTemplateInfo> constructor(
13819 i::FunctionTemplateInfo::cast(internal_template->constructor()));
13820 CHECK(!constructor->access_check_info()->IsUndefined());
13821 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
13822 CHECK(!context0.IsEmpty());
13823 CHECK(!constructor->access_check_info()->IsUndefined());
13827 THREADED_TEST(TurnOnAccessCheck) {
13828 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13829 v8::HandleScope handle_scope(isolate);
13831 // Create an environment with access check to the global object disabled by
13833 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13834 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13835 IndexedGetAccessBlocker,
13836 v8::Handle<v8::Value>(),
13838 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
13839 Context::Scope context_scope(context);
13841 // Set up a property and a number of functions.
13842 context->Global()->Set(v8_str("a"), v8_num(1));
13843 CompileRun("function f1() {return a;}"
13844 "function f2() {return a;}"
13845 "function g1() {return h();}"
13846 "function g2() {return h();}"
13847 "function h() {return 1;}");
13848 Local<Function> f1 =
13849 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
13850 Local<Function> f2 =
13851 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
13852 Local<Function> g1 =
13853 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
13854 Local<Function> g2 =
13855 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
13856 Local<Function> h =
13857 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
13859 // Get the global object.
13860 v8::Handle<v8::Object> global = context->Global();
13862 // Call f1 one time and f2 a number of times. This will ensure that f1 still
13863 // uses the runtime system to retreive property a whereas f2 uses global load
13865 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
13866 for (int i = 0; i < 4; i++) {
13867 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
13870 // Same for g1 and g2.
13871 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
13872 for (int i = 0; i < 4; i++) {
13873 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
13876 // Detach the global and turn on access check.
13877 context->DetachGlobal();
13878 context->Global()->TurnOnAccessCheck();
13880 // Failing access check to property get results in undefined.
13881 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
13882 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
13884 // Failing access check to function call results in exception.
13885 CHECK(g1->Call(global, 0, NULL).IsEmpty());
13886 CHECK(g2->Call(global, 0, NULL).IsEmpty());
13888 // No failing access check when just returning a constant.
13889 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
13893 static const char* kPropertyA = "a";
13894 static const char* kPropertyH = "h";
13896 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
13898 v8::AccessType type,
13899 Local<Value> data) {
13900 if (!name->IsString()) return false;
13901 i::Handle<i::String> name_handle =
13902 v8::Utils::OpenHandle(String::Cast(*name));
13903 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
13904 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
13908 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
13909 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13910 v8::HandleScope handle_scope(isolate);
13912 // Create an environment with access check to the global object disabled by
13913 // default. When the registered access checker will block access to properties
13915 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13916 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
13917 IndexedGetAccessBlocker,
13918 v8::Handle<v8::Value>(),
13920 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
13921 Context::Scope context_scope(context);
13923 // Set up a property and a number of functions.
13924 context->Global()->Set(v8_str("a"), v8_num(1));
13925 static const char* source = "function f1() {return a;}"
13926 "function f2() {return a;}"
13927 "function g1() {return h();}"
13928 "function g2() {return h();}"
13929 "function h() {return 1;}";
13931 CompileRun(source);
13932 Local<Function> f1;
13933 Local<Function> f2;
13934 Local<Function> g1;
13935 Local<Function> g2;
13937 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
13938 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
13939 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
13940 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
13941 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
13943 // Get the global object.
13944 v8::Handle<v8::Object> global = context->Global();
13946 // Call f1 one time and f2 a number of times. This will ensure that f1 still
13947 // uses the runtime system to retreive property a whereas f2 uses global load
13949 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
13950 for (int i = 0; i < 4; i++) {
13951 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
13954 // Same for g1 and g2.
13955 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
13956 for (int i = 0; i < 4; i++) {
13957 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
13960 // Detach the global and turn on access check now blocking access to property
13961 // a and function h.
13962 context->DetachGlobal();
13963 context->Global()->TurnOnAccessCheck();
13965 // Failing access check to property get results in undefined.
13966 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
13967 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
13969 // Failing access check to function call results in exception.
13970 CHECK(g1->Call(global, 0, NULL).IsEmpty());
13971 CHECK(g2->Call(global, 0, NULL).IsEmpty());
13973 // No failing access check when just returning a constant.
13974 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
13976 // Now compile the source again. And get the newly compiled functions, except
13977 // for h for which access is blocked.
13978 CompileRun(source);
13979 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
13980 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
13981 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
13982 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
13983 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
13985 // Failing access check to property get results in undefined.
13986 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
13987 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
13989 // Failing access check to function call results in exception.
13990 CHECK(g1->Call(global, 0, NULL).IsEmpty());
13991 CHECK(g2->Call(global, 0, NULL).IsEmpty());
13995 // This test verifies that pre-compilation (aka preparsing) can be called
13996 // without initializing the whole VM. Thus we cannot run this test in a
13997 // multi-threaded setup.
13999 // TODO(155): This test would break without the initialization of V8. This is
14000 // a workaround for now to make this test not fail.
14001 v8::V8::Initialize();
14002 const char* script = "function foo(a) { return a+1; }";
14003 v8::ScriptData* sd =
14004 v8::ScriptData::PreCompile(script, i::StrLength(script));
14005 CHECK_NE(sd->Length(), 0);
14006 CHECK_NE(sd->Data(), NULL);
14007 CHECK(!sd->HasError());
14012 TEST(PreCompileWithError) {
14013 v8::V8::Initialize();
14014 const char* script = "function foo(a) { return 1 * * 2; }";
14015 v8::ScriptData* sd =
14016 v8::ScriptData::PreCompile(script, i::StrLength(script));
14017 CHECK(sd->HasError());
14022 TEST(Regress31661) {
14023 v8::V8::Initialize();
14024 const char* script = " The Definintive Guide";
14025 v8::ScriptData* sd =
14026 v8::ScriptData::PreCompile(script, i::StrLength(script));
14027 CHECK(sd->HasError());
14032 // Tests that ScriptData can be serialized and deserialized.
14033 TEST(PreCompileSerialization) {
14034 v8::V8::Initialize();
14035 const char* script = "function foo(a) { return a+1; }";
14036 v8::ScriptData* sd =
14037 v8::ScriptData::PreCompile(script, i::StrLength(script));
14040 int serialized_data_length = sd->Length();
14041 char* serialized_data = i::NewArray<char>(serialized_data_length);
14042 i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
14045 v8::ScriptData* deserialized_sd =
14046 v8::ScriptData::New(serialized_data, serialized_data_length);
14048 // Verify that the original is the same as the deserialized.
14049 CHECK_EQ(sd->Length(), deserialized_sd->Length());
14050 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
14051 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
14054 delete deserialized_sd;
14058 // Attempts to deserialize bad data.
14059 TEST(PreCompileDeserializationError) {
14060 v8::V8::Initialize();
14061 const char* data = "DONT CARE";
14062 int invalid_size = 3;
14063 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
14065 CHECK_EQ(0, sd->Length());
14071 // Attempts to deserialize bad data.
14072 TEST(PreCompileInvalidPreparseDataError) {
14073 v8::V8::Initialize();
14074 LocalContext context;
14075 v8::HandleScope scope(context->GetIsolate());
14077 const char* script = "function foo(){ return 5;}\n"
14078 "function bar(){ return 6 + 7;} foo();";
14079 v8::ScriptData* sd =
14080 v8::ScriptData::PreCompile(script, i::StrLength(script));
14081 CHECK(!sd->HasError());
14082 // ScriptDataImpl private implementation details
14083 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14084 const int kFunctionEntrySize = i::FunctionEntry::kSize;
14085 const int kFunctionEntryStartOffset = 0;
14086 const int kFunctionEntryEndOffset = 1;
14087 unsigned* sd_data =
14088 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14090 // Overwrite function bar's end position with 0.
14091 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14092 v8::TryCatch try_catch;
14094 Local<String> source = String::New(script);
14095 Local<Script> compiled_script = Script::New(source, NULL, sd);
14096 CHECK(try_catch.HasCaught());
14097 String::Utf8Value exception_value(try_catch.Message()->Get());
14098 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
14103 // Overwrite function bar's start position with 200. The function entry
14104 // will not be found when searching for it by position and we should fall
14105 // back on eager compilation.
14106 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
14107 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14108 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
14110 compiled_script = Script::New(source, NULL, sd);
14111 CHECK(!try_catch.HasCaught());
14117 // Verifies that the Handle<String> and const char* versions of the API produce
14118 // the same results (at least for one trivial case).
14119 TEST(PreCompileAPIVariationsAreSame) {
14120 v8::V8::Initialize();
14121 v8::HandleScope scope(v8::Isolate::GetCurrent());
14123 const char* cstring = "function foo(a) { return a+1; }";
14125 v8::ScriptData* sd_from_cstring =
14126 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
14128 TestAsciiResource* resource = new TestAsciiResource(cstring);
14129 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
14130 v8::String::NewExternal(resource));
14132 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
14133 v8::String::New(cstring));
14135 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
14136 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
14137 sd_from_external_string->Data(),
14138 sd_from_cstring->Length()));
14140 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
14141 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
14142 sd_from_string->Data(),
14143 sd_from_cstring->Length()));
14146 delete sd_from_cstring;
14147 delete sd_from_external_string;
14148 delete sd_from_string;
14152 // This tests that we do not allow dictionary load/call inline caches
14153 // to use functions that have not yet been compiled. The potential
14154 // problem of loading a function that has not yet been compiled can
14155 // arise because we share code between contexts via the compilation
14157 THREADED_TEST(DictionaryICLoadedFunction) {
14158 v8::HandleScope scope(v8::Isolate::GetCurrent());
14160 for (int i = 0; i < 2; i++) {
14161 LocalContext context;
14162 context->Global()->Set(v8_str("tmp"), v8::True());
14163 context->Global()->Delete(v8_str("tmp"));
14164 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14167 for (int i = 0; i < 2; i++) {
14168 LocalContext context;
14169 context->Global()->Set(v8_str("tmp"), v8::True());
14170 context->Global()->Delete(v8_str("tmp"));
14171 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14176 // Test that cross-context new calls use the context of the callee to
14177 // create the new JavaScript object.
14178 THREADED_TEST(CrossContextNew) {
14179 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14180 v8::HandleScope scope(isolate);
14181 v8::Local<Context> context0 = Context::New(isolate);
14182 v8::Local<Context> context1 = Context::New(isolate);
14184 // Allow cross-domain access.
14185 Local<String> token = v8_str("<security token>");
14186 context0->SetSecurityToken(token);
14187 context1->SetSecurityToken(token);
14189 // Set an 'x' property on the Object prototype and define a
14190 // constructor function in context0.
14192 CompileRun("Object.prototype.x = 42; function C() {};");
14195 // Call the constructor function from context0 and check that the
14196 // result has the 'x' property.
14198 context1->Global()->Set(v8_str("other"), context0->Global());
14199 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14200 CHECK(value->IsInt32());
14201 CHECK_EQ(42, value->Int32Value());
14206 class RegExpInterruptTest {
14208 RegExpInterruptTest() : block_(0) {}
14209 ~RegExpInterruptTest() {}
14212 gc_during_regexp_ = 0;
14213 regexp_success_ = false;
14214 gc_success_ = false;
14215 GCThread gc_thread(this);
14217 v8::Locker::StartPreemption(1);
14219 LongRunningRegExp();
14221 v8::Unlocker unlock(CcTest::default_isolate());
14224 v8::Locker::StopPreemption();
14225 CHECK(regexp_success_);
14226 CHECK(gc_success_);
14230 // Number of garbage collections required.
14231 static const int kRequiredGCs = 5;
14233 class GCThread : public i::Thread {
14235 explicit GCThread(RegExpInterruptTest* test)
14236 : Thread("GCThread"), test_(test) {}
14237 virtual void Run() {
14238 test_->CollectGarbage();
14241 RegExpInterruptTest* test_;
14244 void CollectGarbage() {
14246 while (gc_during_regexp_ < kRequiredGCs) {
14248 v8::Locker lock(CcTest::default_isolate());
14249 // TODO(lrn): Perhaps create some garbage before collecting.
14250 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14255 gc_success_ = true;
14258 void LongRunningRegExp() {
14259 block_.Signal(); // Enable garbage collection thread on next preemption.
14261 while (gc_during_regexp_ < kRequiredGCs) {
14262 int gc_before = gc_count_;
14264 // Match 15-30 "a"'s against 14 and a "b".
14265 const char* c_source =
14266 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
14267 ".exec('aaaaaaaaaaaaaaab') === null";
14268 Local<String> source = String::New(c_source);
14269 Local<Script> script = Script::Compile(source);
14270 Local<Value> result = script->Run();
14271 if (!result->BooleanValue()) {
14272 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
14277 // Match 15-30 "a"'s against 15 and a "b".
14278 const char* c_source =
14279 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
14280 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
14281 Local<String> source = String::New(c_source);
14282 Local<Script> script = Script::Compile(source);
14283 Local<Value> result = script->Run();
14284 if (!result->BooleanValue()) {
14285 gc_during_regexp_ = kRequiredGCs;
14289 int gc_after = gc_count_;
14290 gc_during_regexp_ += gc_after - gc_before;
14294 regexp_success_ = true;
14297 i::Semaphore block_;
14299 int gc_during_regexp_;
14300 bool regexp_success_;
14305 // Test that a regular expression execution can be interrupted and
14306 // survive a garbage collection.
14307 TEST(RegExpInterruption) {
14308 v8::Locker lock(CcTest::default_isolate());
14309 v8::V8::Initialize();
14310 v8::HandleScope scope(CcTest::default_isolate());
14311 Local<Context> local_env;
14314 local_env = env.local();
14317 // Local context should still be live.
14318 CHECK(!local_env.IsEmpty());
14319 local_env->Enter();
14321 // Should complete without problems.
14322 RegExpInterruptTest().RunTest();
14328 class ApplyInterruptTest {
14330 ApplyInterruptTest() : block_(0) {}
14331 ~ApplyInterruptTest() {}
14334 gc_during_apply_ = 0;
14335 apply_success_ = false;
14336 gc_success_ = false;
14337 GCThread gc_thread(this);
14339 v8::Locker::StartPreemption(1);
14341 LongRunningApply();
14343 v8::Unlocker unlock(CcTest::default_isolate());
14346 v8::Locker::StopPreemption();
14347 CHECK(apply_success_);
14348 CHECK(gc_success_);
14352 // Number of garbage collections required.
14353 static const int kRequiredGCs = 2;
14355 class GCThread : public i::Thread {
14357 explicit GCThread(ApplyInterruptTest* test)
14358 : Thread("GCThread"), test_(test) {}
14359 virtual void Run() {
14360 test_->CollectGarbage();
14363 ApplyInterruptTest* test_;
14366 void CollectGarbage() {
14368 while (gc_during_apply_ < kRequiredGCs) {
14370 v8::Locker lock(CcTest::default_isolate());
14371 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14376 gc_success_ = true;
14379 void LongRunningApply() {
14382 while (gc_during_apply_ < kRequiredGCs) {
14383 int gc_before = gc_count_;
14385 const char* c_source =
14386 "function do_very_little(bar) {"
14389 "for (var i = 0; i < 100000; i++) {"
14390 " do_very_little.apply(this, ['bar']);"
14392 Local<String> source = String::New(c_source);
14393 Local<Script> script = Script::Compile(source);
14394 Local<Value> result = script->Run();
14395 // Check that no exception was thrown.
14396 CHECK(!result.IsEmpty());
14398 int gc_after = gc_count_;
14399 gc_during_apply_ += gc_after - gc_before;
14402 apply_success_ = true;
14405 i::Semaphore block_;
14407 int gc_during_apply_;
14408 bool apply_success_;
14413 // Test that nothing bad happens if we get a preemption just when we were
14414 // about to do an apply().
14415 TEST(ApplyInterruption) {
14416 v8::Locker lock(CcTest::default_isolate());
14417 v8::V8::Initialize();
14418 v8::HandleScope scope(CcTest::default_isolate());
14419 Local<Context> local_env;
14422 local_env = env.local();
14425 // Local context should still be live.
14426 CHECK(!local_env.IsEmpty());
14427 local_env->Enter();
14429 // Should complete without problems.
14430 ApplyInterruptTest().RunTest();
14436 // Verify that we can clone an object
14437 TEST(ObjectClone) {
14439 v8::HandleScope scope(env->GetIsolate());
14441 const char* sample =
14443 "rv.alpha = 'hello';" \
14447 // Create an object, verify basics.
14448 Local<Value> val = CompileRun(sample);
14449 CHECK(val->IsObject());
14450 Local<v8::Object> obj = val.As<v8::Object>();
14451 obj->Set(v8_str("gamma"), v8_str("cloneme"));
14453 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
14454 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
14455 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
14458 Local<v8::Object> clone = obj->Clone();
14459 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
14460 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
14461 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
14463 // Set a property on the clone, verify each object.
14464 clone->Set(v8_str("beta"), v8::Integer::New(456));
14465 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
14466 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
14470 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
14472 explicit AsciiVectorResource(i::Vector<const char> vector)
14474 virtual ~AsciiVectorResource() {}
14475 virtual size_t length() const { return data_.length(); }
14476 virtual const char* data() const { return data_.start(); }
14478 i::Vector<const char> data_;
14482 class UC16VectorResource : public v8::String::ExternalStringResource {
14484 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
14486 virtual ~UC16VectorResource() {}
14487 virtual size_t length() const { return data_.length(); }
14488 virtual const i::uc16* data() const { return data_.start(); }
14490 i::Vector<const i::uc16> data_;
14494 static void MorphAString(i::String* string,
14495 AsciiVectorResource* ascii_resource,
14496 UC16VectorResource* uc16_resource) {
14497 CHECK(i::StringShape(string).IsExternal());
14498 if (string->IsOneByteRepresentation()) {
14499 // Check old map is not internalized or long.
14500 CHECK(string->map() == HEAP->external_ascii_string_map());
14501 // Morph external string to be TwoByte string.
14502 string->set_map(HEAP->external_string_map());
14503 i::ExternalTwoByteString* morphed =
14504 i::ExternalTwoByteString::cast(string);
14505 morphed->set_resource(uc16_resource);
14507 // Check old map is not internalized or long.
14508 CHECK(string->map() == HEAP->external_string_map());
14509 // Morph external string to be ASCII string.
14510 string->set_map(HEAP->external_ascii_string_map());
14511 i::ExternalAsciiString* morphed =
14512 i::ExternalAsciiString::cast(string);
14513 morphed->set_resource(ascii_resource);
14518 // Test that we can still flatten a string if the components it is built up
14519 // from have been turned into 16 bit strings in the mean time.
14520 THREADED_TEST(MorphCompositeStringTest) {
14521 char utf_buffer[129];
14522 const char* c_string = "Now is the time for all good men"
14523 " to come to the aid of the party";
14524 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
14527 i::Factory* factory = i::Isolate::Current()->factory();
14528 v8::HandleScope scope(env->GetIsolate());
14529 AsciiVectorResource ascii_resource(
14530 i::Vector<const char>(c_string, i::StrLength(c_string)));
14531 UC16VectorResource uc16_resource(
14532 i::Vector<const uint16_t>(two_byte_string,
14533 i::StrLength(c_string)));
14535 Local<String> lhs(v8::Utils::ToLocal(
14536 factory->NewExternalStringFromAscii(&ascii_resource)));
14537 Local<String> rhs(v8::Utils::ToLocal(
14538 factory->NewExternalStringFromAscii(&ascii_resource)));
14540 env->Global()->Set(v8_str("lhs"), lhs);
14541 env->Global()->Set(v8_str("rhs"), rhs);
14544 "var cons = lhs + rhs;"
14545 "var slice = lhs.substring(1, lhs.length - 1);"
14546 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
14548 CHECK(lhs->IsOneByte());
14549 CHECK(rhs->IsOneByte());
14551 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
14552 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
14554 // This should UTF-8 without flattening, since everything is ASCII.
14555 Handle<String> cons = v8_compile("cons")->Run().As<String>();
14556 CHECK_EQ(128, cons->Utf8Length());
14558 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
14559 CHECK_EQ(128, nchars);
14560 CHECK_EQ(0, strcmp(
14562 "Now is the time for all good men to come to the aid of the party"
14563 "Now is the time for all good men to come to the aid of the party"));
14565 // Now do some stuff to make sure the strings are flattened, etc.
14567 "/[^a-z]/.test(cons);"
14568 "/[^a-z]/.test(slice);"
14569 "/[^a-z]/.test(slice_on_cons);");
14570 const char* expected_cons =
14571 "Now is the time for all good men to come to the aid of the party"
14572 "Now is the time for all good men to come to the aid of the party";
14573 const char* expected_slice =
14574 "ow is the time for all good men to come to the aid of the part";
14575 const char* expected_slice_on_cons =
14576 "ow is the time for all good men to come to the aid of the party"
14577 "Now is the time for all good men to come to the aid of the part";
14578 CHECK_EQ(String::New(expected_cons),
14579 env->Global()->Get(v8_str("cons")));
14580 CHECK_EQ(String::New(expected_slice),
14581 env->Global()->Get(v8_str("slice")));
14582 CHECK_EQ(String::New(expected_slice_on_cons),
14583 env->Global()->Get(v8_str("slice_on_cons")));
14585 i::DeleteArray(two_byte_string);
14589 TEST(CompileExternalTwoByteSource) {
14590 LocalContext context;
14591 v8::HandleScope scope(context->GetIsolate());
14593 // This is a very short list of sources, which currently is to check for a
14594 // regression caused by r2703.
14595 const char* ascii_sources[] = {
14597 "-0.5", // This mainly testes PushBack in the Scanner.
14598 "--0.5", // This mainly testes PushBack in the Scanner.
14602 // Compile the sources as external two byte strings.
14603 for (int i = 0; ascii_sources[i] != NULL; i++) {
14604 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
14605 UC16VectorResource uc16_resource(
14606 i::Vector<const uint16_t>(two_byte_string,
14607 i::StrLength(ascii_sources[i])));
14608 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
14609 v8::Script::Compile(source);
14610 i::DeleteArray(two_byte_string);
14615 class RegExpStringModificationTest {
14617 RegExpStringModificationTest()
14620 morphs_during_regexp_(0),
14621 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
14622 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
14623 ~RegExpStringModificationTest() {}
14625 i::Factory* factory = i::Isolate::Current()->factory();
14627 regexp_success_ = false;
14628 morph_success_ = false;
14630 // Initialize the contents of two_byte_content_ to be a uc16 representation
14631 // of "aaaaaaaaaaaaaab".
14632 for (int i = 0; i < 14; i++) {
14633 two_byte_content_[i] = 'a';
14635 two_byte_content_[14] = 'b';
14637 // Create the input string for the regexp - the one we are going to change
14639 input_ = factory->NewExternalStringFromAscii(&ascii_resource_);
14641 // Inject the input as a global variable.
14642 i::Handle<i::String> input_name =
14643 factory->NewStringFromAscii(i::Vector<const char>("input", 5));
14644 i::Isolate::Current()->native_context()->global_object()->SetProperty(
14648 i::kNonStrictMode)->ToObjectChecked();
14650 MorphThread morph_thread(this);
14651 morph_thread.Start();
14652 v8::Locker::StartPreemption(1);
14653 LongRunningRegExp();
14655 v8::Unlocker unlock(CcTest::default_isolate());
14656 morph_thread.Join();
14658 v8::Locker::StopPreemption();
14659 CHECK(regexp_success_);
14660 CHECK(morph_success_);
14664 // Number of string modifications required.
14665 static const int kRequiredModifications = 5;
14666 static const int kMaxModifications = 100;
14668 class MorphThread : public i::Thread {
14670 explicit MorphThread(RegExpStringModificationTest* test)
14671 : Thread("MorphThread"), test_(test) {}
14672 virtual void Run() {
14673 test_->MorphString();
14676 RegExpStringModificationTest* test_;
14679 void MorphString() {
14681 while (morphs_during_regexp_ < kRequiredModifications &&
14682 morphs_ < kMaxModifications) {
14684 v8::Locker lock(CcTest::default_isolate());
14685 // Swap string between ascii and two-byte representation.
14686 i::String* string = *input_;
14687 MorphAString(string, &ascii_resource_, &uc16_resource_);
14692 morph_success_ = true;
14695 void LongRunningRegExp() {
14696 block_.Signal(); // Enable morphing thread on next preemption.
14697 while (morphs_during_regexp_ < kRequiredModifications &&
14698 morphs_ < kMaxModifications) {
14699 int morphs_before = morphs_;
14701 v8::HandleScope scope(v8::Isolate::GetCurrent());
14702 // Match 15-30 "a"'s against 14 and a "b".
14703 const char* c_source =
14704 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
14705 ".exec(input) === null";
14706 Local<String> source = String::New(c_source);
14707 Local<Script> script = Script::Compile(source);
14708 Local<Value> result = script->Run();
14709 CHECK(result->IsTrue());
14711 int morphs_after = morphs_;
14712 morphs_during_regexp_ += morphs_after - morphs_before;
14714 regexp_success_ = true;
14717 i::uc16 two_byte_content_[15];
14718 i::Semaphore block_;
14720 int morphs_during_regexp_;
14721 bool regexp_success_;
14722 bool morph_success_;
14723 i::Handle<i::String> input_;
14724 AsciiVectorResource ascii_resource_;
14725 UC16VectorResource uc16_resource_;
14729 // Test that a regular expression execution can be interrupted and
14730 // the string changed without failing.
14731 TEST(RegExpStringModification) {
14732 v8::Locker lock(CcTest::default_isolate());
14733 v8::V8::Initialize();
14734 v8::HandleScope scope(CcTest::default_isolate());
14735 Local<Context> local_env;
14738 local_env = env.local();
14741 // Local context should still be live.
14742 CHECK(!local_env.IsEmpty());
14743 local_env->Enter();
14745 // Should complete without problems.
14746 RegExpStringModificationTest().RunTest();
14752 // Test that we cannot set a property on the global object if there
14753 // is a read-only property in the prototype chain.
14754 TEST(ReadOnlyPropertyInGlobalProto) {
14755 i::FLAG_es5_readonly = true;
14756 v8::HandleScope scope(v8::Isolate::GetCurrent());
14757 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14758 LocalContext context(0, templ);
14759 v8::Handle<v8::Object> global = context->Global();
14760 v8::Handle<v8::Object> global_proto =
14761 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
14762 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
14763 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
14764 // Check without 'eval' or 'with'.
14765 v8::Handle<v8::Value> res =
14766 CompileRun("function f() { x = 42; return x; }; f()");
14767 CHECK_EQ(v8::Integer::New(0), res);
14768 // Check with 'eval'.
14769 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
14770 CHECK_EQ(v8::Integer::New(0), res);
14771 // Check with 'with'.
14772 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
14773 CHECK_EQ(v8::Integer::New(0), res);
14776 static int force_set_set_count = 0;
14777 static int force_set_get_count = 0;
14778 bool pass_on_get = false;
14780 static void ForceSetGetter(v8::Local<v8::String> name,
14781 const v8::PropertyCallbackInfo<v8::Value>& info) {
14782 force_set_get_count++;
14786 info.GetReturnValue().Set(3);
14789 static void ForceSetSetter(v8::Local<v8::String> name,
14790 v8::Local<v8::Value> value,
14791 const v8::PropertyCallbackInfo<void>& info) {
14792 force_set_set_count++;
14795 static void ForceSetInterceptSetter(
14796 v8::Local<v8::String> name,
14797 v8::Local<v8::Value> value,
14798 const v8::PropertyCallbackInfo<v8::Value>& info) {
14799 force_set_set_count++;
14800 info.GetReturnValue().SetUndefined();
14805 force_set_get_count = 0;
14806 force_set_set_count = 0;
14807 pass_on_get = false;
14809 v8::HandleScope scope(v8::Isolate::GetCurrent());
14810 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14811 v8::Handle<v8::String> access_property = v8::String::New("a");
14812 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
14813 LocalContext context(NULL, templ);
14814 v8::Handle<v8::Object> global = context->Global();
14816 // Ordinary properties
14817 v8::Handle<v8::String> simple_property = v8::String::New("p");
14818 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
14819 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14820 // This should fail because the property is read-only
14821 global->Set(simple_property, v8::Int32::New(5));
14822 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14823 // This should succeed even though the property is read-only
14824 global->ForceSet(simple_property, v8::Int32::New(6));
14825 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
14828 CHECK_EQ(0, force_set_set_count);
14829 CHECK_EQ(0, force_set_get_count);
14830 CHECK_EQ(3, global->Get(access_property)->Int32Value());
14831 // CHECK_EQ the property shouldn't override it, just call the setter
14832 // which in this case does nothing.
14833 global->Set(access_property, v8::Int32::New(7));
14834 CHECK_EQ(3, global->Get(access_property)->Int32Value());
14835 CHECK_EQ(1, force_set_set_count);
14836 CHECK_EQ(2, force_set_get_count);
14837 // Forcing the property to be set should override the accessor without
14839 global->ForceSet(access_property, v8::Int32::New(8));
14840 CHECK_EQ(8, global->Get(access_property)->Int32Value());
14841 CHECK_EQ(1, force_set_set_count);
14842 CHECK_EQ(2, force_set_get_count);
14846 TEST(ForceSetWithInterceptor) {
14847 force_set_get_count = 0;
14848 force_set_set_count = 0;
14849 pass_on_get = false;
14851 v8::HandleScope scope(v8::Isolate::GetCurrent());
14852 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14853 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
14854 LocalContext context(NULL, templ);
14855 v8::Handle<v8::Object> global = context->Global();
14857 v8::Handle<v8::String> some_property = v8::String::New("a");
14858 CHECK_EQ(0, force_set_set_count);
14859 CHECK_EQ(0, force_set_get_count);
14860 CHECK_EQ(3, global->Get(some_property)->Int32Value());
14861 // Setting the property shouldn't override it, just call the setter
14862 // which in this case does nothing.
14863 global->Set(some_property, v8::Int32::New(7));
14864 CHECK_EQ(3, global->Get(some_property)->Int32Value());
14865 CHECK_EQ(1, force_set_set_count);
14866 CHECK_EQ(2, force_set_get_count);
14867 // Getting the property when the interceptor returns an empty handle
14868 // should yield undefined, since the property isn't present on the
14869 // object itself yet.
14870 pass_on_get = true;
14871 CHECK(global->Get(some_property)->IsUndefined());
14872 CHECK_EQ(1, force_set_set_count);
14873 CHECK_EQ(3, force_set_get_count);
14874 // Forcing the property to be set should cause the value to be
14875 // set locally without calling the interceptor.
14876 global->ForceSet(some_property, v8::Int32::New(8));
14877 CHECK_EQ(8, global->Get(some_property)->Int32Value());
14878 CHECK_EQ(1, force_set_set_count);
14879 CHECK_EQ(4, force_set_get_count);
14880 // Reenabling the interceptor should cause it to take precedence over
14882 pass_on_get = false;
14883 CHECK_EQ(3, global->Get(some_property)->Int32Value());
14884 CHECK_EQ(1, force_set_set_count);
14885 CHECK_EQ(5, force_set_get_count);
14886 // The interceptor should also work for other properties
14887 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
14888 CHECK_EQ(1, force_set_set_count);
14889 CHECK_EQ(6, force_set_get_count);
14893 THREADED_TEST(ForceDelete) {
14894 v8::HandleScope scope(v8::Isolate::GetCurrent());
14895 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14896 LocalContext context(NULL, templ);
14897 v8::Handle<v8::Object> global = context->Global();
14899 // Ordinary properties
14900 v8::Handle<v8::String> simple_property = v8::String::New("p");
14901 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
14902 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14903 // This should fail because the property is dont-delete.
14904 CHECK(!global->Delete(simple_property));
14905 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14906 // This should succeed even though the property is dont-delete.
14907 CHECK(global->ForceDelete(simple_property));
14908 CHECK(global->Get(simple_property)->IsUndefined());
14912 static int force_delete_interceptor_count = 0;
14913 static bool pass_on_delete = false;
14916 static void ForceDeleteDeleter(
14917 v8::Local<v8::String> name,
14918 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
14919 force_delete_interceptor_count++;
14920 if (pass_on_delete) return;
14921 info.GetReturnValue().Set(true);
14925 THREADED_TEST(ForceDeleteWithInterceptor) {
14926 force_delete_interceptor_count = 0;
14927 pass_on_delete = false;
14929 v8::HandleScope scope(v8::Isolate::GetCurrent());
14930 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14931 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
14932 LocalContext context(NULL, templ);
14933 v8::Handle<v8::Object> global = context->Global();
14935 v8::Handle<v8::String> some_property = v8::String::New("a");
14936 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
14938 // Deleting a property should get intercepted and nothing should
14940 CHECK_EQ(0, force_delete_interceptor_count);
14941 CHECK(global->Delete(some_property));
14942 CHECK_EQ(1, force_delete_interceptor_count);
14943 CHECK_EQ(42, global->Get(some_property)->Int32Value());
14944 // Deleting the property when the interceptor returns an empty
14945 // handle should not delete the property since it is DontDelete.
14946 pass_on_delete = true;
14947 CHECK(!global->Delete(some_property));
14948 CHECK_EQ(2, force_delete_interceptor_count);
14949 CHECK_EQ(42, global->Get(some_property)->Int32Value());
14950 // Forcing the property to be deleted should delete the value
14951 // without calling the interceptor.
14952 CHECK(global->ForceDelete(some_property));
14953 CHECK(global->Get(some_property)->IsUndefined());
14954 CHECK_EQ(2, force_delete_interceptor_count);
14958 // Make sure that forcing a delete invalidates any IC stubs, so we
14959 // don't read the hole value.
14960 THREADED_TEST(ForceDeleteIC) {
14961 LocalContext context;
14962 v8::HandleScope scope(context->GetIsolate());
14963 // Create a DontDelete variable on the global object.
14964 CompileRun("this.__proto__ = { foo: 'horse' };"
14965 "var foo = 'fish';"
14966 "function f() { return foo.length; }");
14967 // Initialize the IC for foo in f.
14968 CompileRun("for (var i = 0; i < 4; i++) f();");
14969 // Make sure the value of foo is correct before the deletion.
14970 CHECK_EQ(4, CompileRun("f()")->Int32Value());
14971 // Force the deletion of foo.
14972 CHECK(context->Global()->ForceDelete(v8_str("foo")));
14973 // Make sure the value for foo is read from the prototype, and that
14974 // we don't get in trouble with reading the deleted cell value
14976 CHECK_EQ(5, CompileRun("f()")->Int32Value());
14980 TEST(InlinedFunctionAcrossContexts) {
14981 i::FLAG_allow_natives_syntax = true;
14982 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14983 v8::HandleScope outer_scope(isolate);
14984 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
14985 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
14989 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
14990 CompileRun("var G = 42; function foo() { return G; }");
14991 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
14993 ctx2->Global()->Set(v8_str("o"), foo);
14994 v8::Local<v8::Value> res = CompileRun(
14995 "function f() { return o(); }"
14996 "for (var i = 0; i < 10; ++i) f();"
14997 "%OptimizeFunctionOnNextCall(f);"
14999 CHECK_EQ(42, res->Int32Value());
15001 v8::Handle<v8::String> G_property = v8::String::New("G");
15002 CHECK(ctx1->Global()->ForceDelete(G_property));
15009 " return e.toString();"
15012 "ReferenceError: G is not defined");
15019 static v8::Local<Context> calling_context0;
15020 static v8::Local<Context> calling_context1;
15021 static v8::Local<Context> calling_context2;
15024 // Check that the call to the callback is initiated in
15025 // calling_context2, the directly calling context is calling_context1
15026 // and the callback itself is in calling_context0.
15027 static void GetCallingContextCallback(
15028 const v8::FunctionCallbackInfo<v8::Value>& args) {
15029 ApiTestFuzzer::Fuzz();
15030 CHECK(Context::GetCurrent() == calling_context0);
15031 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15032 CHECK(Context::GetCalling() == calling_context1);
15033 CHECK(Context::GetEntered() == calling_context2);
15034 args.GetReturnValue().Set(42);
15038 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15039 i::Isolate* isolate = i::Isolate::Current();
15040 CHECK(isolate != NULL);
15041 CHECK(isolate->context() == NULL);
15042 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15043 v8::HandleScope scope(v8_isolate);
15044 // The following should not crash, but return an empty handle.
15045 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15046 CHECK(current.IsEmpty());
15050 THREADED_TEST(GetCallingContext) {
15051 v8::Isolate* isolate = v8::Isolate::GetCurrent();
15052 v8::HandleScope scope(isolate);
15054 Local<Context> calling_context0(Context::New(isolate));
15055 Local<Context> calling_context1(Context::New(isolate));
15056 Local<Context> calling_context2(Context::New(isolate));
15057 ::calling_context0 = calling_context0;
15058 ::calling_context1 = calling_context1;
15059 ::calling_context2 = calling_context2;
15061 // Allow cross-domain access.
15062 Local<String> token = v8_str("<security token>");
15063 calling_context0->SetSecurityToken(token);
15064 calling_context1->SetSecurityToken(token);
15065 calling_context2->SetSecurityToken(token);
15067 // Create an object with a C++ callback in context0.
15068 calling_context0->Enter();
15069 Local<v8::FunctionTemplate> callback_templ =
15070 v8::FunctionTemplate::New(GetCallingContextCallback);
15071 calling_context0->Global()->Set(v8_str("callback"),
15072 callback_templ->GetFunction());
15073 calling_context0->Exit();
15075 // Expose context0 in context1 and set up a function that calls the
15076 // callback function.
15077 calling_context1->Enter();
15078 calling_context1->Global()->Set(v8_str("context0"),
15079 calling_context0->Global());
15080 CompileRun("function f() { context0.callback() }");
15081 calling_context1->Exit();
15083 // Expose context1 in context2 and call the callback function in
15084 // context0 indirectly through f in context1.
15085 calling_context2->Enter();
15086 calling_context2->Global()->Set(v8_str("context1"),
15087 calling_context1->Global());
15088 CompileRun("context1.f()");
15089 calling_context2->Exit();
15090 ::calling_context0.Clear();
15091 ::calling_context1.Clear();
15092 ::calling_context2.Clear();
15096 // Check that a variable declaration with no explicit initialization
15097 // value does shadow an existing property in the prototype chain.
15098 THREADED_TEST(InitGlobalVarInProtoChain) {
15099 i::FLAG_es52_globals = true;
15100 LocalContext context;
15101 v8::HandleScope scope(context->GetIsolate());
15102 // Introduce a variable in the prototype chain.
15103 CompileRun("__proto__.x = 42");
15104 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15105 CHECK(!result->IsUndefined());
15106 CHECK_EQ(43, result->Int32Value());
15110 // Regression test for issue 398.
15111 // If a function is added to an object, creating a constant function
15112 // field, and the result is cloned, replacing the constant function on the
15113 // original should not affect the clone.
15114 // See http://code.google.com/p/v8/issues/detail?id=398
15115 THREADED_TEST(ReplaceConstantFunction) {
15116 LocalContext context;
15117 v8::HandleScope scope(context->GetIsolate());
15118 v8::Handle<v8::Object> obj = v8::Object::New();
15119 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
15120 v8::Handle<v8::String> foo_string = v8::String::New("foo");
15121 obj->Set(foo_string, func_templ->GetFunction());
15122 v8::Handle<v8::Object> obj_clone = obj->Clone();
15123 obj_clone->Set(foo_string, v8::String::New("Hello"));
15124 CHECK(!obj->Get(foo_string)->IsUndefined());
15128 // Regression test for http://crbug.com/16276.
15129 THREADED_TEST(Regress16276) {
15130 LocalContext context;
15131 v8::HandleScope scope(context->GetIsolate());
15132 // Force the IC in f to be a dictionary load IC.
15133 CompileRun("function f(obj) { return obj.x; }\n"
15134 "var obj = { x: { foo: 42 }, y: 87 };\n"
15137 "for (var i = 0; i < 5; i++) f(obj);");
15138 // Detach the global object to make 'this' refer directly to the
15139 // global object (not the proxy), and make sure that the dictionary
15140 // load IC doesn't mess up loading directly from the global object.
15141 context->DetachGlobal();
15142 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
15145 static void CheckElementValue(i::Isolate* isolate,
15147 i::Handle<i::Object> obj,
15149 i::Object* element = obj->GetElement(isolate, offset)->ToObjectChecked();
15150 CHECK_EQ(expected, i::Smi::cast(element)->value());
15154 THREADED_TEST(PixelArray) {
15155 LocalContext context;
15156 i::Isolate* isolate = i::Isolate::Current();
15157 i::Factory* factory = isolate->factory();
15158 v8::HandleScope scope(context->GetIsolate());
15159 const int kElementCount = 260;
15160 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15161 i::Handle<i::ExternalPixelArray> pixels =
15162 i::Handle<i::ExternalPixelArray>::cast(
15163 factory->NewExternalArray(kElementCount,
15164 v8::kExternalPixelArray,
15166 // Force GC to trigger verification.
15167 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15168 for (int i = 0; i < kElementCount; i++) {
15169 pixels->set(i, i % 256);
15171 // Force GC to trigger verification.
15172 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15173 for (int i = 0; i < kElementCount; i++) {
15174 CHECK_EQ(i % 256, pixels->get_scalar(i));
15175 CHECK_EQ(i % 256, pixel_data[i]);
15178 v8::Handle<v8::Object> obj = v8::Object::New();
15179 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15180 // Set the elements to be the pixels.
15181 // jsobj->set_elements(*pixels);
15182 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15183 CheckElementValue(isolate, 1, jsobj, 1);
15184 obj->Set(v8_str("field"), v8::Int32::New(1503));
15185 context->Global()->Set(v8_str("pixels"), obj);
15186 v8::Handle<v8::Value> result = CompileRun("pixels.field");
15187 CHECK_EQ(1503, result->Int32Value());
15188 result = CompileRun("pixels[1]");
15189 CHECK_EQ(1, result->Int32Value());
15191 result = CompileRun("var sum = 0;"
15192 "for (var i = 0; i < 8; i++) {"
15193 " sum += pixels[i] = pixels[i] = -i;"
15196 CHECK_EQ(-28, result->Int32Value());
15198 result = CompileRun("var sum = 0;"
15199 "for (var i = 0; i < 8; i++) {"
15200 " sum += pixels[i] = pixels[i] = 0;"
15203 CHECK_EQ(0, result->Int32Value());
15205 result = CompileRun("var sum = 0;"
15206 "for (var i = 0; i < 8; i++) {"
15207 " sum += pixels[i] = pixels[i] = 255;"
15210 CHECK_EQ(8 * 255, result->Int32Value());
15212 result = CompileRun("var sum = 0;"
15213 "for (var i = 0; i < 8; i++) {"
15214 " sum += pixels[i] = pixels[i] = 256 + i;"
15217 CHECK_EQ(2076, result->Int32Value());
15219 result = CompileRun("var sum = 0;"
15220 "for (var i = 0; i < 8; i++) {"
15221 " sum += pixels[i] = pixels[i] = i;"
15224 CHECK_EQ(28, result->Int32Value());
15226 result = CompileRun("var sum = 0;"
15227 "for (var i = 0; i < 8; i++) {"
15228 " sum += pixels[i];"
15231 CHECK_EQ(28, result->Int32Value());
15233 i::Handle<i::Smi> value(i::Smi::FromInt(2),
15234 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15235 i::Handle<i::Object> no_failure;
15237 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15238 ASSERT(!no_failure.is_null());
15239 i::USE(no_failure);
15240 CheckElementValue(isolate, 2, jsobj, 1);
15241 *value.location() = i::Smi::FromInt(256);
15243 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15244 ASSERT(!no_failure.is_null());
15245 i::USE(no_failure);
15246 CheckElementValue(isolate, 255, jsobj, 1);
15247 *value.location() = i::Smi::FromInt(-1);
15249 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15250 ASSERT(!no_failure.is_null());
15251 i::USE(no_failure);
15252 CheckElementValue(isolate, 0, jsobj, 1);
15254 result = CompileRun("for (var i = 0; i < 8; i++) {"
15255 " pixels[i] = (i * 65) - 109;"
15257 "pixels[1] + pixels[6];");
15258 CHECK_EQ(255, result->Int32Value());
15259 CheckElementValue(isolate, 0, jsobj, 0);
15260 CheckElementValue(isolate, 0, jsobj, 1);
15261 CheckElementValue(isolate, 21, jsobj, 2);
15262 CheckElementValue(isolate, 86, jsobj, 3);
15263 CheckElementValue(isolate, 151, jsobj, 4);
15264 CheckElementValue(isolate, 216, jsobj, 5);
15265 CheckElementValue(isolate, 255, jsobj, 6);
15266 CheckElementValue(isolate, 255, jsobj, 7);
15267 result = CompileRun("var sum = 0;"
15268 "for (var i = 0; i < 8; i++) {"
15269 " sum += pixels[i];"
15272 CHECK_EQ(984, result->Int32Value());
15274 result = CompileRun("for (var i = 0; i < 8; i++) {"
15275 " pixels[i] = (i * 1.1);"
15277 "pixels[1] + pixels[6];");
15278 CHECK_EQ(8, result->Int32Value());
15279 CheckElementValue(isolate, 0, jsobj, 0);
15280 CheckElementValue(isolate, 1, jsobj, 1);
15281 CheckElementValue(isolate, 2, jsobj, 2);
15282 CheckElementValue(isolate, 3, jsobj, 3);
15283 CheckElementValue(isolate, 4, jsobj, 4);
15284 CheckElementValue(isolate, 6, jsobj, 5);
15285 CheckElementValue(isolate, 7, jsobj, 6);
15286 CheckElementValue(isolate, 8, jsobj, 7);
15288 result = CompileRun("for (var i = 0; i < 8; i++) {"
15289 " pixels[7] = undefined;"
15292 CHECK_EQ(0, result->Int32Value());
15293 CheckElementValue(isolate, 0, jsobj, 7);
15295 result = CompileRun("for (var i = 0; i < 8; i++) {"
15296 " pixels[6] = '2.3';"
15299 CHECK_EQ(2, result->Int32Value());
15300 CheckElementValue(isolate, 2, jsobj, 6);
15302 result = CompileRun("for (var i = 0; i < 8; i++) {"
15303 " pixels[5] = NaN;"
15306 CHECK_EQ(0, result->Int32Value());
15307 CheckElementValue(isolate, 0, jsobj, 5);
15309 result = CompileRun("for (var i = 0; i < 8; i++) {"
15310 " pixels[8] = Infinity;"
15313 CHECK_EQ(255, result->Int32Value());
15314 CheckElementValue(isolate, 255, jsobj, 8);
15316 result = CompileRun("for (var i = 0; i < 8; i++) {"
15317 " pixels[9] = -Infinity;"
15320 CHECK_EQ(0, result->Int32Value());
15321 CheckElementValue(isolate, 0, jsobj, 9);
15323 result = CompileRun("pixels[3] = 33;"
15324 "delete pixels[3];"
15326 CHECK_EQ(33, result->Int32Value());
15328 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15329 "pixels[2] = 12; pixels[3] = 13;"
15330 "pixels.__defineGetter__('2',"
15331 "function() { return 120; });"
15333 CHECK_EQ(12, result->Int32Value());
15335 result = CompileRun("var js_array = new Array(40);"
15336 "js_array[0] = 77;"
15338 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15340 result = CompileRun("pixels[1] = 23;"
15341 "pixels.__proto__ = [];"
15342 "js_array.__proto__ = pixels;"
15343 "js_array.concat(pixels);");
15344 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15345 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15347 result = CompileRun("pixels[1] = 23;");
15348 CHECK_EQ(23, result->Int32Value());
15350 // Test for index greater than 255. Regression test for:
15351 // http://code.google.com/p/chromium/issues/detail?id=26337.
15352 result = CompileRun("pixels[256] = 255;");
15353 CHECK_EQ(255, result->Int32Value());
15354 result = CompileRun("var i = 0;"
15355 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15357 CHECK_EQ(255, result->Int32Value());
15359 // Make sure that pixel array ICs recognize when a non-pixel array
15360 // is passed to it.
15361 result = CompileRun("function pa_load(p) {"
15363 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15366 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15367 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15368 "just_ints = new Object();"
15369 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15370 "for (var i = 0; i < 10; ++i) {"
15371 " result = pa_load(just_ints);"
15374 CHECK_EQ(32640, result->Int32Value());
15376 // Make sure that pixel array ICs recognize out-of-bound accesses.
15377 result = CompileRun("function pa_load(p, start) {"
15379 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15382 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15383 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15384 "for (var i = 0; i < 10; ++i) {"
15385 " result = pa_load(pixels,-10);"
15388 CHECK_EQ(0, result->Int32Value());
15390 // Make sure that generic ICs properly handles a pixel array.
15391 result = CompileRun("function pa_load(p) {"
15393 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15396 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15397 "just_ints = new Object();"
15398 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15399 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15400 "for (var i = 0; i < 10; ++i) {"
15401 " result = pa_load(pixels);"
15404 CHECK_EQ(32640, result->Int32Value());
15406 // Make sure that generic load ICs recognize out-of-bound accesses in
15408 result = CompileRun("function pa_load(p, start) {"
15410 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15413 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15414 "just_ints = new Object();"
15415 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15416 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15417 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15418 "for (var i = 0; i < 10; ++i) {"
15419 " result = pa_load(pixels,-10);"
15422 CHECK_EQ(0, result->Int32Value());
15424 // Make sure that generic ICs properly handles other types than pixel
15425 // arrays (that the inlined fast pixel array test leaves the right information
15426 // in the right registers).
15427 result = CompileRun("function pa_load(p) {"
15429 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15432 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15433 "just_ints = new Object();"
15434 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15435 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15436 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15437 "sparse_array = new Object();"
15438 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15439 "sparse_array[1000000] = 3;"
15440 "for (var i = 0; i < 10; ++i) {"
15441 " result = pa_load(sparse_array);"
15444 CHECK_EQ(32640, result->Int32Value());
15446 // Make sure that pixel array store ICs clamp values correctly.
15447 result = CompileRun("function pa_store(p) {"
15448 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15450 "pa_store(pixels);"
15452 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15454 CHECK_EQ(48896, result->Int32Value());
15456 // Make sure that pixel array stores correctly handle accesses outside
15457 // of the pixel array..
15458 result = CompileRun("function pa_store(p,start) {"
15459 " for (var j = 0; j < 256; j++) {"
15460 " p[j+start] = j * 2;"
15463 "pa_store(pixels,0);"
15464 "pa_store(pixels,-128);"
15466 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15468 CHECK_EQ(65280, result->Int32Value());
15470 // Make sure that the generic store stub correctly handle accesses outside
15471 // of the pixel array..
15472 result = CompileRun("function pa_store(p,start) {"
15473 " for (var j = 0; j < 256; j++) {"
15474 " p[j+start] = j * 2;"
15477 "pa_store(pixels,0);"
15478 "just_ints = new Object();"
15479 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15480 "pa_store(just_ints, 0);"
15481 "pa_store(pixels,-128);"
15483 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15485 CHECK_EQ(65280, result->Int32Value());
15487 // Make sure that the generic keyed store stub clamps pixel array values
15489 result = CompileRun("function pa_store(p) {"
15490 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15492 "pa_store(pixels);"
15493 "just_ints = new Object();"
15494 "pa_store(just_ints);"
15495 "pa_store(pixels);"
15497 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15499 CHECK_EQ(48896, result->Int32Value());
15501 // Make sure that pixel array loads are optimized by crankshaft.
15502 result = CompileRun("function pa_load(p) {"
15504 " for (var i=0; i<256; ++i) {"
15509 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15510 "for (var i = 0; i < 5000; ++i) {"
15511 " result = pa_load(pixels);"
15514 CHECK_EQ(32640, result->Int32Value());
15516 // Make sure that pixel array stores are optimized by crankshaft.
15517 result = CompileRun("function pa_init(p) {"
15518 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
15520 "function pa_load(p) {"
15522 " for (var i=0; i<256; ++i) {"
15527 "for (var i = 0; i < 5000; ++i) {"
15528 " pa_init(pixels);"
15530 "result = pa_load(pixels);"
15532 CHECK_EQ(32640, result->Int32Value());
15538 THREADED_TEST(PixelArrayInfo) {
15539 LocalContext context;
15540 v8::HandleScope scope(context->GetIsolate());
15541 for (int size = 0; size < 100; size += 10) {
15542 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
15543 v8::Handle<v8::Object> obj = v8::Object::New();
15544 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
15545 CHECK(obj->HasIndexedPropertiesInPixelData());
15546 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
15547 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
15553 static void NotHandledIndexedPropertyGetter(
15555 const v8::PropertyCallbackInfo<v8::Value>& info) {
15556 ApiTestFuzzer::Fuzz();
15560 static void NotHandledIndexedPropertySetter(
15562 Local<Value> value,
15563 const v8::PropertyCallbackInfo<v8::Value>& info) {
15564 ApiTestFuzzer::Fuzz();
15568 THREADED_TEST(PixelArrayWithInterceptor) {
15569 LocalContext context;
15570 i::Factory* factory = i::Isolate::Current()->factory();
15571 v8::HandleScope scope(context->GetIsolate());
15572 const int kElementCount = 260;
15573 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15574 i::Handle<i::ExternalPixelArray> pixels =
15575 i::Handle<i::ExternalPixelArray>::cast(
15576 factory->NewExternalArray(kElementCount,
15577 v8::kExternalPixelArray,
15579 for (int i = 0; i < kElementCount; i++) {
15580 pixels->set(i, i % 256);
15582 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
15583 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
15584 NotHandledIndexedPropertySetter);
15585 v8::Handle<v8::Object> obj = templ->NewInstance();
15586 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15587 context->Global()->Set(v8_str("pixels"), obj);
15588 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
15589 CHECK_EQ(1, result->Int32Value());
15590 result = CompileRun("var sum = 0;"
15591 "for (var i = 0; i < 8; i++) {"
15592 " sum += pixels[i] = pixels[i] = -i;"
15595 CHECK_EQ(-28, result->Int32Value());
15596 result = CompileRun("pixels.hasOwnProperty('1')");
15597 CHECK(result->BooleanValue());
15602 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
15603 switch (array_type) {
15604 case v8::kExternalByteArray:
15605 case v8::kExternalUnsignedByteArray:
15606 case v8::kExternalPixelArray:
15609 case v8::kExternalShortArray:
15610 case v8::kExternalUnsignedShortArray:
15613 case v8::kExternalIntArray:
15614 case v8::kExternalUnsignedIntArray:
15615 case v8::kExternalFloatArray:
15618 case v8::kExternalDoubleArray:
15630 template <class ExternalArrayClass, class ElementType>
15631 static void ObjectWithExternalArrayTestHelper(
15632 Handle<Context> context,
15633 v8::Handle<Object> obj,
15635 v8::ExternalArrayType array_type,
15636 int64_t low, int64_t high) {
15637 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15638 i::Isolate* isolate = jsobj->GetIsolate();
15639 obj->Set(v8_str("field"), v8::Int32::New(1503));
15640 context->Global()->Set(v8_str("ext_array"), obj);
15641 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
15642 CHECK_EQ(1503, result->Int32Value());
15643 result = CompileRun("ext_array[1]");
15644 CHECK_EQ(1, result->Int32Value());
15646 // Check pass through of assigned smis
15647 result = CompileRun("var sum = 0;"
15648 "for (var i = 0; i < 8; i++) {"
15649 " sum += ext_array[i] = ext_array[i] = -i;"
15652 CHECK_EQ(-28, result->Int32Value());
15654 // Check assigned smis
15655 result = CompileRun("for (var i = 0; i < 8; i++) {"
15656 " ext_array[i] = i;"
15659 "for (var i = 0; i < 8; i++) {"
15660 " sum += ext_array[i];"
15663 CHECK_EQ(28, result->Int32Value());
15665 // Check assigned smis in reverse order
15666 result = CompileRun("for (var i = 8; --i >= 0; ) {"
15667 " ext_array[i] = i;"
15670 "for (var i = 0; i < 8; i++) {"
15671 " sum += ext_array[i];"
15674 CHECK_EQ(28, result->Int32Value());
15676 // Check pass through of assigned HeapNumbers
15677 result = CompileRun("var sum = 0;"
15678 "for (var i = 0; i < 16; i+=2) {"
15679 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
15682 CHECK_EQ(-28, result->Int32Value());
15684 // Check assigned HeapNumbers
15685 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
15686 " ext_array[i] = (i * 0.5);"
15689 "for (var i = 0; i < 16; i+=2) {"
15690 " sum += ext_array[i];"
15693 CHECK_EQ(28, result->Int32Value());
15695 // Check assigned HeapNumbers in reverse order
15696 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
15697 " ext_array[i] = (i * 0.5);"
15700 "for (var i = 0; i < 16; i+=2) {"
15701 " sum += ext_array[i];"
15704 CHECK_EQ(28, result->Int32Value());
15706 i::ScopedVector<char> test_buf(1024);
15708 // Check legal boundary conditions.
15709 // The repeated loads and stores ensure the ICs are exercised.
15710 const char* boundary_program =
15712 "for (var i = 0; i < 16; i++) {"
15713 " ext_array[i] = %lld;"
15715 " res = ext_array[i];"
15719 i::OS::SNPrintF(test_buf,
15722 result = CompileRun(test_buf.start());
15723 CHECK_EQ(low, result->IntegerValue());
15725 i::OS::SNPrintF(test_buf,
15728 result = CompileRun(test_buf.start());
15729 CHECK_EQ(high, result->IntegerValue());
15731 // Check misprediction of type in IC.
15732 result = CompileRun("var tmp_array = ext_array;"
15734 "for (var i = 0; i < 8; i++) {"
15735 " tmp_array[i] = i;"
15736 " sum += tmp_array[i];"
15742 // Force GC to trigger verification.
15743 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15744 CHECK_EQ(28, result->Int32Value());
15746 // Make sure out-of-range loads do not throw.
15747 i::OS::SNPrintF(test_buf,
15748 "var caught_exception = false;"
15752 " caught_exception = true;"
15754 "caught_exception;",
15756 result = CompileRun(test_buf.start());
15757 CHECK_EQ(false, result->BooleanValue());
15759 // Make sure out-of-range stores do not throw.
15760 i::OS::SNPrintF(test_buf,
15761 "var caught_exception = false;"
15763 " ext_array[%d] = 1;"
15765 " caught_exception = true;"
15767 "caught_exception;",
15769 result = CompileRun(test_buf.start());
15770 CHECK_EQ(false, result->BooleanValue());
15772 // Check other boundary conditions, values and operations.
15773 result = CompileRun("for (var i = 0; i < 8; i++) {"
15774 " ext_array[7] = undefined;"
15777 CHECK_EQ(0, result->Int32Value());
15778 if (array_type == v8::kExternalDoubleArray ||
15779 array_type == v8::kExternalFloatArray) {
15780 CHECK_EQ(static_cast<int>(i::OS::nan_value()),
15782 jsobj->GetElement(isolate, 7)->ToObjectChecked()->Number()));
15784 CheckElementValue(isolate, 0, jsobj, 7);
15787 result = CompileRun("for (var i = 0; i < 8; i++) {"
15788 " ext_array[6] = '2.3';"
15791 CHECK_EQ(2, result->Int32Value());
15794 jsobj->GetElement(isolate, 6)->ToObjectChecked()->Number()));
15796 if (array_type != v8::kExternalFloatArray &&
15797 array_type != v8::kExternalDoubleArray) {
15798 // Though the specification doesn't state it, be explicit about
15799 // converting NaNs and +/-Infinity to zero.
15800 result = CompileRun("for (var i = 0; i < 8; i++) {"
15801 " ext_array[i] = 5;"
15803 "for (var i = 0; i < 8; i++) {"
15804 " ext_array[i] = NaN;"
15807 CHECK_EQ(0, result->Int32Value());
15808 CheckElementValue(isolate, 0, jsobj, 5);
15810 result = CompileRun("for (var i = 0; i < 8; i++) {"
15811 " ext_array[i] = 5;"
15813 "for (var i = 0; i < 8; i++) {"
15814 " ext_array[i] = Infinity;"
15817 int expected_value =
15818 (array_type == v8::kExternalPixelArray) ? 255 : 0;
15819 CHECK_EQ(expected_value, result->Int32Value());
15820 CheckElementValue(isolate, expected_value, jsobj, 5);
15822 result = CompileRun("for (var i = 0; i < 8; i++) {"
15823 " ext_array[i] = 5;"
15825 "for (var i = 0; i < 8; i++) {"
15826 " ext_array[i] = -Infinity;"
15829 CHECK_EQ(0, result->Int32Value());
15830 CheckElementValue(isolate, 0, jsobj, 5);
15832 // Check truncation behavior of integral arrays.
15833 const char* unsigned_data =
15834 "var source_data = [0.6, 10.6];"
15835 "var expected_results = [0, 10];";
15836 const char* signed_data =
15837 "var source_data = [0.6, 10.6, -0.6, -10.6];"
15838 "var expected_results = [0, 10, 0, -10];";
15839 const char* pixel_data =
15840 "var source_data = [0.6, 10.6];"
15841 "var expected_results = [1, 11];";
15843 (array_type == v8::kExternalUnsignedByteArray ||
15844 array_type == v8::kExternalUnsignedShortArray ||
15845 array_type == v8::kExternalUnsignedIntArray);
15846 bool is_pixel_data = array_type == v8::kExternalPixelArray;
15848 i::OS::SNPrintF(test_buf,
15850 "var all_passed = true;"
15851 "for (var i = 0; i < source_data.length; i++) {"
15852 " for (var j = 0; j < 8; j++) {"
15853 " ext_array[j] = source_data[i];"
15855 " all_passed = all_passed &&"
15856 " (ext_array[5] == expected_results[i]);"
15861 (is_pixel_data ? pixel_data : signed_data)));
15862 result = CompileRun(test_buf.start());
15863 CHECK_EQ(true, result->BooleanValue());
15866 i::Handle<ExternalArrayClass> array(
15867 ExternalArrayClass::cast(jsobj->elements()));
15868 for (int i = 0; i < element_count; i++) {
15869 array->set(i, static_cast<ElementType>(i));
15872 // Test complex assignments
15873 result = CompileRun("function ee_op_test_complex_func(sum) {"
15874 " for (var i = 0; i < 40; ++i) {"
15875 " sum += (ext_array[i] += 1);"
15876 " sum += (ext_array[i] -= 1);"
15881 "for (var i=0;i<10000;++i) {"
15882 " sum=ee_op_test_complex_func(sum);"
15885 CHECK_EQ(16000000, result->Int32Value());
15887 // Test count operations
15888 result = CompileRun("function ee_op_test_count_func(sum) {"
15889 " for (var i = 0; i < 40; ++i) {"
15890 " sum += (++ext_array[i]);"
15891 " sum += (--ext_array[i]);"
15896 "for (var i=0;i<10000;++i) {"
15897 " sum=ee_op_test_count_func(sum);"
15900 CHECK_EQ(16000000, result->Int32Value());
15902 result = CompileRun("ext_array[3] = 33;"
15903 "delete ext_array[3];"
15905 CHECK_EQ(33, result->Int32Value());
15907 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
15908 "ext_array[2] = 12; ext_array[3] = 13;"
15909 "ext_array.__defineGetter__('2',"
15910 "function() { return 120; });"
15912 CHECK_EQ(12, result->Int32Value());
15914 result = CompileRun("var js_array = new Array(40);"
15915 "js_array[0] = 77;"
15917 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15919 result = CompileRun("ext_array[1] = 23;"
15920 "ext_array.__proto__ = [];"
15921 "js_array.__proto__ = ext_array;"
15922 "js_array.concat(ext_array);");
15923 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15924 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15926 result = CompileRun("ext_array[1] = 23;");
15927 CHECK_EQ(23, result->Int32Value());
15931 template <class ExternalArrayClass, class ElementType>
15932 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
15935 LocalContext context;
15936 i::Isolate* isolate = i::Isolate::Current();
15937 i::Factory* factory = isolate->factory();
15938 v8::HandleScope scope(context->GetIsolate());
15939 const int kElementCount = 40;
15940 int element_size = ExternalArrayElementSize(array_type);
15941 ElementType* array_data =
15942 static_cast<ElementType*>(malloc(kElementCount * element_size));
15943 i::Handle<ExternalArrayClass> array =
15944 i::Handle<ExternalArrayClass>::cast(
15945 factory->NewExternalArray(kElementCount, array_type, array_data));
15946 // Force GC to trigger verification.
15947 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15948 for (int i = 0; i < kElementCount; i++) {
15949 array->set(i, static_cast<ElementType>(i));
15951 // Force GC to trigger verification.
15952 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15953 for (int i = 0; i < kElementCount; i++) {
15954 CHECK_EQ(static_cast<int64_t>(i),
15955 static_cast<int64_t>(array->get_scalar(i)));
15956 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
15959 v8::Handle<v8::Object> obj = v8::Object::New();
15960 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15961 // Set the elements to be the external array.
15962 obj->SetIndexedPropertiesToExternalArrayData(array_data,
15967 jsobj->GetElement(isolate, 1)->ToObjectChecked()->Number()));
15969 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
15970 context.local(), obj, kElementCount, array_type, low, high);
15972 v8::Handle<v8::Value> result;
15974 // Test more complex manipulations which cause eax to contain values
15975 // that won't be completely overwritten by loads from the arrays.
15976 // This catches bugs in the instructions used for the KeyedLoadIC
15977 // for byte and word types.
15979 const int kXSize = 300;
15980 const int kYSize = 300;
15981 const int kLargeElementCount = kXSize * kYSize * 4;
15982 ElementType* large_array_data =
15983 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
15984 v8::Handle<v8::Object> large_obj = v8::Object::New();
15985 // Set the elements to be the external array.
15986 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
15988 kLargeElementCount);
15989 context->Global()->Set(v8_str("large_array"), large_obj);
15990 // Initialize contents of a few rows.
15991 for (int x = 0; x < 300; x++) {
15993 int offset = row * 300 * 4;
15994 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
15995 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
15996 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
15997 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
15999 offset = row * 300 * 4;
16000 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16001 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16002 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16003 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16005 offset = row * 300 * 4;
16006 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16007 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16008 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16009 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16011 // The goal of the code below is to make "offset" large enough
16012 // that the computation of the index (which goes into eax) has
16013 // high bits set which will not be overwritten by a byte or short
16015 result = CompileRun("var failed = false;"
16017 "for (var i = 0; i < 300; i++) {"
16018 " if (large_array[4 * i] != 127 ||"
16019 " large_array[4 * i + 1] != 0 ||"
16020 " large_array[4 * i + 2] != 0 ||"
16021 " large_array[4 * i + 3] != 127) {"
16025 "offset = 150 * 300 * 4;"
16026 "for (var i = 0; i < 300; i++) {"
16027 " if (large_array[offset + 4 * i] != 127 ||"
16028 " large_array[offset + 4 * i + 1] != 0 ||"
16029 " large_array[offset + 4 * i + 2] != 0 ||"
16030 " large_array[offset + 4 * i + 3] != 127) {"
16034 "offset = 298 * 300 * 4;"
16035 "for (var i = 0; i < 300; i++) {"
16036 " if (large_array[offset + 4 * i] != 127 ||"
16037 " large_array[offset + 4 * i + 1] != 0 ||"
16038 " large_array[offset + 4 * i + 2] != 0 ||"
16039 " large_array[offset + 4 * i + 3] != 127) {"
16044 CHECK_EQ(true, result->BooleanValue());
16045 free(large_array_data);
16048 // The "" property descriptor is overloaded to store information about
16049 // the external array. Ensure that setting and accessing the "" property
16050 // works (it should overwrite the information cached about the external
16051 // array in the DescriptorArray) in various situations.
16052 result = CompileRun("ext_array[''] = 23; ext_array['']");
16053 CHECK_EQ(23, result->Int32Value());
16055 // Property "" set after the external array is associated with the object.
16057 v8::Handle<v8::Object> obj2 = v8::Object::New();
16058 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
16059 obj2->Set(v8_str(""), v8::Int32::New(1503));
16060 // Set the elements to be the external array.
16061 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16064 context->Global()->Set(v8_str("ext_array"), obj2);
16065 result = CompileRun("ext_array['']");
16066 CHECK_EQ(1503, result->Int32Value());
16069 // Property "" set after the external array is associated with the object.
16071 v8::Handle<v8::Object> obj2 = v8::Object::New();
16072 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
16073 // Set the elements to be the external array.
16074 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16077 obj2->Set(v8_str(""), v8::Int32::New(1503));
16078 context->Global()->Set(v8_str("ext_array"), obj2);
16079 result = CompileRun("ext_array['']");
16080 CHECK_EQ(1503, result->Int32Value());
16083 // Should reuse the map from previous test.
16085 v8::Handle<v8::Object> obj2 = v8::Object::New();
16086 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
16087 // Set the elements to be the external array. Should re-use the map
16088 // from previous test.
16089 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16092 context->Global()->Set(v8_str("ext_array"), obj2);
16093 result = CompileRun("ext_array['']");
16096 // Property "" is a constant function that shouldn't not be interfered with
16097 // when an external array is set.
16099 v8::Handle<v8::Object> obj2 = v8::Object::New();
16101 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
16103 // Add a constant function to an object.
16104 context->Global()->Set(v8_str("ext_array"), obj2);
16105 result = CompileRun("ext_array[''] = function() {return 1503;};"
16106 "ext_array['']();");
16108 // Add an external array transition to the same map that
16109 // has the constant transition.
16110 v8::Handle<v8::Object> obj3 = v8::Object::New();
16111 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
16112 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16115 context->Global()->Set(v8_str("ext_array"), obj3);
16118 // If a external array transition is in the map, it should get clobbered
16119 // by a constant function.
16121 // Add an external array transition.
16122 v8::Handle<v8::Object> obj3 = v8::Object::New();
16123 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
16124 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16128 // Add a constant function to the same map that just got an external array
16130 v8::Handle<v8::Object> obj2 = v8::Object::New();
16131 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
16132 context->Global()->Set(v8_str("ext_array"), obj2);
16133 result = CompileRun("ext_array[''] = function() {return 1503;};"
16134 "ext_array['']();");
16141 THREADED_TEST(ExternalByteArray) {
16142 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
16143 v8::kExternalByteArray,
16149 THREADED_TEST(ExternalUnsignedByteArray) {
16150 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
16151 v8::kExternalUnsignedByteArray,
16157 THREADED_TEST(ExternalPixelArray) {
16158 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
16159 v8::kExternalPixelArray,
16165 THREADED_TEST(ExternalShortArray) {
16166 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
16167 v8::kExternalShortArray,
16173 THREADED_TEST(ExternalUnsignedShortArray) {
16174 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
16175 v8::kExternalUnsignedShortArray,
16181 THREADED_TEST(ExternalIntArray) {
16182 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
16183 v8::kExternalIntArray,
16184 INT_MIN, // -2147483648
16185 INT_MAX); // 2147483647
16189 THREADED_TEST(ExternalUnsignedIntArray) {
16190 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
16191 v8::kExternalUnsignedIntArray,
16193 UINT_MAX); // 4294967295
16197 THREADED_TEST(ExternalFloatArray) {
16198 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
16199 v8::kExternalFloatArray,
16205 THREADED_TEST(ExternalDoubleArray) {
16206 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
16207 v8::kExternalDoubleArray,
16213 THREADED_TEST(ExternalArrays) {
16214 TestExternalByteArray();
16215 TestExternalUnsignedByteArray();
16216 TestExternalShortArray();
16217 TestExternalUnsignedShortArray();
16218 TestExternalIntArray();
16219 TestExternalUnsignedIntArray();
16220 TestExternalFloatArray();
16224 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16225 LocalContext context;
16226 v8::HandleScope scope(context->GetIsolate());
16227 for (int size = 0; size < 100; size += 10) {
16228 int element_size = ExternalArrayElementSize(array_type);
16229 void* external_data = malloc(size * element_size);
16230 v8::Handle<v8::Object> obj = v8::Object::New();
16231 obj->SetIndexedPropertiesToExternalArrayData(
16232 external_data, array_type, size);
16233 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16234 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16235 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16236 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16237 free(external_data);
16242 THREADED_TEST(ExternalArrayInfo) {
16243 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
16244 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
16245 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
16246 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
16247 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
16248 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
16249 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
16250 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
16251 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
16255 void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
16256 v8::Handle<v8::Object> obj = v8::Object::New();
16257 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16258 last_location = last_message = NULL;
16259 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16260 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16261 CHECK_NE(NULL, last_location);
16262 CHECK_NE(NULL, last_message);
16266 TEST(ExternalArrayLimits) {
16267 LocalContext context;
16268 v8::HandleScope scope(context->GetIsolate());
16269 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
16270 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
16271 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
16272 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
16273 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
16274 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
16275 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
16276 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
16277 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
16278 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
16279 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
16280 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
16281 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
16282 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
16283 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
16284 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
16285 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
16286 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
16290 template <typename ElementType, typename TypedArray,
16291 class ExternalArrayClass>
16292 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16293 int64_t low, int64_t high) {
16294 const int kElementCount = 50;
16296 i::ScopedVector<ElementType> backing_store(kElementCount+2);
16299 v8::Isolate* isolate = env->GetIsolate();
16300 v8::HandleScope handle_scope(isolate);
16302 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
16303 backing_store.start(), (kElementCount+2)*sizeof(ElementType));
16304 Local<TypedArray> ta =
16305 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16306 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16307 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16308 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
16309 CHECK_EQ(kElementCount*sizeof(ElementType),
16310 static_cast<int>(ta->ByteLength()));
16311 CHECK_EQ(ab, ta->Buffer());
16313 ElementType* data = backing_store.start() + 2;
16314 for (int i = 0; i < kElementCount; i++) {
16315 data[i] = static_cast<ElementType>(i);
16318 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16319 env.local(), ta, kElementCount, array_type, low, high);
16323 THREADED_TEST(Uint8Array) {
16324 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUnsignedByteArray>(
16325 v8::kExternalUnsignedByteArray, 0, 0xFF);
16329 THREADED_TEST(Int8Array) {
16330 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalByteArray>(
16331 v8::kExternalByteArray, -0x80, 0x7F);
16335 THREADED_TEST(Uint16Array) {
16336 TypedArrayTestHelper<uint16_t,
16338 i::ExternalUnsignedShortArray>(
16339 v8::kExternalUnsignedShortArray, 0, 0xFFFF);
16343 THREADED_TEST(Int16Array) {
16344 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalShortArray>(
16345 v8::kExternalShortArray, -0x8000, 0x7FFF);
16349 THREADED_TEST(Uint32Array) {
16350 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUnsignedIntArray>(
16351 v8::kExternalUnsignedIntArray, 0, UINT_MAX);
16355 THREADED_TEST(Int32Array) {
16356 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalIntArray>(
16357 v8::kExternalIntArray, INT_MIN, INT_MAX);
16361 THREADED_TEST(Float32Array) {
16362 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloatArray>(
16363 v8::kExternalFloatArray, -500, 500);
16367 THREADED_TEST(Float64Array) {
16368 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalDoubleArray>(
16369 v8::kExternalDoubleArray, -500, 500);
16373 THREADED_TEST(Uint8ClampedArray) {
16374 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, i::ExternalPixelArray>(
16375 v8::kExternalPixelArray, 0, 0xFF);
16379 THREADED_TEST(DataView) {
16380 const int kSize = 50;
16382 i::ScopedVector<uint8_t> backing_store(kSize+2);
16385 v8::Isolate* isolate = env->GetIsolate();
16386 v8::HandleScope handle_scope(isolate);
16388 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
16389 backing_store.start(), 2 + kSize);
16390 Local<v8::DataView> dv =
16391 v8::DataView::New(ab, 2, kSize);
16392 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16393 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
16394 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16395 CHECK_EQ(ab, dv->Buffer());
16399 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
16400 THREADED_TEST(Is##View) { \
16401 LocalContext env; \
16402 v8::Isolate* isolate = env->GetIsolate(); \
16403 v8::HandleScope handle_scope(isolate); \
16405 Handle<Value> result = CompileRun( \
16406 "var ab = new ArrayBuffer(128);" \
16407 "new " #View "(ab)"); \
16408 CHECK(result->IsArrayBufferView()); \
16409 CHECK(result->Is##View()); \
16410 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
16413 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16414 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16415 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16416 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
16417 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
16418 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
16419 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
16420 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
16421 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
16422 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
16424 #undef IS_ARRAY_BUFFER_VIEW_TEST
16428 THREADED_TEST(ScriptContextDependence) {
16430 v8::HandleScope scope(c1->GetIsolate());
16431 const char *source = "foo";
16432 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
16433 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
16434 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
16435 CHECK_EQ(dep->Run()->Int32Value(), 100);
16436 CHECK_EQ(indep->Run()->Int32Value(), 100);
16438 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
16439 CHECK_EQ(dep->Run()->Int32Value(), 100);
16440 CHECK_EQ(indep->Run()->Int32Value(), 101);
16444 THREADED_TEST(StackTrace) {
16445 LocalContext context;
16446 v8::HandleScope scope(context->GetIsolate());
16447 v8::TryCatch try_catch;
16448 const char *source = "function foo() { FAIL.FAIL; }; foo();";
16449 v8::Handle<v8::String> src = v8::String::New(source);
16450 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
16451 v8::Script::New(src, origin)->Run();
16452 CHECK(try_catch.HasCaught());
16453 v8::String::Utf8Value stack(try_catch.StackTrace());
16454 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
16458 // Checks that a StackFrame has certain expected values.
16459 void checkStackFrame(const char* expected_script_name,
16460 const char* expected_func_name, int expected_line_number,
16461 int expected_column, bool is_eval, bool is_constructor,
16462 v8::Handle<v8::StackFrame> frame) {
16463 v8::HandleScope scope(v8::Isolate::GetCurrent());
16464 v8::String::Utf8Value func_name(frame->GetFunctionName());
16465 v8::String::Utf8Value script_name(frame->GetScriptName());
16466 if (*script_name == NULL) {
16467 // The situation where there is no associated script, like for evals.
16468 CHECK(expected_script_name == NULL);
16470 CHECK(strstr(*script_name, expected_script_name) != NULL);
16472 CHECK(strstr(*func_name, expected_func_name) != NULL);
16473 CHECK_EQ(expected_line_number, frame->GetLineNumber());
16474 CHECK_EQ(expected_column, frame->GetColumn());
16475 CHECK_EQ(is_eval, frame->IsEval());
16476 CHECK_EQ(is_constructor, frame->IsConstructor());
16480 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
16481 v8::HandleScope scope(args.GetIsolate());
16482 const char* origin = "capture-stack-trace-test";
16483 const int kOverviewTest = 1;
16484 const int kDetailedTest = 2;
16486 ASSERT(args.Length() == 1);
16488 int testGroup = args[0]->Int32Value();
16489 if (testGroup == kOverviewTest) {
16490 v8::Handle<v8::StackTrace> stackTrace =
16491 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
16492 CHECK_EQ(4, stackTrace->GetFrameCount());
16493 checkStackFrame(origin, "bar", 2, 10, false, false,
16494 stackTrace->GetFrame(0));
16495 checkStackFrame(origin, "foo", 6, 3, false, false,
16496 stackTrace->GetFrame(1));
16497 // This is the source string inside the eval which has the call to foo.
16498 checkStackFrame(NULL, "", 1, 5, false, false,
16499 stackTrace->GetFrame(2));
16500 // The last frame is an anonymous function which has the initial eval call.
16501 checkStackFrame(origin, "", 8, 7, false, false,
16502 stackTrace->GetFrame(3));
16504 CHECK(stackTrace->AsArray()->IsArray());
16505 } else if (testGroup == kDetailedTest) {
16506 v8::Handle<v8::StackTrace> stackTrace =
16507 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16508 CHECK_EQ(4, stackTrace->GetFrameCount());
16509 checkStackFrame(origin, "bat", 4, 22, false, false,
16510 stackTrace->GetFrame(0));
16511 checkStackFrame(origin, "baz", 8, 3, false, true,
16512 stackTrace->GetFrame(1));
16513 #ifdef ENABLE_DEBUGGER_SUPPORT
16514 bool is_eval = true;
16515 #else // ENABLE_DEBUGGER_SUPPORT
16516 bool is_eval = false;
16517 #endif // ENABLE_DEBUGGER_SUPPORT
16519 // This is the source string inside the eval which has the call to baz.
16520 checkStackFrame(NULL, "", 1, 5, is_eval, false,
16521 stackTrace->GetFrame(2));
16522 // The last frame is an anonymous function which has the initial eval call.
16523 checkStackFrame(origin, "", 10, 1, false, false,
16524 stackTrace->GetFrame(3));
16526 CHECK(stackTrace->AsArray()->IsArray());
16531 // Tests the C++ StackTrace API.
16532 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
16533 // THREADED_TEST(CaptureStackTrace) {
16534 TEST(CaptureStackTrace) {
16535 v8::HandleScope scope(v8::Isolate::GetCurrent());
16536 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
16537 Local<ObjectTemplate> templ = ObjectTemplate::New();
16538 templ->Set(v8_str("AnalyzeStackInNativeCode"),
16539 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
16540 LocalContext context(0, templ);
16542 // Test getting OVERVIEW information. Should ignore information that is not
16543 // script name, function name, line number, and column offset.
16544 const char *overview_source =
16545 "function bar() {\n"
16546 " var y; AnalyzeStackInNativeCode(1);\n"
16548 "function foo() {\n"
16552 "var x;eval('new foo();');";
16553 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
16554 v8::Handle<Value> overview_result(
16555 v8::Script::New(overview_src, origin)->Run());
16556 CHECK(!overview_result.IsEmpty());
16557 CHECK(overview_result->IsObject());
16559 // Test getting DETAILED information.
16560 const char *detailed_source =
16561 "function bat() {AnalyzeStackInNativeCode(2);\n"
16564 "function baz() {\n"
16567 "eval('new baz();');";
16568 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
16569 // Make the script using a non-zero line and column offset.
16570 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
16571 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
16572 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
16573 v8::Handle<v8::Script> detailed_script(
16574 v8::Script::New(detailed_src, &detailed_origin));
16575 v8::Handle<Value> detailed_result(detailed_script->Run());
16576 CHECK(!detailed_result.IsEmpty());
16577 CHECK(detailed_result->IsObject());
16581 static void StackTraceForUncaughtExceptionListener(
16582 v8::Handle<v8::Message> message,
16583 v8::Handle<Value>) {
16584 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16585 CHECK_EQ(2, stack_trace->GetFrameCount());
16586 checkStackFrame("origin", "foo", 2, 3, false, false,
16587 stack_trace->GetFrame(0));
16588 checkStackFrame("origin", "bar", 5, 3, false, false,
16589 stack_trace->GetFrame(1));
16593 TEST(CaptureStackTraceForUncaughtException) {
16596 v8::HandleScope scope(env->GetIsolate());
16597 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
16598 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16600 Script::Compile(v8_str("function foo() {\n"
16603 "function bar() {\n"
16606 v8_str("origin"))->Run();
16607 v8::Local<v8::Object> global = env->Global();
16608 Local<Value> trouble = global->Get(v8_str("bar"));
16609 CHECK(trouble->IsFunction());
16610 Function::Cast(*trouble)->Call(global, 0, NULL);
16611 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16612 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
16616 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
16618 v8::HandleScope scope(env->GetIsolate());
16619 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
16621 v8::StackTrace::kDetailed);
16624 "var setters = ['column', 'lineNumber', 'scriptName',\n"
16625 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
16626 " 'isConstructor'];\n"
16627 "for (var i = 0; i < setters.length; i++) {\n"
16628 " var prop = setters[i];\n"
16629 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
16631 CompileRun("throw 'exception';");
16632 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16636 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
16637 v8::Handle<v8::Value> data) {
16638 // Use the frame where JavaScript is called from.
16639 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16640 CHECK(!stack_trace.IsEmpty());
16641 int frame_count = stack_trace->GetFrameCount();
16642 CHECK_EQ(3, frame_count);
16643 int line_number[] = {1, 2, 5};
16644 for (int i = 0; i < frame_count; i++) {
16645 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
16650 // Test that we only return the stack trace at the site where the exception
16651 // is first thrown (not where it is rethrown).
16652 TEST(RethrowStackTrace) {
16654 v8::HandleScope scope(env->GetIsolate());
16655 // We make sure that
16656 // - the stack trace of the ReferenceError in g() is reported.
16657 // - the stack trace is not overwritten when e1 is rethrown by t().
16658 // - the stack trace of e2 does not overwrite that of e1.
16659 const char* source =
16660 "function g() { error; } \n"
16661 "function f() { g(); } \n"
16662 "function t(e) { throw e; } \n"
16665 "} catch (e1) { \n"
16668 " } catch (e2) { \n"
16672 v8::V8::AddMessageListener(RethrowStackTraceHandler);
16673 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16674 CompileRun(source);
16675 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16676 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
16680 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
16681 v8::Handle<v8::Value> data) {
16682 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16683 CHECK(!stack_trace.IsEmpty());
16684 int frame_count = stack_trace->GetFrameCount();
16685 CHECK_EQ(2, frame_count);
16686 int line_number[] = {3, 7};
16687 for (int i = 0; i < frame_count; i++) {
16688 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
16693 // Test that we do not recognize identity for primitive exceptions.
16694 TEST(RethrowPrimitiveStackTrace) {
16696 v8::HandleScope scope(env->GetIsolate());
16697 // We do not capture stack trace for non Error objects on creation time.
16698 // Instead, we capture the stack trace on last throw.
16699 const char* source =
16700 "function g() { throw 404; } \n"
16701 "function f() { g(); } \n"
16702 "function t(e) { throw e; } \n"
16705 "} catch (e1) { \n"
16708 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
16709 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16710 CompileRun(source);
16711 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16712 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
16716 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
16717 v8::Handle<v8::Value> data) {
16718 // Use the frame where JavaScript is called from.
16719 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16720 CHECK(!stack_trace.IsEmpty());
16721 CHECK_EQ(1, stack_trace->GetFrameCount());
16722 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
16726 // Test that the stack trace is captured when the error object is created and
16727 // not where it is thrown.
16728 TEST(RethrowExistingStackTrace) {
16730 v8::HandleScope scope(env->GetIsolate());
16731 const char* source =
16732 "var e = new Error(); \n"
16734 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
16735 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16736 CompileRun(source);
16737 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16738 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
16742 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
16743 v8::Handle<v8::Value> data) {
16744 // Use the frame where JavaScript is called from.
16745 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16746 CHECK(!stack_trace.IsEmpty());
16747 CHECK_EQ(1, stack_trace->GetFrameCount());
16748 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
16752 // Test that the stack trace is captured where the bogus Error object is thrown.
16753 TEST(RethrowBogusErrorStackTrace) {
16755 v8::HandleScope scope(env->GetIsolate());
16756 const char* source =
16757 "var e = {__proto__: new Error()} \n"
16759 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
16760 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16761 CompileRun(source);
16762 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16763 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
16767 void AnalyzeStackOfEvalWithSourceURL(
16768 const v8::FunctionCallbackInfo<v8::Value>& args) {
16769 v8::HandleScope scope(args.GetIsolate());
16770 v8::Handle<v8::StackTrace> stackTrace =
16771 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16772 CHECK_EQ(5, stackTrace->GetFrameCount());
16773 v8::Handle<v8::String> url = v8_str("eval_url");
16774 for (int i = 0; i < 3; i++) {
16775 v8::Handle<v8::String> name =
16776 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16777 CHECK(!name.IsEmpty());
16778 CHECK_EQ(url, name);
16783 TEST(SourceURLInStackTrace) {
16784 v8::HandleScope scope(v8::Isolate::GetCurrent());
16785 Local<ObjectTemplate> templ = ObjectTemplate::New();
16786 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
16787 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
16788 LocalContext context(0, templ);
16790 const char *source =
16791 "function outer() {\n"
16792 "function bar() {\n"
16793 " AnalyzeStackOfEvalWithSourceURL();\n"
16795 "function foo() {\n"
16801 "eval('(' + outer +')()%s');";
16803 i::ScopedVector<char> code(1024);
16804 i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
16805 CHECK(CompileRun(code.start())->IsUndefined());
16806 i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
16807 CHECK(CompileRun(code.start())->IsUndefined());
16811 static int scriptIdInStack[2];
16813 void AnalyzeScriptIdInStack(
16814 const v8::FunctionCallbackInfo<v8::Value>& args) {
16815 v8::HandleScope scope(args.GetIsolate());
16816 v8::Handle<v8::StackTrace> stackTrace =
16817 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kScriptId);
16818 CHECK_EQ(2, stackTrace->GetFrameCount());
16819 for (int i = 0; i < 2; i++) {
16820 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
16825 TEST(ScriptIdInStackTrace) {
16826 v8::HandleScope scope(v8::Isolate::GetCurrent());
16827 Local<ObjectTemplate> templ = ObjectTemplate::New();
16828 templ->Set(v8_str("AnalyzeScriptIdInStack"),
16829 v8::FunctionTemplate::New(AnalyzeScriptIdInStack));
16830 LocalContext context(0, templ);
16832 v8::Handle<v8::String> scriptSource = v8::String::New(
16833 "function foo() {\n"
16834 " AnalyzeScriptIdInStack();"
16837 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
16838 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
16840 for (int i = 0; i < 2; i++) {
16841 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
16842 CHECK_EQ(scriptIdInStack[i], script->GetId());
16847 void AnalyzeStackOfInlineScriptWithSourceURL(
16848 const v8::FunctionCallbackInfo<v8::Value>& args) {
16849 v8::HandleScope scope(args.GetIsolate());
16850 v8::Handle<v8::StackTrace> stackTrace =
16851 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16852 CHECK_EQ(4, stackTrace->GetFrameCount());
16853 v8::Handle<v8::String> url = v8_str("url");
16854 for (int i = 0; i < 3; i++) {
16855 v8::Handle<v8::String> name =
16856 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16857 CHECK(!name.IsEmpty());
16858 CHECK_EQ(url, name);
16863 TEST(InlineScriptWithSourceURLInStackTrace) {
16864 v8::HandleScope scope(v8::Isolate::GetCurrent());
16865 Local<ObjectTemplate> templ = ObjectTemplate::New();
16866 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
16867 v8::FunctionTemplate::New(
16868 AnalyzeStackOfInlineScriptWithSourceURL));
16869 LocalContext context(0, templ);
16871 const char *source =
16872 "function outer() {\n"
16873 "function bar() {\n"
16874 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
16876 "function foo() {\n"
16884 i::ScopedVector<char> code(1024);
16885 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
16886 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
16887 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
16888 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
16892 void AnalyzeStackOfDynamicScriptWithSourceURL(
16893 const v8::FunctionCallbackInfo<v8::Value>& args) {
16894 v8::HandleScope scope(args.GetIsolate());
16895 v8::Handle<v8::StackTrace> stackTrace =
16896 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16897 CHECK_EQ(4, stackTrace->GetFrameCount());
16898 v8::Handle<v8::String> url = v8_str("source_url");
16899 for (int i = 0; i < 3; i++) {
16900 v8::Handle<v8::String> name =
16901 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16902 CHECK(!name.IsEmpty());
16903 CHECK_EQ(url, name);
16908 TEST(DynamicWithSourceURLInStackTrace) {
16909 v8::HandleScope scope(v8::Isolate::GetCurrent());
16910 Local<ObjectTemplate> templ = ObjectTemplate::New();
16911 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
16912 v8::FunctionTemplate::New(
16913 AnalyzeStackOfDynamicScriptWithSourceURL));
16914 LocalContext context(0, templ);
16916 const char *source =
16917 "function outer() {\n"
16918 "function bar() {\n"
16919 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
16921 "function foo() {\n"
16929 i::ScopedVector<char> code(1024);
16930 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
16931 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
16932 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
16933 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
16937 static void CreateGarbageInOldSpace() {
16938 i::Factory* factory = i::Isolate::Current()->factory();
16939 v8::HandleScope scope(v8::Isolate::GetCurrent());
16940 i::AlwaysAllocateScope always_allocate;
16941 for (int i = 0; i < 1000; i++) {
16942 factory->NewFixedArray(1000, i::TENURED);
16947 // Test that idle notification can be handled and eventually returns true.
16948 TEST(IdleNotification) {
16949 const intptr_t MB = 1024 * 1024;
16951 v8::HandleScope scope(env->GetIsolate());
16952 intptr_t initial_size = HEAP->SizeOfObjects();
16953 CreateGarbageInOldSpace();
16954 intptr_t size_with_garbage = HEAP->SizeOfObjects();
16955 CHECK_GT(size_with_garbage, initial_size + MB);
16956 bool finished = false;
16957 for (int i = 0; i < 200 && !finished; i++) {
16958 finished = v8::V8::IdleNotification();
16960 intptr_t final_size = HEAP->SizeOfObjects();
16962 CHECK_LT(final_size, initial_size + 1);
16966 // Test that idle notification can be handled and eventually collects garbage.
16967 TEST(IdleNotificationWithSmallHint) {
16968 const intptr_t MB = 1024 * 1024;
16969 const int IdlePauseInMs = 900;
16971 v8::HandleScope scope(env->GetIsolate());
16972 intptr_t initial_size = HEAP->SizeOfObjects();
16973 CreateGarbageInOldSpace();
16974 intptr_t size_with_garbage = HEAP->SizeOfObjects();
16975 CHECK_GT(size_with_garbage, initial_size + MB);
16976 bool finished = false;
16977 for (int i = 0; i < 200 && !finished; i++) {
16978 finished = v8::V8::IdleNotification(IdlePauseInMs);
16980 intptr_t final_size = HEAP->SizeOfObjects();
16982 CHECK_LT(final_size, initial_size + 1);
16986 // Test that idle notification can be handled and eventually collects garbage.
16987 TEST(IdleNotificationWithLargeHint) {
16988 const intptr_t MB = 1024 * 1024;
16989 const int IdlePauseInMs = 900;
16991 v8::HandleScope scope(env->GetIsolate());
16992 intptr_t initial_size = HEAP->SizeOfObjects();
16993 CreateGarbageInOldSpace();
16994 intptr_t size_with_garbage = HEAP->SizeOfObjects();
16995 CHECK_GT(size_with_garbage, initial_size + MB);
16996 bool finished = false;
16997 for (int i = 0; i < 200 && !finished; i++) {
16998 finished = v8::V8::IdleNotification(IdlePauseInMs);
17000 intptr_t final_size = HEAP->SizeOfObjects();
17002 CHECK_LT(final_size, initial_size + 1);
17006 TEST(Regress2107) {
17007 const intptr_t MB = 1024 * 1024;
17008 const int kShortIdlePauseInMs = 100;
17009 const int kLongIdlePauseInMs = 1000;
17011 v8::Isolate* isolate = env->GetIsolate();
17012 v8::HandleScope scope(env->GetIsolate());
17013 intptr_t initial_size = HEAP->SizeOfObjects();
17014 // Send idle notification to start a round of incremental GCs.
17015 v8::V8::IdleNotification(kShortIdlePauseInMs);
17016 // Emulate 7 page reloads.
17017 for (int i = 0; i < 7; i++) {
17019 v8::HandleScope inner_scope(env->GetIsolate());
17020 v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17022 CreateGarbageInOldSpace();
17025 v8::V8::ContextDisposedNotification();
17026 v8::V8::IdleNotification(kLongIdlePauseInMs);
17028 // Create garbage and check that idle notification still collects it.
17029 CreateGarbageInOldSpace();
17030 intptr_t size_with_garbage = HEAP->SizeOfObjects();
17031 CHECK_GT(size_with_garbage, initial_size + MB);
17032 bool finished = false;
17033 for (int i = 0; i < 200 && !finished; i++) {
17034 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17036 intptr_t final_size = HEAP->SizeOfObjects();
17037 CHECK_LT(final_size, initial_size + 1);
17040 static uint32_t* stack_limit;
17042 static void GetStackLimitCallback(
17043 const v8::FunctionCallbackInfo<v8::Value>& args) {
17044 stack_limit = reinterpret_cast<uint32_t*>(
17045 i::Isolate::Current()->stack_guard()->real_climit());
17049 // Uses the address of a local variable to determine the stack top now.
17050 // Given a size, returns an address that is that far from the current
17052 static uint32_t* ComputeStackLimit(uint32_t size) {
17053 uint32_t* answer = &size - (size / sizeof(size));
17054 // If the size is very large and the stack is very near the bottom of
17055 // memory then the calculation above may wrap around and give an address
17056 // that is above the (downwards-growing) stack. In that case we return
17057 // a very low address.
17058 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17063 // We need at least 165kB for an x64 debug build with clang and ASAN.
17064 static const int stack_breathing_room = 256 * i::KB;
17067 TEST(SetResourceConstraints) {
17068 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17070 // Set stack limit.
17071 v8::ResourceConstraints constraints;
17072 constraints.set_stack_limit(set_limit);
17073 CHECK(v8::SetResourceConstraints(&constraints));
17075 // Execute a script.
17077 v8::HandleScope scope(env->GetIsolate());
17078 Local<v8::FunctionTemplate> fun_templ =
17079 v8::FunctionTemplate::New(GetStackLimitCallback);
17080 Local<Function> fun = fun_templ->GetFunction();
17081 env->Global()->Set(v8_str("get_stack_limit"), fun);
17082 CompileRun("get_stack_limit();");
17084 CHECK(stack_limit == set_limit);
17088 TEST(SetResourceConstraintsInThread) {
17089 uint32_t* set_limit;
17091 v8::Locker locker(CcTest::default_isolate());
17092 set_limit = ComputeStackLimit(stack_breathing_room);
17094 // Set stack limit.
17095 v8::ResourceConstraints constraints;
17096 constraints.set_stack_limit(set_limit);
17097 CHECK(v8::SetResourceConstraints(&constraints));
17099 // Execute a script.
17100 v8::HandleScope scope(CcTest::default_isolate());
17102 Local<v8::FunctionTemplate> fun_templ =
17103 v8::FunctionTemplate::New(GetStackLimitCallback);
17104 Local<Function> fun = fun_templ->GetFunction();
17105 env->Global()->Set(v8_str("get_stack_limit"), fun);
17106 CompileRun("get_stack_limit();");
17108 CHECK(stack_limit == set_limit);
17111 v8::Locker locker(CcTest::default_isolate());
17112 CHECK(stack_limit == set_limit);
17117 THREADED_TEST(GetHeapStatistics) {
17119 v8::HandleScope scope(c1->GetIsolate());
17120 v8::HeapStatistics heap_statistics;
17121 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17122 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17123 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17124 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17125 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17129 class VisitorImpl : public v8::ExternalResourceVisitor {
17131 explicit VisitorImpl(TestResource** resource) {
17132 for (int i = 0; i < 4; i++) {
17133 resource_[i] = resource[i];
17134 found_resource_[i] = false;
17137 virtual ~VisitorImpl() {}
17138 virtual void VisitExternalString(v8::Handle<v8::String> string) {
17139 if (!string->IsExternal()) {
17140 CHECK(string->IsExternalAscii());
17143 v8::String::ExternalStringResource* resource =
17144 string->GetExternalStringResource();
17146 for (int i = 0; i < 4; i++) {
17147 if (resource_[i] == resource) {
17148 CHECK(!found_resource_[i]);
17149 found_resource_[i] = true;
17153 void CheckVisitedResources() {
17154 for (int i = 0; i < 4; i++) {
17155 CHECK(found_resource_[i]);
17160 v8::String::ExternalStringResource* resource_[4];
17161 bool found_resource_[4];
17165 TEST(VisitExternalStrings) {
17167 v8::HandleScope scope(env->GetIsolate());
17168 const char* string = "Some string";
17169 uint16_t* two_byte_string = AsciiToTwoByteString(string);
17170 TestResource* resource[4];
17171 resource[0] = new TestResource(two_byte_string);
17172 v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]);
17173 resource[1] = new TestResource(two_byte_string);
17174 v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]);
17176 // Externalized symbol.
17177 resource[2] = new TestResource(two_byte_string);
17178 v8::Local<v8::String> string2 = v8::String::NewSymbol(string);
17179 CHECK(string2->MakeExternal(resource[2]));
17181 // Symbolized External.
17182 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17183 v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]);
17184 HEAP->CollectAllAvailableGarbage(); // Tenure string.
17185 // Turn into a symbol.
17186 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17187 CHECK(!HEAP->InternalizeString(*string3_i)->IsFailure());
17188 CHECK(string3_i->IsInternalizedString());
17190 // We need to add usages for string* to avoid warnings in GCC 4.7
17191 CHECK(string0->IsExternal());
17192 CHECK(string1->IsExternal());
17193 CHECK(string2->IsExternal());
17194 CHECK(string3->IsExternal());
17196 VisitorImpl visitor(resource);
17197 v8::V8::VisitExternalResources(&visitor);
17198 visitor.CheckVisitedResources();
17202 static double DoubleFromBits(uint64_t value) {
17204 i::OS::MemCopy(&target, &value, sizeof(target));
17209 static uint64_t DoubleToBits(double value) {
17211 i::OS::MemCopy(&target, &value, sizeof(target));
17216 static double DoubleToDateTime(double input) {
17217 double date_limit = 864e13;
17218 if (std::isnan(input) || input < -date_limit || input > date_limit) {
17219 return i::OS::nan_value();
17221 return (input < 0) ? -(floor(-input)) : floor(input);
17225 // We don't have a consistent way to write 64-bit constants syntactically, so we
17226 // split them into two 32-bit constants and combine them programmatically.
17227 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
17228 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
17232 THREADED_TEST(QuietSignalingNaNs) {
17233 LocalContext context;
17234 v8::HandleScope scope(context->GetIsolate());
17235 v8::TryCatch try_catch;
17237 // Special double values.
17238 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
17239 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
17240 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
17241 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
17242 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
17243 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
17244 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
17246 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
17247 // on either side of the epoch.
17248 double date_limit = 864e13;
17250 double test_values[] = {
17272 int num_test_values = 20;
17274 for (int i = 0; i < num_test_values; i++) {
17275 double test_value = test_values[i];
17277 // Check that Number::New preserves non-NaNs and quiets SNaNs.
17278 v8::Handle<v8::Value> number = v8::Number::New(test_value);
17279 double stored_number = number->NumberValue();
17280 if (!std::isnan(test_value)) {
17281 CHECK_EQ(test_value, stored_number);
17283 uint64_t stored_bits = DoubleToBits(stored_number);
17284 // Check if quiet nan (bits 51..62 all set).
17285 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
17286 // Most significant fraction bit for quiet nan is set to 0
17287 // on MIPS architecture. Allowed by IEEE-754.
17288 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
17290 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
17294 // Check that Date::New preserves non-NaNs in the date range and
17296 v8::Handle<v8::Value> date = v8::Date::New(test_value);
17297 double expected_stored_date = DoubleToDateTime(test_value);
17298 double stored_date = date->NumberValue();
17299 if (!std::isnan(expected_stored_date)) {
17300 CHECK_EQ(expected_stored_date, stored_date);
17302 uint64_t stored_bits = DoubleToBits(stored_date);
17303 // Check if quiet nan (bits 51..62 all set).
17304 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
17305 // Most significant fraction bit for quiet nan is set to 0
17306 // on MIPS architecture. Allowed by IEEE-754.
17307 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
17309 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
17316 static void SpaghettiIncident(
17317 const v8::FunctionCallbackInfo<v8::Value>& args) {
17318 v8::HandleScope scope(args.GetIsolate());
17320 v8::Handle<v8::String> str(args[0]->ToString());
17322 if (tc.HasCaught())
17327 // Test that an exception can be propagated down through a spaghetti
17328 // stack using ReThrow.
17329 THREADED_TEST(SpaghettiStackReThrow) {
17330 v8::HandleScope scope(v8::Isolate::GetCurrent());
17331 LocalContext context;
17332 context->Global()->Set(
17333 v8::String::New("s"),
17334 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
17335 v8::TryCatch try_catch;
17339 " toString: function () {"
17349 CHECK(try_catch.HasCaught());
17350 v8::String::Utf8Value value(try_catch.Exception());
17351 CHECK_EQ(0, strcmp(*value, "Hey!"));
17356 v8::V8::Initialize();
17357 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17358 v8::HandleScope scope(isolate);
17359 v8::Local<Context> other_context;
17362 // Create a context used to keep the code from aging in the compilation
17364 other_context = Context::New(isolate);
17366 // Context-dependent context data creates reference from the compilation
17367 // cache to the global object.
17368 const char* source_simple = "1";
17370 v8::HandleScope scope(isolate);
17371 v8::Local<Context> context = Context::New(isolate);
17374 Local<v8::String> obj = v8::String::New("");
17375 context->SetEmbedderData(0, obj);
17376 CompileRun(source_simple);
17379 v8::V8::ContextDisposedNotification();
17380 for (gc_count = 1; gc_count < 10; gc_count++) {
17381 other_context->Enter();
17382 CompileRun(source_simple);
17383 other_context->Exit();
17384 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17385 if (GetGlobalObjectsCount() == 1) break;
17387 CHECK_GE(2, gc_count);
17388 CHECK_EQ(1, GetGlobalObjectsCount());
17390 // Eval in a function creates reference from the compilation cache to the
17392 const char* source_eval = "function f(){eval('1')}; f()";
17394 v8::HandleScope scope(isolate);
17395 v8::Local<Context> context = Context::New(isolate);
17398 CompileRun(source_eval);
17401 v8::V8::ContextDisposedNotification();
17402 for (gc_count = 1; gc_count < 10; gc_count++) {
17403 other_context->Enter();
17404 CompileRun(source_eval);
17405 other_context->Exit();
17406 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17407 if (GetGlobalObjectsCount() == 1) break;
17409 CHECK_GE(2, gc_count);
17410 CHECK_EQ(1, GetGlobalObjectsCount());
17412 // Looking up the line number for an exception creates reference from the
17413 // compilation cache to the global object.
17414 const char* source_exception = "function f(){throw 1;} f()";
17416 v8::HandleScope scope(isolate);
17417 v8::Local<Context> context = Context::New(isolate);
17420 v8::TryCatch try_catch;
17421 CompileRun(source_exception);
17422 CHECK(try_catch.HasCaught());
17423 v8::Handle<v8::Message> message = try_catch.Message();
17424 CHECK(!message.IsEmpty());
17425 CHECK_EQ(1, message->GetLineNumber());
17428 v8::V8::ContextDisposedNotification();
17429 for (gc_count = 1; gc_count < 10; gc_count++) {
17430 other_context->Enter();
17431 CompileRun(source_exception);
17432 other_context->Exit();
17433 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17434 if (GetGlobalObjectsCount() == 1) break;
17436 CHECK_GE(2, gc_count);
17437 CHECK_EQ(1, GetGlobalObjectsCount());
17439 v8::V8::ContextDisposedNotification();
17443 THREADED_TEST(ScriptOrigin) {
17445 v8::HandleScope scope(env->GetIsolate());
17446 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17447 v8::Handle<v8::String> script = v8::String::New(
17448 "function f() {}\n\nfunction g() {}");
17449 v8::Script::Compile(script, &origin)->Run();
17450 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17451 env->Global()->Get(v8::String::New("f")));
17452 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17453 env->Global()->Get(v8::String::New("g")));
17455 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
17456 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
17457 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
17459 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
17460 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
17461 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
17465 THREADED_TEST(FunctionGetInferredName) {
17467 v8::HandleScope scope(env->GetIsolate());
17468 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17469 v8::Handle<v8::String> script = v8::String::New(
17470 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
17471 v8::Script::Compile(script, &origin)->Run();
17472 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17473 env->Global()->Get(v8::String::New("f")));
17474 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
17478 THREADED_TEST(ScriptLineNumber) {
17480 v8::HandleScope scope(env->GetIsolate());
17481 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17482 v8::Handle<v8::String> script = v8::String::New(
17483 "function f() {}\n\nfunction g() {}");
17484 v8::Script::Compile(script, &origin)->Run();
17485 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17486 env->Global()->Get(v8::String::New("f")));
17487 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17488 env->Global()->Get(v8::String::New("g")));
17489 CHECK_EQ(0, f->GetScriptLineNumber());
17490 CHECK_EQ(2, g->GetScriptLineNumber());
17494 THREADED_TEST(ScriptColumnNumber) {
17496 v8::HandleScope scope(env->GetIsolate());
17497 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
17498 v8::Integer::New(3), v8::Integer::New(2));
17499 v8::Handle<v8::String> script = v8::String::New(
17500 "function foo() {}\n\n function bar() {}");
17501 v8::Script::Compile(script, &origin)->Run();
17502 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
17503 env->Global()->Get(v8::String::New("foo")));
17504 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
17505 env->Global()->Get(v8::String::New("bar")));
17506 CHECK_EQ(14, foo->GetScriptColumnNumber());
17507 CHECK_EQ(17, bar->GetScriptColumnNumber());
17511 THREADED_TEST(FunctionGetScriptId) {
17513 v8::HandleScope scope(env->GetIsolate());
17514 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
17515 v8::Integer::New(3), v8::Integer::New(2));
17516 v8::Handle<v8::String> scriptSource = v8::String::New(
17517 "function foo() {}\n\n function bar() {}");
17518 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
17520 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
17521 env->Global()->Get(v8::String::New("foo")));
17522 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
17523 env->Global()->Get(v8::String::New("bar")));
17524 CHECK_EQ(script->Id(), foo->GetScriptId());
17525 CHECK_EQ(script->Id(), bar->GetScriptId());
17529 static void GetterWhichReturns42(
17530 Local<String> name,
17531 const v8::PropertyCallbackInfo<v8::Value>& info) {
17532 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17533 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17534 info.GetReturnValue().Set(v8_num(42));
17538 static void SetterWhichSetsYOnThisTo23(
17539 Local<String> name,
17540 Local<Value> value,
17541 const v8::PropertyCallbackInfo<void>& info) {
17542 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17543 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17544 info.This()->Set(v8_str("y"), v8_num(23));
17548 void FooGetInterceptor(Local<String> name,
17549 const v8::PropertyCallbackInfo<v8::Value>& info) {
17550 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17551 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17552 if (!name->Equals(v8_str("foo"))) return;
17553 info.GetReturnValue().Set(v8_num(42));
17557 void FooSetInterceptor(Local<String> name,
17558 Local<Value> value,
17559 const v8::PropertyCallbackInfo<v8::Value>& info) {
17560 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17561 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17562 if (!name->Equals(v8_str("foo"))) return;
17563 info.This()->Set(v8_str("y"), v8_num(23));
17564 info.GetReturnValue().Set(v8_num(23));
17568 TEST(SetterOnConstructorPrototype) {
17569 v8::HandleScope scope(v8::Isolate::GetCurrent());
17570 Local<ObjectTemplate> templ = ObjectTemplate::New();
17571 templ->SetAccessor(v8_str("x"),
17572 GetterWhichReturns42,
17573 SetterWhichSetsYOnThisTo23);
17574 LocalContext context;
17575 context->Global()->Set(v8_str("P"), templ->NewInstance());
17576 CompileRun("function C1() {"
17579 "C1.prototype = P;"
17583 "C2.prototype = { };"
17584 "C2.prototype.__proto__ = P;");
17586 v8::Local<v8::Script> script;
17587 script = v8::Script::Compile(v8_str("new C1();"));
17588 for (int i = 0; i < 10; i++) {
17589 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17590 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
17591 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
17594 script = v8::Script::Compile(v8_str("new C2();"));
17595 for (int i = 0; i < 10; i++) {
17596 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
17597 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
17598 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
17603 static void NamedPropertyGetterWhichReturns42(
17604 Local<String> name,
17605 const v8::PropertyCallbackInfo<v8::Value>& info) {
17606 info.GetReturnValue().Set(v8_num(42));
17610 static void NamedPropertySetterWhichSetsYOnThisTo23(
17611 Local<String> name,
17612 Local<Value> value,
17613 const v8::PropertyCallbackInfo<v8::Value>& info) {
17614 if (name->Equals(v8_str("x"))) {
17615 info.This()->Set(v8_str("y"), v8_num(23));
17620 THREADED_TEST(InterceptorOnConstructorPrototype) {
17621 v8::HandleScope scope(v8::Isolate::GetCurrent());
17622 Local<ObjectTemplate> templ = ObjectTemplate::New();
17623 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
17624 NamedPropertySetterWhichSetsYOnThisTo23);
17625 LocalContext context;
17626 context->Global()->Set(v8_str("P"), templ->NewInstance());
17627 CompileRun("function C1() {"
17630 "C1.prototype = P;"
17634 "C2.prototype = { };"
17635 "C2.prototype.__proto__ = P;");
17637 v8::Local<v8::Script> script;
17638 script = v8::Script::Compile(v8_str("new C1();"));
17639 for (int i = 0; i < 10; i++) {
17640 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17641 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
17642 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
17645 script = v8::Script::Compile(v8_str("new C2();"));
17646 for (int i = 0; i < 10; i++) {
17647 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
17648 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
17649 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
17655 const char* source = "function C1() {"
17658 "C1.prototype = P;";
17660 LocalContext context;
17661 v8::HandleScope scope(context->GetIsolate());
17662 v8::Local<v8::Script> script;
17664 // Use a simple object as prototype.
17665 v8::Local<v8::Object> prototype = v8::Object::New();
17666 prototype->Set(v8_str("y"), v8_num(42));
17667 context->Global()->Set(v8_str("P"), prototype);
17669 // This compile will add the code to the compilation cache.
17670 CompileRun(source);
17672 script = v8::Script::Compile(v8_str("new C1();"));
17673 // Allow enough iterations for the inobject slack tracking logic
17674 // to finalize instance size and install the fast construct stub.
17675 for (int i = 0; i < 256; i++) {
17676 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17677 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
17678 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
17681 // Use an API object with accessors as prototype.
17682 Local<ObjectTemplate> templ = ObjectTemplate::New();
17683 templ->SetAccessor(v8_str("x"),
17684 GetterWhichReturns42,
17685 SetterWhichSetsYOnThisTo23);
17686 context->Global()->Set(v8_str("P"), templ->NewInstance());
17688 // This compile will get the code from the compilation cache.
17689 CompileRun(source);
17691 script = v8::Script::Compile(v8_str("new C1();"));
17692 for (int i = 0; i < 10; i++) {
17693 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17694 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
17695 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
17699 int prologue_call_count = 0;
17700 int epilogue_call_count = 0;
17701 int prologue_call_count_second = 0;
17702 int epilogue_call_count_second = 0;
17704 void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
17705 ++prologue_call_count;
17709 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
17710 ++epilogue_call_count;
17714 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
17715 ++prologue_call_count_second;
17719 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
17720 ++epilogue_call_count_second;
17724 TEST(GCCallbacks) {
17725 LocalContext context;
17727 v8::V8::AddGCPrologueCallback(PrologueCallback);
17728 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
17729 CHECK_EQ(0, prologue_call_count);
17730 CHECK_EQ(0, epilogue_call_count);
17731 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17732 CHECK_EQ(1, prologue_call_count);
17733 CHECK_EQ(1, epilogue_call_count);
17734 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
17735 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
17736 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17737 CHECK_EQ(2, prologue_call_count);
17738 CHECK_EQ(2, epilogue_call_count);
17739 CHECK_EQ(1, prologue_call_count_second);
17740 CHECK_EQ(1, epilogue_call_count_second);
17741 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
17742 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
17743 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17744 CHECK_EQ(2, prologue_call_count);
17745 CHECK_EQ(2, epilogue_call_count);
17746 CHECK_EQ(2, prologue_call_count_second);
17747 CHECK_EQ(2, epilogue_call_count_second);
17748 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
17749 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17750 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17751 CHECK_EQ(2, prologue_call_count);
17752 CHECK_EQ(2, epilogue_call_count);
17753 CHECK_EQ(2, prologue_call_count_second);
17754 CHECK_EQ(2, epilogue_call_count_second);
17758 THREADED_TEST(AddToJSFunctionResultCache) {
17759 i::FLAG_stress_compaction = false;
17760 i::FLAG_allow_natives_syntax = true;
17761 v8::HandleScope scope(v8::Isolate::GetCurrent());
17763 LocalContext context;
17769 " var r0 = %_GetFromCache(0, key0);"
17770 " var r1 = %_GetFromCache(0, key1);"
17771 " var r0_ = %_GetFromCache(0, key0);"
17773 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
17774 " var r1_ = %_GetFromCache(0, key1);"
17776 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
17777 " return 'PASSED';"
17779 HEAP->ClearJSFunctionResultCaches();
17780 ExpectString(code, "PASSED");
17784 static const int k0CacheSize = 16;
17786 THREADED_TEST(FillJSFunctionResultCache) {
17787 i::FLAG_allow_natives_syntax = true;
17788 LocalContext context;
17789 v8::HandleScope scope(context->GetIsolate());
17794 " var r = %_GetFromCache(0, k);"
17795 " for (var i = 0; i < 16; i++) {"
17796 " %_GetFromCache(0, 'a' + i);"
17798 " if (r === %_GetFromCache(0, k))"
17799 " return 'FAILED: k0CacheSize is too small';"
17800 " return 'PASSED';"
17802 HEAP->ClearJSFunctionResultCaches();
17803 ExpectString(code, "PASSED");
17807 THREADED_TEST(RoundRobinGetFromCache) {
17808 i::FLAG_allow_natives_syntax = true;
17809 LocalContext context;
17810 v8::HandleScope scope(context->GetIsolate());
17815 " for (var i = 0; i < 16; i++) keys.push(i);"
17816 " var values = [];"
17817 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17818 " for (var i = 0; i < 16; i++) {"
17819 " var v = %_GetFromCache(0, keys[i]);"
17820 " if (v.toString() !== values[i].toString())"
17821 " return 'Wrong value for ' + "
17822 " keys[i] + ': ' + v + ' vs. ' + values[i];"
17824 " return 'PASSED';"
17826 HEAP->ClearJSFunctionResultCaches();
17827 ExpectString(code, "PASSED");
17831 THREADED_TEST(ReverseGetFromCache) {
17832 i::FLAG_allow_natives_syntax = true;
17833 LocalContext context;
17834 v8::HandleScope scope(context->GetIsolate());
17839 " for (var i = 0; i < 16; i++) keys.push(i);"
17840 " var values = [];"
17841 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17842 " for (var i = 15; i >= 16; i--) {"
17843 " var v = %_GetFromCache(0, keys[i]);"
17844 " if (v !== values[i])"
17845 " return 'Wrong value for ' + "
17846 " keys[i] + ': ' + v + ' vs. ' + values[i];"
17848 " return 'PASSED';"
17850 HEAP->ClearJSFunctionResultCaches();
17851 ExpectString(code, "PASSED");
17855 THREADED_TEST(TestEviction) {
17856 i::FLAG_allow_natives_syntax = true;
17857 LocalContext context;
17858 v8::HandleScope scope(context->GetIsolate());
17862 " for (var i = 0; i < 2*16; i++) {"
17863 " %_GetFromCache(0, 'a' + i);"
17865 " return 'PASSED';"
17867 HEAP->ClearJSFunctionResultCaches();
17868 ExpectString(code, "PASSED");
17872 THREADED_TEST(TwoByteStringInAsciiCons) {
17873 // See Chromium issue 47824.
17874 LocalContext context;
17875 v8::HandleScope scope(context->GetIsolate());
17877 const char* init_code =
17878 "var str1 = 'abelspendabel';"
17879 "var str2 = str1 + str1 + str1;"
17881 Local<Value> result = CompileRun(init_code);
17883 Local<Value> indexof = CompileRun("str2.indexOf('els')");
17884 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
17886 CHECK(result->IsString());
17887 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
17888 int length = string->length();
17889 CHECK(string->IsOneByteRepresentation());
17891 FlattenString(string);
17892 i::Handle<i::String> flat_string = FlattenGetString(string);
17894 CHECK(string->IsOneByteRepresentation());
17895 CHECK(flat_string->IsOneByteRepresentation());
17897 // Create external resource.
17898 uint16_t* uc16_buffer = new uint16_t[length + 1];
17900 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
17901 uc16_buffer[length] = 0;
17903 TestResource resource(uc16_buffer);
17905 flat_string->MakeExternal(&resource);
17907 CHECK(flat_string->IsTwoByteRepresentation());
17909 // If the cons string has been short-circuited, skip the following checks.
17910 if (!string.is_identical_to(flat_string)) {
17911 // At this point, we should have a Cons string which is flat and ASCII,
17912 // with a first half that is a two-byte string (although it only contains
17913 // ASCII characters). This is a valid sequence of steps, and it can happen
17915 CHECK(string->IsOneByteRepresentation());
17916 i::ConsString* cons = i::ConsString::cast(*string);
17917 CHECK_EQ(0, cons->second()->length());
17918 CHECK(cons->first()->IsTwoByteRepresentation());
17921 // Check that some string operations work.
17924 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
17925 CHECK_EQ(6, reresult->Int32Value());
17928 reresult = CompileRun("str2.match(/abe./g).length;");
17929 CHECK_EQ(6, reresult->Int32Value());
17931 reresult = CompileRun("str2.search(/bel/g);");
17932 CHECK_EQ(1, reresult->Int32Value());
17934 reresult = CompileRun("str2.search(/be./g);");
17935 CHECK_EQ(1, reresult->Int32Value());
17937 ExpectTrue("/bel/g.test(str2);");
17939 ExpectTrue("/be./g.test(str2);");
17941 reresult = CompileRun("/bel/g.exec(str2);");
17942 CHECK(!reresult->IsNull());
17944 reresult = CompileRun("/be./g.exec(str2);");
17945 CHECK(!reresult->IsNull());
17947 ExpectString("str2.substring(2, 10);", "elspenda");
17949 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
17951 ExpectString("str2.charAt(2);", "e");
17953 ExpectObject("str2.indexOf('els');", indexof);
17955 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
17957 reresult = CompileRun("str2.charCodeAt(2);");
17958 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
17962 TEST(ContainsOnlyOneByte) {
17963 v8::V8::Initialize();
17964 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17965 v8::HandleScope scope(isolate);
17966 // Make a buffer long enough that it won't automatically be converted.
17967 const int length = 512;
17968 // Ensure word aligned assignment.
17969 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
17970 i::SmartArrayPointer<uintptr_t>
17971 aligned_contents(new uintptr_t[aligned_length]);
17972 uint16_t* string_contents = reinterpret_cast<uint16_t*>(*aligned_contents);
17973 // Set to contain only one byte.
17974 for (int i = 0; i < length-1; i++) {
17975 string_contents[i] = 0x41;
17977 string_contents[length-1] = 0;
17979 Handle<String> string;
17980 string = String::NewExternal(new TestResource(string_contents));
17981 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17982 // Counter example.
17983 string = String::NewFromTwoByte(isolate, string_contents);
17984 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
17985 // Test left right and balanced cons strings.
17986 Handle<String> base = String::NewFromUtf8(isolate, "a");
17987 Handle<String> left = base;
17988 Handle<String> right = base;
17989 for (int i = 0; i < 1000; i++) {
17990 left = String::Concat(base, left);
17991 right = String::Concat(right, base);
17993 Handle<String> balanced = String::Concat(left, base);
17994 balanced = String::Concat(balanced, right);
17995 Handle<String> cons_strings[] = {left, balanced, right};
17996 Handle<String> two_byte =
17997 String::NewExternal(new TestResource(string_contents));
17998 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
17999 // Base assumptions.
18000 string = cons_strings[i];
18001 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18002 // Test left and right concatentation.
18003 string = String::Concat(two_byte, cons_strings[i]);
18004 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18005 string = String::Concat(cons_strings[i], two_byte);
18006 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18008 // Set bits in different positions
18009 // for strings of different lengths and alignments.
18010 for (int alignment = 0; alignment < 7; alignment++) {
18011 for (int size = 2; alignment + size < length; size *= 2) {
18012 int zero_offset = size + alignment;
18013 string_contents[zero_offset] = 0;
18014 for (int i = 0; i < size; i++) {
18015 int shift = 8 + (i % 7);
18016 string_contents[alignment + i] = 1 << shift;
18018 String::NewExternal(new TestResource(string_contents + alignment));
18019 CHECK_EQ(size, string->Length());
18020 CHECK(!string->ContainsOnlyOneByte());
18021 string_contents[alignment + i] = 0x41;
18023 string_contents[zero_offset] = 0x41;
18029 // Failed access check callback that performs a GC on each invocation.
18030 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
18031 v8::AccessType type,
18032 Local<v8::Value> data) {
18033 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
18037 TEST(GCInFailedAccessCheckCallback) {
18038 // Install a failed access check callback that performs a GC on each
18039 // invocation. Then force the callback to be called from va
18041 v8::V8::Initialize();
18042 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
18044 v8::HandleScope scope(v8::Isolate::GetCurrent());
18046 // Create an ObjectTemplate for global objects and install access
18047 // check callbacks that will block access.
18048 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
18049 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
18050 IndexedGetAccessBlocker,
18051 v8::Handle<v8::Value>(),
18054 // Create a context and set an x property on it's global object.
18055 LocalContext context0(NULL, global_template);
18056 context0->Global()->Set(v8_str("x"), v8_num(42));
18057 v8::Handle<v8::Object> global0 = context0->Global();
18059 // Create a context with a different security token so that the
18060 // failed access check callback will be called on each access.
18061 LocalContext context1(NULL, global_template);
18062 context1->Global()->Set(v8_str("other"), global0);
18064 // Get property with failed access check.
18065 ExpectUndefined("other.x");
18067 // Get element with failed access check.
18068 ExpectUndefined("other[0]");
18070 // Set property with failed access check.
18071 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
18072 CHECK(result->IsObject());
18074 // Set element with failed access check.
18075 result = CompileRun("other[0] = new Object()");
18076 CHECK(result->IsObject());
18078 // Get property attribute with failed access check.
18079 ExpectFalse("\'x\' in other");
18081 // Get property attribute for element with failed access check.
18082 ExpectFalse("0 in other");
18084 // Delete property.
18085 ExpectFalse("delete other.x");
18088 CHECK_EQ(false, global0->Delete(0));
18092 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
18094 // Define JavaScript accessor.
18095 ExpectUndefined("Object.prototype.__defineGetter__.call("
18096 " other, \'x\', function() { return 42; })");
18099 ExpectUndefined("Object.prototype.__lookupGetter__.call("
18102 // HasLocalElement.
18103 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
18105 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
18106 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
18107 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
18109 // Reset the failed access check callback so it does not influence
18110 // the other tests.
18111 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
18115 TEST(DefaultIsolateGetCurrent) {
18116 CHECK(v8::Isolate::GetCurrent() != NULL);
18117 v8::Isolate* isolate = v8::Isolate::GetCurrent();
18118 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
18119 printf("*** %s\n", "DefaultIsolateGetCurrent success");
18123 TEST(IsolateNewDispose) {
18124 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
18125 v8::Isolate* isolate = v8::Isolate::New();
18126 CHECK(isolate != NULL);
18127 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
18128 CHECK(current_isolate != isolate);
18129 CHECK(current_isolate == v8::Isolate::GetCurrent());
18131 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
18132 last_location = last_message = NULL;
18133 isolate->Dispose();
18134 CHECK_EQ(last_location, NULL);
18135 CHECK_EQ(last_message, NULL);
18139 TEST(IsolateEnterExitDefault) {
18140 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
18141 CHECK(current_isolate != NULL); // Default isolate.
18142 v8::HandleScope scope(current_isolate);
18143 LocalContext context;
18144 ExpectString("'hello'", "hello");
18145 current_isolate->Enter();
18146 ExpectString("'still working'", "still working");
18147 current_isolate->Exit();
18148 ExpectString("'still working 2'", "still working 2");
18149 current_isolate->Exit();
18150 // Default isolate is always, well, 'default current'.
18151 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
18152 // Still working since default isolate is auto-entering any thread
18153 // that has no isolate and attempts to execute V8 APIs.
18154 ExpectString("'still working 3'", "still working 3");
18158 TEST(DisposeDefaultIsolate) {
18159 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
18161 // Run some V8 code to trigger default isolate to become 'current'.
18162 v8::HandleScope scope(v8::Isolate::GetCurrent());
18163 LocalContext context;
18164 ExpectString("'run some V8'", "run some V8");
18166 v8::Isolate* isolate = v8::Isolate::GetCurrent();
18167 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
18168 last_location = last_message = NULL;
18169 isolate->Dispose();
18170 // It is not possible to dispose default isolate via Isolate API.
18171 CHECK_NE(last_location, NULL);
18172 CHECK_NE(last_message, NULL);
18176 TEST(RunDefaultAndAnotherIsolate) {
18177 v8::HandleScope scope(v8::Isolate::GetCurrent());
18178 LocalContext context;
18180 // Enter new isolate.
18181 v8::Isolate* isolate = v8::Isolate::New();
18184 { // Need this block because subsequent Exit() will deallocate Heap,
18185 // so we need all scope objects to be deconstructed when it happens.
18186 v8::HandleScope scope_new(isolate);
18187 LocalContext context_new;
18189 // Run something in new isolate.
18190 CompileRun("var foo = 153;");
18191 ExpectTrue("function f() { return foo == 153; }; f()");
18195 // This runs automatically in default isolate.
18196 // Variables in another isolate should be not available.
18197 ExpectTrue("function f() {"
18208 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
18209 last_location = last_message = NULL;
18210 isolate->Dispose();
18211 CHECK_EQ(last_location, NULL);
18212 CHECK_EQ(last_message, NULL);
18214 // Check that default isolate still runs.
18215 ExpectTrue("function f() { return bar == 371; }; f()");
18219 TEST(DisposeIsolateWhenInUse) {
18220 v8::Isolate* isolate = v8::Isolate::New();
18223 v8::HandleScope scope(isolate);
18224 LocalContext context;
18225 // Run something in this isolate.
18226 ExpectTrue("true");
18227 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
18228 last_location = last_message = NULL;
18229 // Still entered, should fail.
18230 isolate->Dispose();
18231 CHECK_NE(last_location, NULL);
18232 CHECK_NE(last_message, NULL);
18236 TEST(RunTwoIsolatesOnSingleThread) {
18238 v8::Isolate* isolate1 = v8::Isolate::New();
18240 v8::Persistent<v8::Context> context1;
18242 v8::HandleScope scope(isolate1);
18243 context1.Reset(isolate1, Context::New(isolate1));
18247 v8::HandleScope scope(isolate1);
18248 v8::Local<v8::Context> context =
18249 v8::Local<v8::Context>::New(isolate1, context1);
18250 v8::Context::Scope context_scope(context);
18251 // Run something in new isolate.
18252 CompileRun("var foo = 'isolate 1';");
18253 ExpectString("function f() { return foo; }; f()", "isolate 1");
18257 v8::Isolate* isolate2 = v8::Isolate::New();
18258 v8::Persistent<v8::Context> context2;
18261 v8::Isolate::Scope iscope(isolate2);
18262 v8::HandleScope scope(isolate2);
18263 context2.Reset(isolate2, Context::New(isolate2));
18264 v8::Local<v8::Context> context =
18265 v8::Local<v8::Context>::New(isolate2, context2);
18266 v8::Context::Scope context_scope(context);
18268 // Run something in new isolate.
18269 CompileRun("var foo = 'isolate 2';");
18270 ExpectString("function f() { return foo; }; f()", "isolate 2");
18274 v8::HandleScope scope(isolate1);
18275 v8::Local<v8::Context> context =
18276 v8::Local<v8::Context>::New(isolate1, context1);
18277 v8::Context::Scope context_scope(context);
18278 // Now again in isolate 1
18279 ExpectString("function f() { return foo; }; f()", "isolate 1");
18284 // Run some stuff in default isolate.
18285 v8::Persistent<v8::Context> context_default;
18287 v8::Isolate* isolate = v8::Isolate::GetCurrent();
18288 v8::Isolate::Scope iscope(isolate);
18289 v8::HandleScope scope(isolate);
18290 context_default.Reset(isolate, Context::New(isolate));
18294 v8::HandleScope scope(v8::Isolate::GetCurrent());
18295 v8::Local<v8::Context> context =
18296 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context_default);
18297 v8::Context::Scope context_scope(context);
18298 // Variables in other isolates should be not available, verify there
18299 // is an exception.
18300 ExpectTrue("function f() {"
18308 "var isDefaultIsolate = true;"
18315 v8::Isolate::Scope iscope(isolate2);
18316 v8::HandleScope scope(v8::Isolate::GetCurrent());
18317 v8::Local<v8::Context> context =
18318 v8::Local<v8::Context>::New(isolate2, context2);
18319 v8::Context::Scope context_scope(context);
18320 ExpectString("function f() { return foo; }; f()", "isolate 2");
18324 v8::HandleScope scope(v8::Isolate::GetCurrent());
18325 v8::Local<v8::Context> context =
18326 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
18327 v8::Context::Scope context_scope(context);
18328 ExpectString("function f() { return foo; }; f()", "isolate 1");
18332 v8::Isolate::Scope iscope(isolate2);
18333 context2.Dispose();
18336 context1.Dispose();
18339 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
18340 last_location = last_message = NULL;
18342 isolate1->Dispose();
18343 CHECK_EQ(last_location, NULL);
18344 CHECK_EQ(last_message, NULL);
18346 isolate2->Dispose();
18347 CHECK_EQ(last_location, NULL);
18348 CHECK_EQ(last_message, NULL);
18350 // Check that default isolate still runs.
18352 v8::HandleScope scope(v8::Isolate::GetCurrent());
18353 v8::Local<v8::Context> context =
18354 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context_default);
18355 v8::Context::Scope context_scope(context);
18356 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
18361 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
18362 v8::Isolate::Scope isolate_scope(isolate);
18363 v8::HandleScope scope(isolate);
18364 LocalContext context;
18365 i::ScopedVector<char> code(1024);
18366 i::OS::SNPrintF(code, "function fib(n) {"
18367 " if (n <= 2) return 1;"
18368 " return fib(n-1) + fib(n-2);"
18371 Local<Value> value = CompileRun(code.start());
18372 CHECK(value->IsNumber());
18373 return static_cast<int>(value->NumberValue());
18376 class IsolateThread : public v8::internal::Thread {
18378 IsolateThread(v8::Isolate* isolate, int fib_limit)
18379 : Thread("IsolateThread"),
18381 fib_limit_(fib_limit),
18385 result_ = CalcFibonacci(isolate_, fib_limit_);
18388 int result() { return result_; }
18391 v8::Isolate* isolate_;
18397 TEST(MultipleIsolatesOnIndividualThreads) {
18398 v8::Isolate* isolate1 = v8::Isolate::New();
18399 v8::Isolate* isolate2 = v8::Isolate::New();
18401 IsolateThread thread1(isolate1, 21);
18402 IsolateThread thread2(isolate2, 12);
18404 // Compute some fibonacci numbers on 3 threads in 3 isolates.
18408 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
18409 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
18414 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
18415 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
18416 CHECK_EQ(result1, 10946);
18417 CHECK_EQ(result2, 144);
18418 CHECK_EQ(result1, thread1.result());
18419 CHECK_EQ(result2, thread2.result());
18421 isolate1->Dispose();
18422 isolate2->Dispose();
18426 TEST(IsolateDifferentContexts) {
18427 v8::Isolate* isolate = v8::Isolate::New();
18428 Local<v8::Context> context;
18430 v8::Isolate::Scope isolate_scope(isolate);
18431 v8::HandleScope handle_scope(isolate);
18432 context = v8::Context::New(isolate);
18433 v8::Context::Scope context_scope(context);
18434 Local<Value> v = CompileRun("2");
18435 CHECK(v->IsNumber());
18436 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
18439 v8::Isolate::Scope isolate_scope(isolate);
18440 v8::HandleScope handle_scope(isolate);
18441 context = v8::Context::New(isolate);
18442 v8::Context::Scope context_scope(context);
18443 Local<Value> v = CompileRun("22");
18444 CHECK(v->IsNumber());
18445 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
18449 class InitDefaultIsolateThread : public v8::internal::Thread {
18453 SetResourceConstraints,
18455 SetCounterFunction,
18456 SetCreateHistogramFunction,
18457 SetAddHistogramSampleFunction
18460 explicit InitDefaultIsolateThread(TestCase testCase)
18461 : Thread("InitDefaultIsolateThread"),
18462 testCase_(testCase),
18466 switch (testCase_) {
18468 v8::V8::IgnoreOutOfMemoryException();
18471 case SetResourceConstraints: {
18472 static const int K = 1024;
18473 v8::ResourceConstraints constraints;
18474 constraints.set_max_young_space_size(256 * K);
18475 constraints.set_max_old_space_size(4 * K * K);
18476 v8::SetResourceConstraints(&constraints);
18480 case SetFatalHandler:
18481 v8::V8::SetFatalErrorHandler(NULL);
18484 case SetCounterFunction:
18485 v8::V8::SetCounterFunction(NULL);
18488 case SetCreateHistogramFunction:
18489 v8::V8::SetCreateHistogramFunction(NULL);
18492 case SetAddHistogramSampleFunction:
18493 v8::V8::SetAddHistogramSampleFunction(NULL);
18499 bool result() { return result_; }
18502 TestCase testCase_;
18507 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
18508 InitDefaultIsolateThread thread(testCase);
18511 CHECK_EQ(thread.result(), true);
18515 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
18516 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
18520 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
18521 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
18525 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
18526 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
18530 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
18531 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
18535 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
18536 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
18540 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
18541 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
18545 TEST(StringCheckMultipleContexts) {
18547 "(function() { return \"a\".charAt(0); })()";
18550 // Run the code twice in the first context to initialize the call IC.
18551 LocalContext context1;
18552 v8::HandleScope scope(context1->GetIsolate());
18553 ExpectString(code, "a");
18554 ExpectString(code, "a");
18558 // Change the String.prototype in the second context and check
18559 // that the right function gets called.
18560 LocalContext context2;
18561 v8::HandleScope scope(context2->GetIsolate());
18562 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
18563 ExpectString(code, "not a");
18568 TEST(NumberCheckMultipleContexts) {
18570 "(function() { return (42).toString(); })()";
18573 // Run the code twice in the first context to initialize the call IC.
18574 LocalContext context1;
18575 v8::HandleScope scope(context1->GetIsolate());
18576 ExpectString(code, "42");
18577 ExpectString(code, "42");
18581 // Change the Number.prototype in the second context and check
18582 // that the right function gets called.
18583 LocalContext context2;
18584 v8::HandleScope scope(context2->GetIsolate());
18585 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
18586 ExpectString(code, "not 42");
18591 TEST(BooleanCheckMultipleContexts) {
18593 "(function() { return true.toString(); })()";
18596 // Run the code twice in the first context to initialize the call IC.
18597 LocalContext context1;
18598 v8::HandleScope scope(context1->GetIsolate());
18599 ExpectString(code, "true");
18600 ExpectString(code, "true");
18604 // Change the Boolean.prototype in the second context and check
18605 // that the right function gets called.
18606 LocalContext context2;
18607 v8::HandleScope scope(context2->GetIsolate());
18608 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
18609 ExpectString(code, "");
18614 TEST(DontDeleteCellLoadIC) {
18615 const char* function_code =
18616 "function readCell() { while (true) { return cell; } }";
18619 // Run the code twice in the first context to initialize the load
18620 // IC for a don't delete cell.
18621 LocalContext context1;
18622 v8::HandleScope scope(context1->GetIsolate());
18623 CompileRun("var cell = \"first\";");
18624 ExpectBoolean("delete cell", false);
18625 CompileRun(function_code);
18626 ExpectString("readCell()", "first");
18627 ExpectString("readCell()", "first");
18631 // Use a deletable cell in the second context.
18632 LocalContext context2;
18633 v8::HandleScope scope(context2->GetIsolate());
18634 CompileRun("cell = \"second\";");
18635 CompileRun(function_code);
18636 ExpectString("readCell()", "second");
18637 ExpectBoolean("delete cell", true);
18638 ExpectString("(function() {"
18640 " return readCell();"
18642 " return e.toString();"
18645 "ReferenceError: cell is not defined");
18646 CompileRun("cell = \"new_second\";");
18647 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
18648 ExpectString("readCell()", "new_second");
18649 ExpectString("readCell()", "new_second");
18654 TEST(DontDeleteCellLoadICForceDelete) {
18655 const char* function_code =
18656 "function readCell() { while (true) { return cell; } }";
18658 // Run the code twice to initialize the load IC for a don't delete
18660 LocalContext context;
18661 v8::HandleScope scope(context->GetIsolate());
18662 CompileRun("var cell = \"value\";");
18663 ExpectBoolean("delete cell", false);
18664 CompileRun(function_code);
18665 ExpectString("readCell()", "value");
18666 ExpectString("readCell()", "value");
18668 // Delete the cell using the API and check the inlined code works
18670 CHECK(context->Global()->ForceDelete(v8_str("cell")));
18671 ExpectString("(function() {"
18673 " return readCell();"
18675 " return e.toString();"
18678 "ReferenceError: cell is not defined");
18682 TEST(DontDeleteCellLoadICAPI) {
18683 const char* function_code =
18684 "function readCell() { while (true) { return cell; } }";
18686 // Run the code twice to initialize the load IC for a don't delete
18687 // cell created using the API.
18688 LocalContext context;
18689 v8::HandleScope scope(context->GetIsolate());
18690 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
18691 ExpectBoolean("delete cell", false);
18692 CompileRun(function_code);
18693 ExpectString("readCell()", "value");
18694 ExpectString("readCell()", "value");
18696 // Delete the cell using the API and check the inlined code works
18698 CHECK(context->Global()->ForceDelete(v8_str("cell")));
18699 ExpectString("(function() {"
18701 " return readCell();"
18703 " return e.toString();"
18706 "ReferenceError: cell is not defined");
18710 class Visitor42 : public v8::PersistentHandleVisitor {
18712 explicit Visitor42(v8::Persistent<v8::Object>* object)
18713 : counter_(0), object_(object) { }
18715 virtual void VisitPersistentHandle(Persistent<Value>* value,
18716 uint16_t class_id) {
18717 if (class_id != 42) return;
18718 CHECK_EQ(42, value->WrapperClassId());
18719 v8::Isolate* isolate = v8::Isolate::GetCurrent();
18720 v8::HandleScope handle_scope(isolate);
18721 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
18722 v8::Handle<v8::Value> object =
18723 v8::Local<v8::Object>::New(isolate, *object_);
18724 CHECK(handle->IsObject());
18725 CHECK_EQ(Handle<Object>::Cast(handle), object);
18730 v8::Persistent<v8::Object>* object_;
18734 TEST(PersistentHandleVisitor) {
18735 LocalContext context;
18736 v8::Isolate* isolate = context->GetIsolate();
18737 v8::HandleScope scope(isolate);
18738 v8::Persistent<v8::Object> object(isolate, v8::Object::New());
18739 CHECK_EQ(0, object.WrapperClassId());
18740 object.SetWrapperClassId(42);
18741 CHECK_EQ(42, object.WrapperClassId());
18743 Visitor42 visitor(&object);
18744 v8::V8::VisitHandlesWithClassIds(&visitor);
18745 CHECK_EQ(1, visitor.counter_);
18751 TEST(WrapperClassId) {
18752 LocalContext context;
18753 v8::Isolate* isolate = context->GetIsolate();
18754 v8::HandleScope scope(isolate);
18755 v8::Persistent<v8::Object> object(isolate, v8::Object::New());
18756 CHECK_EQ(0, object.WrapperClassId());
18757 object.SetWrapperClassId(65535);
18758 CHECK_EQ(65535, object.WrapperClassId());
18763 TEST(PersistentHandleInNewSpaceVisitor) {
18764 LocalContext context;
18765 v8::Isolate* isolate = context->GetIsolate();
18766 v8::HandleScope scope(isolate);
18767 v8::Persistent<v8::Object> object1(isolate, v8::Object::New());
18768 CHECK_EQ(0, object1.WrapperClassId());
18769 object1.SetWrapperClassId(42);
18770 CHECK_EQ(42, object1.WrapperClassId());
18772 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
18774 v8::Persistent<v8::Object> object2(isolate, v8::Object::New());
18775 CHECK_EQ(0, object2.WrapperClassId());
18776 object2.SetWrapperClassId(42);
18777 CHECK_EQ(42, object2.WrapperClassId());
18779 Visitor42 visitor(&object2);
18780 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
18781 CHECK_EQ(1, visitor.counter_);
18789 LocalContext context;
18790 v8::HandleScope scope(context->GetIsolate());
18792 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
18793 CHECK(re->IsRegExp());
18794 CHECK(re->GetSource()->Equals(v8_str("foo")));
18795 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18797 re = v8::RegExp::New(v8_str("bar"),
18798 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18799 v8::RegExp::kGlobal));
18800 CHECK(re->IsRegExp());
18801 CHECK(re->GetSource()->Equals(v8_str("bar")));
18802 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
18803 static_cast<int>(re->GetFlags()));
18805 re = v8::RegExp::New(v8_str("baz"),
18806 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18807 v8::RegExp::kMultiline));
18808 CHECK(re->IsRegExp());
18809 CHECK(re->GetSource()->Equals(v8_str("baz")));
18810 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18811 static_cast<int>(re->GetFlags()));
18813 re = CompileRun("/quux/").As<v8::RegExp>();
18814 CHECK(re->IsRegExp());
18815 CHECK(re->GetSource()->Equals(v8_str("quux")));
18816 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18818 re = CompileRun("/quux/gm").As<v8::RegExp>();
18819 CHECK(re->IsRegExp());
18820 CHECK(re->GetSource()->Equals(v8_str("quux")));
18821 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
18822 static_cast<int>(re->GetFlags()));
18824 // Override the RegExp constructor and check the API constructor
18826 CompileRun("RegExp = function() {}");
18828 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
18829 CHECK(re->IsRegExp());
18830 CHECK(re->GetSource()->Equals(v8_str("foobar")));
18831 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18833 re = v8::RegExp::New(v8_str("foobarbaz"),
18834 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18835 v8::RegExp::kMultiline));
18836 CHECK(re->IsRegExp());
18837 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
18838 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18839 static_cast<int>(re->GetFlags()));
18841 context->Global()->Set(v8_str("re"), re);
18842 ExpectTrue("re.test('FoobarbaZ')");
18844 // RegExps are objects on which you can set properties.
18845 re->Set(v8_str("property"), v8::Integer::New(32));
18846 v8::Handle<v8::Value> value(CompileRun("re.property"));
18847 CHECK_EQ(32, value->Int32Value());
18849 v8::TryCatch try_catch;
18850 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
18851 CHECK(re.IsEmpty());
18852 CHECK(try_catch.HasCaught());
18853 context->Global()->Set(v8_str("ex"), try_catch.Exception());
18854 ExpectTrue("ex instanceof SyntaxError");
18858 THREADED_TEST(Equals) {
18859 LocalContext localContext;
18860 v8::HandleScope handleScope(localContext->GetIsolate());
18862 v8::Handle<v8::Object> globalProxy = localContext->Global();
18863 v8::Handle<Value> global = globalProxy->GetPrototype();
18865 CHECK(global->StrictEquals(global));
18866 CHECK(!global->StrictEquals(globalProxy));
18867 CHECK(!globalProxy->StrictEquals(global));
18868 CHECK(globalProxy->StrictEquals(globalProxy));
18870 CHECK(global->Equals(global));
18871 CHECK(!global->Equals(globalProxy));
18872 CHECK(!globalProxy->Equals(global));
18873 CHECK(globalProxy->Equals(globalProxy));
18877 static void Getter(v8::Local<v8::String> property,
18878 const v8::PropertyCallbackInfo<v8::Value>& info ) {
18879 info.GetReturnValue().Set(v8_str("42!"));
18883 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
18884 v8::Handle<v8::Array> result = v8::Array::New();
18885 result->Set(0, v8_str("universalAnswer"));
18886 info.GetReturnValue().Set(result);
18890 TEST(NamedEnumeratorAndForIn) {
18891 LocalContext context;
18892 v8::HandleScope handle_scope(context->GetIsolate());
18893 v8::Context::Scope context_scope(context.local());
18895 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
18896 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
18897 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
18898 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
18899 "var result = []; for (var k in o) result.push(k); result"));
18900 CHECK_EQ(1, result->Length());
18901 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
18905 TEST(DefinePropertyPostDetach) {
18906 LocalContext context;
18907 v8::HandleScope scope(context->GetIsolate());
18908 v8::Handle<v8::Object> proxy = context->Global();
18909 v8::Handle<v8::Function> define_property =
18910 CompileRun("(function() {"
18911 " Object.defineProperty("
18914 " { configurable: true, enumerable: true, value: 3 });"
18915 "})").As<Function>();
18916 context->DetachGlobal();
18917 define_property->Call(proxy, 0, NULL);
18921 static void InstallContextId(v8::Handle<Context> context, int id) {
18922 Context::Scope scope(context);
18923 CompileRun("Object.prototype").As<Object>()->
18924 Set(v8_str("context_id"), v8::Integer::New(id));
18928 static void CheckContextId(v8::Handle<Object> object, int expected) {
18929 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
18933 THREADED_TEST(CreationContext) {
18934 HandleScope handle_scope(v8::Isolate::GetCurrent());
18935 Handle<Context> context1 = Context::New(v8::Isolate::GetCurrent());
18936 InstallContextId(context1, 1);
18937 Handle<Context> context2 = Context::New(v8::Isolate::GetCurrent());
18938 InstallContextId(context2, 2);
18939 Handle<Context> context3 = Context::New(v8::Isolate::GetCurrent());
18940 InstallContextId(context3, 3);
18942 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
18944 Local<Object> object1;
18945 Local<Function> func1;
18947 Context::Scope scope(context1);
18948 object1 = Object::New();
18949 func1 = tmpl->GetFunction();
18952 Local<Object> object2;
18953 Local<Function> func2;
18955 Context::Scope scope(context2);
18956 object2 = Object::New();
18957 func2 = tmpl->GetFunction();
18960 Local<Object> instance1;
18961 Local<Object> instance2;
18964 Context::Scope scope(context3);
18965 instance1 = func1->NewInstance();
18966 instance2 = func2->NewInstance();
18969 CHECK(object1->CreationContext() == context1);
18970 CheckContextId(object1, 1);
18971 CHECK(func1->CreationContext() == context1);
18972 CheckContextId(func1, 1);
18973 CHECK(instance1->CreationContext() == context1);
18974 CheckContextId(instance1, 1);
18975 CHECK(object2->CreationContext() == context2);
18976 CheckContextId(object2, 2);
18977 CHECK(func2->CreationContext() == context2);
18978 CheckContextId(func2, 2);
18979 CHECK(instance2->CreationContext() == context2);
18980 CheckContextId(instance2, 2);
18983 Context::Scope scope(context1);
18984 CHECK(object1->CreationContext() == context1);
18985 CheckContextId(object1, 1);
18986 CHECK(func1->CreationContext() == context1);
18987 CheckContextId(func1, 1);
18988 CHECK(instance1->CreationContext() == context1);
18989 CheckContextId(instance1, 1);
18990 CHECK(object2->CreationContext() == context2);
18991 CheckContextId(object2, 2);
18992 CHECK(func2->CreationContext() == context2);
18993 CheckContextId(func2, 2);
18994 CHECK(instance2->CreationContext() == context2);
18995 CheckContextId(instance2, 2);
18999 Context::Scope scope(context2);
19000 CHECK(object1->CreationContext() == context1);
19001 CheckContextId(object1, 1);
19002 CHECK(func1->CreationContext() == context1);
19003 CheckContextId(func1, 1);
19004 CHECK(instance1->CreationContext() == context1);
19005 CheckContextId(instance1, 1);
19006 CHECK(object2->CreationContext() == context2);
19007 CheckContextId(object2, 2);
19008 CHECK(func2->CreationContext() == context2);
19009 CheckContextId(func2, 2);
19010 CHECK(instance2->CreationContext() == context2);
19011 CheckContextId(instance2, 2);
19016 THREADED_TEST(CreationContextOfJsFunction) {
19017 HandleScope handle_scope(v8::Isolate::GetCurrent());
19018 Handle<Context> context = Context::New(v8::Isolate::GetCurrent());
19019 InstallContextId(context, 1);
19021 Local<Object> function;
19023 Context::Scope scope(context);
19024 function = CompileRun("function foo() {}; foo").As<Object>();
19027 CHECK(function->CreationContext() == context);
19028 CheckContextId(function, 1);
19032 void HasOwnPropertyIndexedPropertyGetter(
19034 const v8::PropertyCallbackInfo<v8::Value>& info) {
19035 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
19039 void HasOwnPropertyNamedPropertyGetter(
19040 Local<String> property,
19041 const v8::PropertyCallbackInfo<v8::Value>& info) {
19042 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
19046 void HasOwnPropertyIndexedPropertyQuery(
19047 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
19048 if (index == 42) info.GetReturnValue().Set(1);
19052 void HasOwnPropertyNamedPropertyQuery(
19053 Local<String> property,
19054 const v8::PropertyCallbackInfo<v8::Integer>& info) {
19055 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
19059 void HasOwnPropertyNamedPropertyQuery2(
19060 Local<String> property,
19061 const v8::PropertyCallbackInfo<v8::Integer>& info) {
19062 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
19066 void HasOwnPropertyAccessorGetter(
19067 Local<String> property,
19068 const v8::PropertyCallbackInfo<v8::Value>& info) {
19069 info.GetReturnValue().Set(v8_str("yes"));
19073 TEST(HasOwnProperty) {
19075 v8::HandleScope scope(env->GetIsolate());
19076 { // Check normal properties and defined getters.
19077 Handle<Value> value = CompileRun(
19080 " this.__defineGetter__('baz', function() { return 1; });"
19082 "function Bar() { "
19084 " this.__defineGetter__('bla', function() { return 2; });"
19086 "Bar.prototype = new Foo();"
19088 CHECK(value->IsObject());
19089 Handle<Object> object = value->ToObject();
19090 CHECK(object->Has(v8_str("foo")));
19091 CHECK(!object->HasOwnProperty(v8_str("foo")));
19092 CHECK(object->HasOwnProperty(v8_str("bar")));
19093 CHECK(object->Has(v8_str("baz")));
19094 CHECK(!object->HasOwnProperty(v8_str("baz")));
19095 CHECK(object->HasOwnProperty(v8_str("bla")));
19097 { // Check named getter interceptors.
19098 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19099 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
19100 Handle<Object> instance = templ->NewInstance();
19101 CHECK(!instance->HasOwnProperty(v8_str("42")));
19102 CHECK(instance->HasOwnProperty(v8_str("foo")));
19103 CHECK(!instance->HasOwnProperty(v8_str("bar")));
19105 { // Check indexed getter interceptors.
19106 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19107 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
19108 Handle<Object> instance = templ->NewInstance();
19109 CHECK(instance->HasOwnProperty(v8_str("42")));
19110 CHECK(!instance->HasOwnProperty(v8_str("43")));
19111 CHECK(!instance->HasOwnProperty(v8_str("foo")));
19113 { // Check named query interceptors.
19114 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19115 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
19116 Handle<Object> instance = templ->NewInstance();
19117 CHECK(instance->HasOwnProperty(v8_str("foo")));
19118 CHECK(!instance->HasOwnProperty(v8_str("bar")));
19120 { // Check indexed query interceptors.
19121 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19122 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
19123 Handle<Object> instance = templ->NewInstance();
19124 CHECK(instance->HasOwnProperty(v8_str("42")));
19125 CHECK(!instance->HasOwnProperty(v8_str("41")));
19127 { // Check callbacks.
19128 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19129 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
19130 Handle<Object> instance = templ->NewInstance();
19131 CHECK(instance->HasOwnProperty(v8_str("foo")));
19132 CHECK(!instance->HasOwnProperty(v8_str("bar")));
19134 { // Check that query wins on disagreement.
19135 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19136 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
19138 HasOwnPropertyNamedPropertyQuery2);
19139 Handle<Object> instance = templ->NewInstance();
19140 CHECK(!instance->HasOwnProperty(v8_str("foo")));
19141 CHECK(instance->HasOwnProperty(v8_str("bar")));
19146 TEST(IndexedInterceptorWithStringProto) {
19147 v8::HandleScope scope(v8::Isolate::GetCurrent());
19148 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19149 templ->SetIndexedPropertyHandler(NULL,
19151 HasOwnPropertyIndexedPropertyQuery);
19152 LocalContext context;
19153 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19154 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
19155 // These should be intercepted.
19156 CHECK(CompileRun("42 in obj")->BooleanValue());
19157 CHECK(CompileRun("'42' in obj")->BooleanValue());
19158 // These should fall through to the String prototype.
19159 CHECK(CompileRun("0 in obj")->BooleanValue());
19160 CHECK(CompileRun("'0' in obj")->BooleanValue());
19161 // And these should both fail.
19162 CHECK(!CompileRun("32 in obj")->BooleanValue());
19163 CHECK(!CompileRun("'32' in obj")->BooleanValue());
19167 void CheckCodeGenerationAllowed() {
19168 Handle<Value> result = CompileRun("eval('42')");
19169 CHECK_EQ(42, result->Int32Value());
19170 result = CompileRun("(function(e) { return e('42'); })(eval)");
19171 CHECK_EQ(42, result->Int32Value());
19172 result = CompileRun("var f = new Function('return 42'); f()");
19173 CHECK_EQ(42, result->Int32Value());
19177 void CheckCodeGenerationDisallowed() {
19178 TryCatch try_catch;
19180 Handle<Value> result = CompileRun("eval('42')");
19181 CHECK(result.IsEmpty());
19182 CHECK(try_catch.HasCaught());
19185 result = CompileRun("(function(e) { return e('42'); })(eval)");
19186 CHECK(result.IsEmpty());
19187 CHECK(try_catch.HasCaught());
19190 result = CompileRun("var f = new Function('return 42'); f()");
19191 CHECK(result.IsEmpty());
19192 CHECK(try_catch.HasCaught());
19196 bool CodeGenerationAllowed(Local<Context> context) {
19197 ApiTestFuzzer::Fuzz();
19202 bool CodeGenerationDisallowed(Local<Context> context) {
19203 ApiTestFuzzer::Fuzz();
19208 THREADED_TEST(AllowCodeGenFromStrings) {
19209 LocalContext context;
19210 v8::HandleScope scope(context->GetIsolate());
19212 // eval and the Function constructor allowed by default.
19213 CHECK(context->IsCodeGenerationFromStringsAllowed());
19214 CheckCodeGenerationAllowed();
19216 // Disallow eval and the Function constructor.
19217 context->AllowCodeGenerationFromStrings(false);
19218 CHECK(!context->IsCodeGenerationFromStringsAllowed());
19219 CheckCodeGenerationDisallowed();
19222 context->AllowCodeGenerationFromStrings(true);
19223 CheckCodeGenerationAllowed();
19225 // Disallow but setting a global callback that will allow the calls.
19226 context->AllowCodeGenerationFromStrings(false);
19227 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
19228 CHECK(!context->IsCodeGenerationFromStringsAllowed());
19229 CheckCodeGenerationAllowed();
19231 // Set a callback that disallows the code generation.
19232 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
19233 CHECK(!context->IsCodeGenerationFromStringsAllowed());
19234 CheckCodeGenerationDisallowed();
19238 TEST(SetErrorMessageForCodeGenFromStrings) {
19239 LocalContext context;
19240 v8::HandleScope scope(context->GetIsolate());
19241 TryCatch try_catch;
19243 Handle<String> message = v8_str("Message") ;
19244 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
19245 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
19246 context->AllowCodeGenerationFromStrings(false);
19247 context->SetErrorMessageForCodeGenerationFromStrings(message);
19248 Handle<Value> result = CompileRun("eval('42')");
19249 CHECK(result.IsEmpty());
19250 CHECK(try_catch.HasCaught());
19251 Handle<String> actual_message = try_catch.Message()->Get();
19252 CHECK(expected_message->Equals(actual_message));
19256 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
19260 THREADED_TEST(CallAPIFunctionOnNonObject) {
19261 LocalContext context;
19262 v8::HandleScope scope(context->GetIsolate());
19263 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
19264 Handle<Function> function = templ->GetFunction();
19265 context->Global()->Set(v8_str("f"), function);
19266 TryCatch try_catch;
19267 CompileRun("f.call(2)");
19271 // Regression test for issue 1470.
19272 THREADED_TEST(ReadOnlyIndexedProperties) {
19273 v8::HandleScope scope(v8::Isolate::GetCurrent());
19274 Local<ObjectTemplate> templ = ObjectTemplate::New();
19276 LocalContext context;
19277 Local<v8::Object> obj = templ->NewInstance();
19278 context->Global()->Set(v8_str("obj"), obj);
19279 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
19280 obj->Set(v8_str("1"), v8_str("foobar"));
19281 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
19282 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
19283 obj->Set(v8_num(2), v8_str("foobar"));
19284 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
19286 // Test non-smi case.
19287 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
19288 obj->Set(v8_str("2000000000"), v8_str("foobar"));
19289 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
19293 THREADED_TEST(Regress1516) {
19294 LocalContext context;
19295 v8::HandleScope scope(context->GetIsolate());
19297 { v8::HandleScope temp_scope(context->GetIsolate());
19298 CompileRun("({'a': 0})");
19302 { i::MapCache* map_cache =
19303 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
19304 elements = map_cache->NumberOfElements();
19305 CHECK_LE(1, elements);
19308 i::Isolate::Current()->heap()->CollectAllGarbage(
19309 i::Heap::kAbortIncrementalMarkingMask);
19310 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
19311 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
19312 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
19313 CHECK_GT(elements, map_cache->NumberOfElements());
19319 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
19321 v8::AccessType type,
19322 Local<Value> data) {
19323 // Only block read access to __proto__.
19324 if (type == v8::ACCESS_GET &&
19325 name->IsString() &&
19326 name->ToString()->Length() == 9 &&
19327 name->ToString()->Utf8Length() == 9) {
19329 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
19330 return strncmp(buffer, "__proto__", 9) != 0;
19337 THREADED_TEST(Regress93759) {
19338 v8::Isolate* isolate = v8::Isolate::GetCurrent();
19339 HandleScope scope(isolate);
19341 // Template for object with security check.
19342 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
19343 // We don't do indexing, so any callback can be used for that.
19344 no_proto_template->SetAccessCheckCallbacks(
19345 BlockProtoNamedSecurityTestCallback,
19346 IndexedSecurityTestCallback);
19348 // Templates for objects with hidden prototypes and possibly security check.
19349 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
19350 hidden_proto_template->SetHiddenPrototype(true);
19352 Local<FunctionTemplate> protected_hidden_proto_template =
19353 v8::FunctionTemplate::New();
19354 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
19355 BlockProtoNamedSecurityTestCallback,
19356 IndexedSecurityTestCallback);
19357 protected_hidden_proto_template->SetHiddenPrototype(true);
19359 // Context for "foreign" objects used in test.
19360 Local<Context> context = v8::Context::New(isolate);
19363 // Plain object, no security check.
19364 Local<Object> simple_object = Object::New();
19366 // Object with explicit security check.
19367 Local<Object> protected_object =
19368 no_proto_template->NewInstance();
19370 // JSGlobalProxy object, always have security check.
19371 Local<Object> proxy_object =
19374 // Global object, the prototype of proxy_object. No security checks.
19375 Local<Object> global_object =
19376 proxy_object->GetPrototype()->ToObject();
19378 // Hidden prototype without security check.
19379 Local<Object> hidden_prototype =
19380 hidden_proto_template->GetFunction()->NewInstance();
19381 Local<Object> object_with_hidden =
19383 object_with_hidden->SetPrototype(hidden_prototype);
19385 // Hidden prototype with security check on the hidden prototype.
19386 Local<Object> protected_hidden_prototype =
19387 protected_hidden_proto_template->GetFunction()->NewInstance();
19388 Local<Object> object_with_protected_hidden =
19390 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
19394 // Template for object for second context. Values to test are put on it as
19396 Local<ObjectTemplate> global_template = ObjectTemplate::New();
19397 global_template->Set(v8_str("simple"), simple_object);
19398 global_template->Set(v8_str("protected"), protected_object);
19399 global_template->Set(v8_str("global"), global_object);
19400 global_template->Set(v8_str("proxy"), proxy_object);
19401 global_template->Set(v8_str("hidden"), object_with_hidden);
19402 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
19404 LocalContext context2(NULL, global_template);
19406 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
19407 CHECK(result1->Equals(simple_object->GetPrototype()));
19409 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
19410 CHECK(result2->Equals(Undefined()));
19412 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
19413 CHECK(result3->Equals(global_object->GetPrototype()));
19415 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
19416 CHECK(result4->Equals(Undefined()));
19418 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
19419 CHECK(result5->Equals(
19420 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
19422 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
19423 CHECK(result6->Equals(Undefined()));
19427 THREADED_TEST(Regress125988) {
19428 v8::HandleScope scope(v8::Isolate::GetCurrent());
19429 Handle<FunctionTemplate> intercept = FunctionTemplate::New();
19430 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
19432 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
19433 CompileRun("var a = new Object();"
19434 "var b = new Intercept();"
19435 "var c = new Object();"
19439 "for (var i = 0; i < 3; i++) c.x;");
19440 ExpectBoolean("c.hasOwnProperty('x')", false);
19441 ExpectInt32("c.x", 23);
19442 CompileRun("a.y = 42;"
19443 "for (var i = 0; i < 3; i++) c.x;");
19444 ExpectBoolean("c.hasOwnProperty('x')", false);
19445 ExpectInt32("c.x", 23);
19446 ExpectBoolean("c.hasOwnProperty('y')", false);
19447 ExpectInt32("c.y", 42);
19451 static void TestReceiver(Local<Value> expected_result,
19452 Local<Value> expected_receiver,
19453 const char* code) {
19454 Local<Value> result = CompileRun(code);
19455 CHECK(result->IsObject());
19456 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
19457 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
19461 THREADED_TEST(ForeignFunctionReceiver) {
19462 v8::Isolate* isolate = v8::Isolate::GetCurrent();
19463 HandleScope scope(isolate);
19465 // Create two contexts with different "id" properties ('i' and 'o').
19466 // Call a function both from its own context and from a the foreign
19467 // context, and see what "this" is bound to (returning both "this"
19468 // and "this.id" for comparison).
19470 Local<Context> foreign_context = v8::Context::New(isolate);
19471 foreign_context->Enter();
19472 Local<Value> foreign_function =
19473 CompileRun("function func() { return { 0: this.id, "
19475 " toString: function() { "
19482 CHECK(foreign_function->IsFunction());
19483 foreign_context->Exit();
19485 LocalContext context;
19487 Local<String> password = v8_str("Password");
19488 // Don't get hit by security checks when accessing foreign_context's
19489 // global receiver (aka. global proxy).
19490 context->SetSecurityToken(password);
19491 foreign_context->SetSecurityToken(password);
19493 Local<String> i = v8_str("i");
19494 Local<String> o = v8_str("o");
19495 Local<String> id = v8_str("id");
19497 CompileRun("function ownfunc() { return { 0: this.id, "
19499 " toString: function() { "
19506 context->Global()->Set(v8_str("func"), foreign_function);
19508 // Sanity check the contexts.
19509 CHECK(i->Equals(foreign_context->Global()->Get(id)));
19510 CHECK(o->Equals(context->Global()->Get(id)));
19512 // Checking local function's receiver.
19513 // Calling function using its call/apply methods.
19514 TestReceiver(o, context->Global(), "ownfunc.call()");
19515 TestReceiver(o, context->Global(), "ownfunc.apply()");
19516 // Making calls through built-in functions.
19517 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
19518 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
19519 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
19520 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
19521 // Calling with environment record as base.
19522 TestReceiver(o, context->Global(), "ownfunc()");
19523 // Calling with no base.
19524 TestReceiver(o, context->Global(), "(1,ownfunc)()");
19526 // Checking foreign function return value.
19527 // Calling function using its call/apply methods.
19528 TestReceiver(i, foreign_context->Global(), "func.call()");
19529 TestReceiver(i, foreign_context->Global(), "func.apply()");
19530 // Calling function using another context's call/apply methods.
19531 TestReceiver(i, foreign_context->Global(),
19532 "Function.prototype.call.call(func)");
19533 TestReceiver(i, foreign_context->Global(),
19534 "Function.prototype.call.apply(func)");
19535 TestReceiver(i, foreign_context->Global(),
19536 "Function.prototype.apply.call(func)");
19537 TestReceiver(i, foreign_context->Global(),
19538 "Function.prototype.apply.apply(func)");
19539 // Making calls through built-in functions.
19540 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
19541 // ToString(func()) is func()[0], i.e., the returned this.id.
19542 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
19543 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
19544 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
19546 // TODO(1547): Make the following also return "i".
19547 // Calling with environment record as base.
19548 TestReceiver(o, context->Global(), "func()");
19549 // Calling with no base.
19550 TestReceiver(o, context->Global(), "(1,func)()");
19554 uint8_t callback_fired = 0;
19557 void CallCompletedCallback1() {
19558 i::OS::Print("Firing callback 1.\n");
19559 callback_fired ^= 1; // Toggle first bit.
19563 void CallCompletedCallback2() {
19564 i::OS::Print("Firing callback 2.\n");
19565 callback_fired ^= 2; // Toggle second bit.
19569 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
19570 int32_t level = args[0]->Int32Value();
19573 i::OS::Print("Entering recursion level %d.\n", level);
19575 i::Vector<char> script_vector(script, sizeof(script));
19576 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
19577 CompileRun(script_vector.start());
19578 i::OS::Print("Leaving recursion level %d.\n", level);
19579 CHECK_EQ(0, callback_fired);
19581 i::OS::Print("Recursion ends.\n");
19582 CHECK_EQ(0, callback_fired);
19587 TEST(CallCompletedCallback) {
19589 v8::HandleScope scope(env->GetIsolate());
19590 v8::Handle<v8::FunctionTemplate> recursive_runtime =
19591 v8::FunctionTemplate::New(RecursiveCall);
19592 env->Global()->Set(v8_str("recursion"),
19593 recursive_runtime->GetFunction());
19594 // Adding the same callback a second time has no effect.
19595 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
19596 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
19597 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
19598 i::OS::Print("--- Script (1) ---\n");
19599 Local<Script> script =
19600 v8::Script::Compile(v8::String::New("recursion(0)"));
19602 CHECK_EQ(3, callback_fired);
19604 i::OS::Print("\n--- Script (2) ---\n");
19605 callback_fired = 0;
19606 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
19608 CHECK_EQ(2, callback_fired);
19610 i::OS::Print("\n--- Function ---\n");
19611 callback_fired = 0;
19612 Local<Function> recursive_function =
19613 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
19614 v8::Handle<Value> args[] = { v8_num(0) };
19615 recursive_function->Call(env->Global(), 1, args);
19616 CHECK_EQ(2, callback_fired);
19620 void CallCompletedCallbackNoException() {
19621 v8::HandleScope scope(v8::Isolate::GetCurrent());
19622 CompileRun("1+1;");
19626 void CallCompletedCallbackException() {
19627 v8::HandleScope scope(v8::Isolate::GetCurrent());
19628 CompileRun("throw 'second exception';");
19632 TEST(CallCompletedCallbackOneException) {
19634 v8::HandleScope scope(env->GetIsolate());
19635 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
19636 CompileRun("throw 'exception';");
19640 TEST(CallCompletedCallbackTwoExceptions) {
19642 v8::HandleScope scope(env->GetIsolate());
19643 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
19644 CompileRun("throw 'first exception';");
19648 static int probes_counter = 0;
19649 static int misses_counter = 0;
19650 static int updates_counter = 0;
19653 static int* LookupCounter(const char* name) {
19654 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
19655 return &probes_counter;
19656 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
19657 return &misses_counter;
19658 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
19659 return &updates_counter;
19665 static const char* kMegamorphicTestProgram =
19666 "function ClassA() { };"
19667 "function ClassB() { };"
19668 "ClassA.prototype.foo = function() { };"
19669 "ClassB.prototype.foo = function() { };"
19670 "function fooify(obj) { obj.foo(); };"
19671 "var a = new ClassA();"
19672 "var b = new ClassB();"
19673 "for (var i = 0; i < 10000; i++) {"
19679 static void StubCacheHelper(bool primary) {
19680 V8::SetCounterFunction(LookupCounter);
19681 USE(kMegamorphicTestProgram);
19683 i::FLAG_native_code_counters = true;
19685 i::FLAG_test_primary_stub_cache = true;
19687 i::FLAG_test_secondary_stub_cache = true;
19689 i::FLAG_crankshaft = false;
19691 v8::HandleScope scope(env->GetIsolate());
19692 int initial_probes = probes_counter;
19693 int initial_misses = misses_counter;
19694 int initial_updates = updates_counter;
19695 CompileRun(kMegamorphicTestProgram);
19696 int probes = probes_counter - initial_probes;
19697 int misses = misses_counter - initial_misses;
19698 int updates = updates_counter - initial_updates;
19699 CHECK_LT(updates, 10);
19700 CHECK_LT(misses, 10);
19701 CHECK_GE(probes, 10000);
19706 TEST(SecondaryStubCache) {
19707 StubCacheHelper(true);
19711 TEST(PrimaryStubCache) {
19712 StubCacheHelper(false);
19716 TEST(StaticGetters) {
19717 LocalContext context;
19718 i::Factory* factory = i::Isolate::Current()->factory();
19719 v8::Isolate* isolate = v8::Isolate::GetCurrent();
19720 v8::HandleScope scope(isolate);
19721 i::Handle<i::Object> undefined_value = factory->undefined_value();
19722 CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
19723 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
19724 i::Handle<i::Object> null_value = factory->null_value();
19725 CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
19726 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
19727 i::Handle<i::Object> true_value = factory->true_value();
19728 CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
19729 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
19730 i::Handle<i::Object> false_value = factory->false_value();
19731 CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
19732 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
19736 TEST(IsolateEmbedderData) {
19737 v8::Isolate* isolate = v8::Isolate::GetCurrent();
19738 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
19739 CHECK_EQ(NULL, isolate->GetData());
19740 CHECK_EQ(NULL, i_isolate->GetData());
19741 static void* data1 = reinterpret_cast<void*>(0xacce55ed);
19742 isolate->SetData(data1);
19743 CHECK_EQ(data1, isolate->GetData());
19744 CHECK_EQ(data1, i_isolate->GetData());
19745 static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
19746 i_isolate->SetData(data2);
19747 CHECK_EQ(data2, isolate->GetData());
19748 CHECK_EQ(data2, i_isolate->GetData());
19749 i_isolate->TearDown();
19750 CHECK_EQ(data2, isolate->GetData());
19751 CHECK_EQ(data2, i_isolate->GetData());
19755 TEST(StringEmpty) {
19756 LocalContext context;
19757 i::Factory* factory = i::Isolate::Current()->factory();
19758 v8::Isolate* isolate = v8::Isolate::GetCurrent();
19759 v8::HandleScope scope(isolate);
19760 i::Handle<i::Object> empty_string = factory->empty_string();
19761 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
19762 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
19766 static int instance_checked_getter_count = 0;
19767 static void InstanceCheckedGetter(
19768 Local<String> name,
19769 const v8::PropertyCallbackInfo<v8::Value>& info) {
19770 CHECK_EQ(name, v8_str("foo"));
19771 instance_checked_getter_count++;
19772 info.GetReturnValue().Set(v8_num(11));
19776 static int instance_checked_setter_count = 0;
19777 static void InstanceCheckedSetter(Local<String> name,
19778 Local<Value> value,
19779 const v8::PropertyCallbackInfo<void>& info) {
19780 CHECK_EQ(name, v8_str("foo"));
19781 CHECK_EQ(value, v8_num(23));
19782 instance_checked_setter_count++;
19786 static void CheckInstanceCheckedResult(int getters,
19788 bool expects_callbacks,
19789 TryCatch* try_catch) {
19790 if (expects_callbacks) {
19791 CHECK(!try_catch->HasCaught());
19792 CHECK_EQ(getters, instance_checked_getter_count);
19793 CHECK_EQ(setters, instance_checked_setter_count);
19795 CHECK(try_catch->HasCaught());
19796 CHECK_EQ(0, instance_checked_getter_count);
19797 CHECK_EQ(0, instance_checked_setter_count);
19799 try_catch->Reset();
19803 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
19804 instance_checked_getter_count = 0;
19805 instance_checked_setter_count = 0;
19806 TryCatch try_catch;
19808 // Test path through generic runtime code.
19809 CompileRun("obj.foo");
19810 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
19811 CompileRun("obj.foo = 23");
19812 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
19814 // Test path through generated LoadIC and StoredIC.
19815 CompileRun("function test_get(o) { o.foo; }"
19817 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
19818 CompileRun("test_get(obj);");
19819 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
19820 CompileRun("test_get(obj);");
19821 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
19822 CompileRun("function test_set(o) { o.foo = 23; }"
19824 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
19825 CompileRun("test_set(obj);");
19826 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
19827 CompileRun("test_set(obj);");
19828 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
19830 // Test path through optimized code.
19831 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
19833 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
19834 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
19836 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
19838 // Cleanup so that closures start out fresh in next check.
19839 CompileRun("%DeoptimizeFunction(test_get);"
19840 "%ClearFunctionTypeFeedback(test_get);"
19841 "%DeoptimizeFunction(test_set);"
19842 "%ClearFunctionTypeFeedback(test_set);");
19846 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
19847 v8::internal::FLAG_allow_natives_syntax = true;
19848 LocalContext context;
19849 v8::HandleScope scope(context->GetIsolate());
19851 Local<FunctionTemplate> templ = FunctionTemplate::New();
19852 Local<ObjectTemplate> inst = templ->InstanceTemplate();
19853 inst->SetAccessor(v8_str("foo"),
19854 InstanceCheckedGetter, InstanceCheckedSetter,
19858 v8::AccessorSignature::New(templ));
19859 context->Global()->Set(v8_str("f"), templ->GetFunction());
19861 printf("Testing positive ...\n");
19862 CompileRun("var obj = new f();");
19863 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19864 CheckInstanceCheckedAccessors(true);
19866 printf("Testing negative ...\n");
19867 CompileRun("var obj = {};"
19868 "obj.__proto__ = new f();");
19869 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19870 CheckInstanceCheckedAccessors(false);
19874 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
19875 v8::internal::FLAG_allow_natives_syntax = true;
19876 LocalContext context;
19877 v8::HandleScope scope(context->GetIsolate());
19879 Local<FunctionTemplate> templ = FunctionTemplate::New();
19880 Local<ObjectTemplate> inst = templ->InstanceTemplate();
19881 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
19882 inst->SetAccessor(v8_str("foo"),
19883 InstanceCheckedGetter, InstanceCheckedSetter,
19887 v8::AccessorSignature::New(templ));
19888 context->Global()->Set(v8_str("f"), templ->GetFunction());
19890 printf("Testing positive ...\n");
19891 CompileRun("var obj = new f();");
19892 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19893 CheckInstanceCheckedAccessors(true);
19895 printf("Testing negative ...\n");
19896 CompileRun("var obj = {};"
19897 "obj.__proto__ = new f();");
19898 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19899 CheckInstanceCheckedAccessors(false);
19903 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
19904 v8::internal::FLAG_allow_natives_syntax = true;
19905 LocalContext context;
19906 v8::HandleScope scope(context->GetIsolate());
19908 Local<FunctionTemplate> templ = FunctionTemplate::New();
19909 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
19910 proto->SetAccessor(v8_str("foo"),
19911 InstanceCheckedGetter, InstanceCheckedSetter,
19915 v8::AccessorSignature::New(templ));
19916 context->Global()->Set(v8_str("f"), templ->GetFunction());
19918 printf("Testing positive ...\n");
19919 CompileRun("var obj = new f();");
19920 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19921 CheckInstanceCheckedAccessors(true);
19923 printf("Testing negative ...\n");
19924 CompileRun("var obj = {};"
19925 "obj.__proto__ = new f();");
19926 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19927 CheckInstanceCheckedAccessors(false);
19929 printf("Testing positive with modified prototype chain ...\n");
19930 CompileRun("var obj = new f();"
19932 "pro.__proto__ = obj.__proto__;"
19933 "obj.__proto__ = pro;");
19934 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19935 CheckInstanceCheckedAccessors(true);
19939 TEST(TryFinallyMessage) {
19940 LocalContext context;
19941 v8::HandleScope scope(context->GetIsolate());
19943 // Test that the original error message is not lost if there is a
19944 // recursive call into Javascript is done in the finally block, e.g. to
19945 // initialize an IC. (crbug.com/129171)
19946 TryCatch try_catch;
19947 const char* trigger_ic =
19949 " throw new Error('test'); \n"
19952 " x++; \n" // Trigger an IC initialization here.
19954 CompileRun(trigger_ic);
19955 CHECK(try_catch.HasCaught());
19956 Local<Message> message = try_catch.Message();
19957 CHECK(!message.IsEmpty());
19958 CHECK_EQ(2, message->GetLineNumber());
19962 // Test that the original exception message is indeed overwritten if
19963 // a new error is thrown in the finally block.
19964 TryCatch try_catch;
19965 const char* throw_again =
19967 " throw new Error('test'); \n"
19971 " throw new Error('again'); \n" // This is the new uncaught error.
19973 CompileRun(throw_again);
19974 CHECK(try_catch.HasCaught());
19975 Local<Message> message = try_catch.Message();
19976 CHECK(!message.IsEmpty());
19977 CHECK_EQ(6, message->GetLineNumber());
19982 static void Helper137002(bool do_store,
19984 bool remove_accessor,
19985 bool interceptor) {
19986 LocalContext context;
19987 Local<ObjectTemplate> templ = ObjectTemplate::New();
19989 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
19991 templ->SetAccessor(v8_str("foo"),
19992 GetterWhichReturns42,
19993 SetterWhichSetsYOnThisTo23);
19995 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19997 // Turn monomorphic on slow object with native accessor, then turn
19998 // polymorphic, finally optimize to create negative lookup and fail.
19999 CompileRun(do_store ?
20000 "function f(x) { x.foo = void 0; }" :
20001 "function f(x) { return x.foo; }");
20002 CompileRun("obj.y = void 0;");
20003 if (!interceptor) {
20004 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
20006 CompileRun("obj.__proto__ = null;"
20007 "f(obj); f(obj); f(obj);");
20009 CompileRun("f({});");
20011 CompileRun("obj.y = void 0;"
20012 "%OptimizeFunctionOnNextCall(f);");
20013 if (remove_accessor) {
20014 CompileRun("delete obj.foo;");
20016 CompileRun("var result = f(obj);");
20018 CompileRun("result = obj.y;");
20020 if (remove_accessor && !interceptor) {
20021 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
20023 CHECK_EQ(do_store ? 23 : 42,
20024 context->Global()->Get(v8_str("result"))->Int32Value());
20029 THREADED_TEST(Regress137002a) {
20030 i::FLAG_allow_natives_syntax = true;
20031 i::FLAG_compilation_cache = false;
20032 v8::HandleScope scope(v8::Isolate::GetCurrent());
20033 for (int i = 0; i < 16; i++) {
20034 Helper137002(i & 8, i & 4, i & 2, i & 1);
20039 THREADED_TEST(Regress137002b) {
20040 i::FLAG_allow_natives_syntax = true;
20041 LocalContext context;
20042 v8::HandleScope scope(context->GetIsolate());
20043 Local<ObjectTemplate> templ = ObjectTemplate::New();
20044 templ->SetAccessor(v8_str("foo"),
20045 GetterWhichReturns42,
20046 SetterWhichSetsYOnThisTo23);
20047 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20049 // Turn monomorphic on slow object with native accessor, then just
20050 // delete the property and fail.
20051 CompileRun("function load(x) { return x.foo; }"
20052 "function store(x) { x.foo = void 0; }"
20053 "function keyed_load(x, key) { return x[key]; }"
20054 // Second version of function has a different source (add void 0)
20055 // so that it does not share code with the first version. This
20056 // ensures that the ICs are monomorphic.
20057 "function load2(x) { void 0; return x.foo; }"
20058 "function store2(x) { void 0; x.foo = void 0; }"
20059 "function keyed_load2(x, key) { void 0; return x[key]; }"
20062 "obj.__proto__ = null;"
20064 "subobj.y = void 0;"
20065 "subobj.__proto__ = obj;"
20066 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
20068 // Make the ICs monomorphic.
20069 "load(obj); load(obj);"
20070 "load2(subobj); load2(subobj);"
20071 "store(obj); store(obj);"
20072 "store2(subobj); store2(subobj);"
20073 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
20074 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
20076 // Actually test the shiny new ICs and better not crash. This
20077 // serves as a regression test for issue 142088 as well.
20082 "keyed_load(obj, 'foo');"
20083 "keyed_load2(subobj, 'foo');"
20085 // Delete the accessor. It better not be called any more now.
20088 "subobj.y = void 0;"
20090 "var load_result = load(obj);"
20091 "var load_result2 = load2(subobj);"
20092 "var keyed_load_result = keyed_load(obj, 'foo');"
20093 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
20096 "var y_from_obj = obj.y;"
20097 "var y_from_subobj = subobj.y;");
20098 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
20099 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
20100 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
20101 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
20102 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
20103 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
20107 THREADED_TEST(Regress142088) {
20108 i::FLAG_allow_natives_syntax = true;
20109 LocalContext context;
20110 v8::HandleScope scope(context->GetIsolate());
20111 Local<ObjectTemplate> templ = ObjectTemplate::New();
20112 templ->SetAccessor(v8_str("foo"),
20113 GetterWhichReturns42,
20114 SetterWhichSetsYOnThisTo23);
20115 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20117 CompileRun("function load(x) { return x.foo; }"
20118 "var o = Object.create(obj);"
20119 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
20120 "load(o); load(o); load(o); load(o);");
20124 THREADED_TEST(Regress137496) {
20125 i::FLAG_expose_gc = true;
20126 LocalContext context;
20127 v8::HandleScope scope(context->GetIsolate());
20129 // Compile a try-finally clause where the finally block causes a GC
20130 // while there still is a message pending for external reporting.
20131 TryCatch try_catch;
20132 try_catch.SetVerbose(true);
20133 CompileRun("try { throw new Error(); } finally { gc(); }");
20134 CHECK(try_catch.HasCaught());
20138 THREADED_TEST(Regress149912) {
20139 LocalContext context;
20140 v8::HandleScope scope(context->GetIsolate());
20141 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20142 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20143 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
20144 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
20148 THREADED_TEST(Regress157124) {
20149 LocalContext context;
20150 v8::HandleScope scope(context->GetIsolate());
20151 Local<ObjectTemplate> templ = ObjectTemplate::New();
20152 Local<Object> obj = templ->NewInstance();
20153 obj->GetIdentityHash();
20154 obj->DeleteHiddenValue(v8_str("Bug"));
20158 THREADED_TEST(Regress2535) {
20159 i::FLAG_harmony_collections = true;
20160 LocalContext context;
20161 v8::HandleScope scope(context->GetIsolate());
20162 Local<Value> set_value = CompileRun("new Set();");
20163 Local<Object> set_object(Local<Object>::Cast(set_value));
20164 CHECK_EQ(0, set_object->InternalFieldCount());
20165 Local<Value> map_value = CompileRun("new Map();");
20166 Local<Object> map_object(Local<Object>::Cast(map_value));
20167 CHECK_EQ(0, map_object->InternalFieldCount());
20171 THREADED_TEST(Regress2746) {
20172 LocalContext context;
20173 v8::HandleScope scope(context->GetIsolate());
20174 Local<Object> obj = Object::New();
20175 Local<String> key = String::New("key");
20176 obj->SetHiddenValue(key, v8::Undefined());
20177 Local<Value> value = obj->GetHiddenValue(key);
20178 CHECK(!value.IsEmpty());
20179 CHECK(value->IsUndefined());
20183 THREADED_TEST(Regress260106) {
20184 LocalContext context;
20185 v8::HandleScope scope(context->GetIsolate());
20186 Local<FunctionTemplate> templ = FunctionTemplate::New(DummyCallHandler);
20187 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
20188 Local<Function> function = templ->GetFunction();
20189 CHECK(!function.IsEmpty());
20190 CHECK(function->IsFunction());
20194 THREADED_TEST(JSONParseObject) {
20195 LocalContext context;
20196 HandleScope scope(context->GetIsolate());
20197 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
20198 Handle<Object> global = context->Global();
20199 global->Set(v8_str("obj"), obj);
20200 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
20204 THREADED_TEST(JSONParseNumber) {
20205 LocalContext context;
20206 HandleScope scope(context->GetIsolate());
20207 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
20208 Handle<Object> global = context->Global();
20209 global->Set(v8_str("obj"), obj);
20210 ExpectString("JSON.stringify(obj)", "42");
20215 class ThreadInterruptTest {
20217 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
20218 ~ThreadInterruptTest() {}
20221 InterruptThread i_thread(this);
20225 CHECK_EQ(kExpectedValue, sem_value_);
20229 static const int kExpectedValue = 1;
20231 class InterruptThread : public i::Thread {
20233 explicit InterruptThread(ThreadInterruptTest* test)
20234 : Thread("InterruptThread"), test_(test) {}
20236 virtual void Run() {
20237 struct sigaction action;
20239 // Ensure that we'll enter waiting condition
20242 // Setup signal handler
20243 memset(&action, 0, sizeof(action));
20244 action.sa_handler = SignalHandler;
20245 sigaction(SIGCHLD, &action, NULL);
20248 kill(getpid(), SIGCHLD);
20250 // Ensure that if wait has returned because of error
20253 // Set value and signal semaphore
20254 test_->sem_value_ = 1;
20255 test_->sem_.Signal();
20258 static void SignalHandler(int signal) {
20262 ThreadInterruptTest* test_;
20266 volatile int sem_value_;
20270 THREADED_TEST(SemaphoreInterruption) {
20271 ThreadInterruptTest().RunTest();
20275 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
20277 v8::AccessType type,
20278 Local<Value> data) {
20279 i::PrintF("Named access blocked.\n");
20284 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
20286 v8::AccessType type,
20287 Local<Value> data) {
20288 i::PrintF("Indexed access blocked.\n");
20293 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
20298 TEST(JSONStringifyAccessCheck) {
20299 v8::V8::Initialize();
20300 v8::HandleScope scope(v8::Isolate::GetCurrent());
20302 // Create an ObjectTemplate for global objects and install access
20303 // check callbacks that will block access.
20304 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
20305 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
20306 IndexAccessAlwaysBlocked);
20308 // Create a context and set an x property on it's global object.
20309 LocalContext context0(NULL, global_template);
20310 v8::Handle<v8::Object> global0 = context0->Global();
20311 global0->Set(v8_str("x"), v8_num(42));
20312 ExpectString("JSON.stringify(this)", "{\"x\":42}");
20314 for (int i = 0; i < 2; i++) {
20316 // Install a toJSON function on the second run.
20317 v8::Handle<v8::FunctionTemplate> toJSON =
20318 v8::FunctionTemplate::New(UnreachableCallback);
20320 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
20322 // Create a context with a different security token so that the
20323 // failed access check callback will be called on each access.
20324 LocalContext context1(NULL, global_template);
20325 context1->Global()->Set(v8_str("other"), global0);
20327 ExpectString("JSON.stringify(other)", "{}");
20328 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
20329 "{\"a\":{},\"b\":[\"c\"]}");
20330 ExpectString("JSON.stringify([other, 'b', 'c'])",
20331 "[{},\"b\",\"c\"]");
20333 v8::Handle<v8::Array> array = v8::Array::New(2);
20334 array->Set(0, v8_str("a"));
20335 array->Set(1, v8_str("b"));
20336 context1->Global()->Set(v8_str("array"), array);
20337 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
20338 array->TurnOnAccessCheck();
20339 ExpectString("JSON.stringify(array)", "[]");
20340 ExpectString("JSON.stringify([array])", "[[]]");
20341 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
20346 bool access_check_fail_thrown = false;
20347 bool catch_callback_called = false;
20350 // Failed access check callback that performs a GC on each invocation.
20351 void FailedAccessCheckThrows(Local<v8::Object> target,
20352 v8::AccessType type,
20353 Local<v8::Value> data) {
20354 access_check_fail_thrown = true;
20355 i::PrintF("Access check failed. Error thrown.\n");
20356 v8::ThrowException(v8::Exception::Error(v8_str("cross context")));
20360 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
20361 for (int i = 0; i < args.Length(); i++) {
20362 i::PrintF("%s\n", *String::Utf8Value(args[i]));
20364 catch_callback_called = true;
20368 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
20369 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
20373 void CheckCorrectThrow(const char* script) {
20374 // Test that the script, when wrapped into a try-catch, triggers the catch
20375 // clause due to failed access check throwing an exception.
20376 // The subsequent try-catch should run without any exception.
20377 access_check_fail_thrown = false;
20378 catch_callback_called = false;
20379 i::ScopedVector<char> source(1024);
20380 i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
20381 CompileRun(source.start());
20382 CHECK(access_check_fail_thrown);
20383 CHECK(catch_callback_called);
20385 access_check_fail_thrown = false;
20386 catch_callback_called = false;
20387 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
20388 CHECK(!access_check_fail_thrown);
20389 CHECK(!catch_callback_called);
20393 TEST(AccessCheckThrows) {
20394 i::FLAG_allow_natives_syntax = true;
20395 v8::V8::Initialize();
20396 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
20397 v8::HandleScope scope(v8::Isolate::GetCurrent());
20399 // Create an ObjectTemplate for global objects and install access
20400 // check callbacks that will block access.
20401 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
20402 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
20403 IndexAccessAlwaysBlocked);
20405 // Create a context and set an x property on it's global object.
20406 LocalContext context0(NULL, global_template);
20407 context0->Global()->Set(v8_str("x"), v8_num(42));
20408 v8::Handle<v8::Object> global0 = context0->Global();
20410 // Create a context with a different security token so that the
20411 // failed access check callback will be called on each access.
20412 LocalContext context1(NULL, global_template);
20413 context1->Global()->Set(v8_str("other"), global0);
20415 v8::Handle<v8::FunctionTemplate> catcher_fun =
20416 v8::FunctionTemplate::New(CatcherCallback);
20417 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
20419 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
20420 v8::FunctionTemplate::New(HasOwnPropertyCallback);
20421 context1->Global()->Set(v8_str("has_own_property"),
20422 has_own_property_fun->GetFunction());
20424 { v8::TryCatch try_catch;
20425 access_check_fail_thrown = false;
20426 CompileRun("other.x;");
20427 CHECK(access_check_fail_thrown);
20428 CHECK(try_catch.HasCaught());
20431 CheckCorrectThrow("other.x");
20432 CheckCorrectThrow("other[1]");
20433 CheckCorrectThrow("JSON.stringify(other)");
20434 CheckCorrectThrow("has_own_property(other, 'x')");
20435 CheckCorrectThrow("%GetProperty(other, 'x')");
20436 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
20437 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
20438 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
20439 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
20440 CheckCorrectThrow("%HasLocalProperty(other, 'x')");
20441 CheckCorrectThrow("%HasProperty(other, 'x')");
20442 CheckCorrectThrow("%HasElement(other, 1)");
20443 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
20444 CheckCorrectThrow("%GetPropertyNames(other)");
20445 CheckCorrectThrow("%GetLocalPropertyNames(other, true)");
20446 CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
20447 "other, 'x', null, null, 1)");
20449 // Reset the failed access check callback so it does not influence
20450 // the other tests.
20451 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
20455 THREADED_TEST(Regress256330) {
20456 i::FLAG_allow_natives_syntax = true;
20457 LocalContext context;
20458 v8::HandleScope scope(context->GetIsolate());
20459 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20460 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20461 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
20462 CompileRun("\"use strict\"; var o = new Bug;"
20463 "function f(o) { o.x = 10; };"
20464 "f(o); f(o); f(o);"
20465 "%OptimizeFunctionOnNextCall(f);"
20467 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
20471 THREADED_TEST(CrankshaftInterceptorSetter) {
20472 i::FLAG_allow_natives_syntax = true;
20473 v8::HandleScope scope(v8::Isolate::GetCurrent());
20474 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20475 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20477 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20478 CompileRun("var obj = new Obj;"
20479 // Initialize fields to avoid transitions later.
20481 "obj.accessor_age = 42;"
20482 "function setter(i) { this.accessor_age = i; };"
20483 "function getter() { return this.accessor_age; };"
20484 "function setAge(i) { obj.age = i; };"
20485 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
20489 "%OptimizeFunctionOnNextCall(setAge);"
20491 // All stores went through the interceptor.
20492 ExpectInt32("obj.interceptor_age", 4);
20493 ExpectInt32("obj.accessor_age", 42);
20497 THREADED_TEST(CrankshaftInterceptorGetter) {
20498 i::FLAG_allow_natives_syntax = true;
20499 v8::HandleScope scope(v8::Isolate::GetCurrent());
20500 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20501 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20503 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20504 CompileRun("var obj = new Obj;"
20505 // Initialize fields to avoid transitions later.
20507 "obj.accessor_age = 42;"
20508 "function getter() { return this.accessor_age; };"
20509 "function getAge() { return obj.interceptor_age; };"
20510 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
20514 "%OptimizeFunctionOnNextCall(getAge);");
20515 // Access through interceptor.
20516 ExpectInt32("getAge()", 1);
20520 THREADED_TEST(CrankshaftInterceptorFieldRead) {
20521 i::FLAG_allow_natives_syntax = true;
20522 v8::HandleScope scope(v8::Isolate::GetCurrent());
20523 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20524 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20526 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20527 CompileRun("var obj = new Obj;"
20528 "obj.__proto__.interceptor_age = 42;"
20530 "function getAge() { return obj.interceptor_age; };");
20531 ExpectInt32("getAge();", 100);
20532 ExpectInt32("getAge();", 100);
20533 ExpectInt32("getAge();", 100);
20534 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
20535 // Access through interceptor.
20536 ExpectInt32("getAge();", 100);
20540 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
20541 i::FLAG_allow_natives_syntax = true;
20542 v8::HandleScope scope(v8::Isolate::GetCurrent());
20543 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20544 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20546 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20547 CompileRun("var obj = new Obj;"
20548 "obj.age = 100000;"
20549 "function setAge(i) { obj.age = i };"
20553 "%OptimizeFunctionOnNextCall(setAge);"
20555 ExpectInt32("obj.age", 100000);
20556 ExpectInt32("obj.interceptor_age", 103);
20560 #endif // V8_OS_POSIX
20563 static Local<Value> function_new_expected_env;
20564 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
20565 CHECK_EQ(function_new_expected_env, info.Data());
20566 info.GetReturnValue().Set(17);
20570 THREADED_TEST(FunctionNew) {
20572 v8::Isolate* isolate = env->GetIsolate();
20573 v8::HandleScope scope(isolate);
20574 Local<Object> data = v8::Object::New();
20575 function_new_expected_env = data;
20576 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
20577 env->Global()->Set(v8_str("func"), func);
20578 Local<Value> result = CompileRun("func();");
20579 CHECK_EQ(v8::Integer::New(17, isolate), result);
20580 // Verify function not cached
20581 int serial_number =
20582 i::Smi::cast(v8::Utils::OpenHandle(*func)
20583 ->shared()->get_api_func_data()->serial_number())->value();
20584 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20585 i::Object* elm = i_isolate->native_context()->function_cache()
20586 ->GetElementNoExceptionThrown(i_isolate, serial_number);
20587 CHECK(elm->IsNull());