chromium.googlesource.com

// Copyright 2012 the V8 project authors. All rights reserved.// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following// disclaimer in the documentation and/or other materials provided// with the distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived// from this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#include <climits>#include <csignal>#include <map>#include <string>#include "test/cctest/test-api.h"#if V8_OS_POSIX#include <unistd.h> // NOLINT#endif#include "include/v8-util.h"#include "src/api.h"#include "src/arguments.h"#include "src/base/platform/platform.h"#include "src/compilation-cache.h"#include "src/debug.h"#include "src/execution.h"#include "src/objects.h"#include "src/parser.h"#include "src/smart-pointers.h"#include "src/unicode-inl.h"#include "src/utils.h"#include "src/vm-state.h"static const bool kLogThreading = false;using ::v8::Boolean;using ::v8::BooleanObject;using ::v8::Context;using ::v8::Extension;using ::v8::Function;using ::v8::FunctionTemplate;using ::v8::Handle;using ::v8::HandleScope;using ::v8::Local;using ::v8::Maybe;using ::v8::Message;using ::v8::MessageCallback;using ::v8::Name;using ::v8::None;using ::v8::Object;using ::v8::ObjectTemplate;using ::v8::Persistent;using ::v8::PropertyAttribute;using ::v8::Script;using ::v8::StackTrace;using ::v8::String;using ::v8::Symbol;using ::v8::TryCatch;using ::v8::Undefined;using ::v8::UniqueId;using ::v8::V8;using ::v8::Value;#define THREADED_PROFILED_TEST(Name) \ static void Test##Name(); \ TEST(Name##WithProfiler) { \ RunWithProfiler(&Test##Name); \ } \ THREADED_TEST(Name)void RunWithProfiler(void (*test)()) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Local<v8::String> profile_name = v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1"); v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler(); cpu_profiler->StartProfiling(profile_name); (*test)(); reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();}static int signature_callback_count;static Local<Value> signature_expected_receiver;static void IncrementingSignatureCallback( const v8::FunctionCallbackInfo<v8::Value>& args) { ApiTestFuzzer::Fuzz(); signature_callback_count++; CHECK(signature_expected_receiver->Equals(args.Holder())); CHECK(signature_expected_receiver->Equals(args.This())); v8::Handle<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length()); for (int i = 0; i < args.Length(); i++) result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]); args.GetReturnValue().Set(result);}static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) { info.GetReturnValue().Set(42);}// Tests that call v8::V8::Dispose() cannot be threaded.UNINITIALIZED_TEST(InitializeAndDisposeOnce) { CHECK(v8::V8::Initialize()); CHECK(v8::V8::Dispose());}// Tests that call v8::V8::Dispose() cannot be threaded.UNINITIALIZED_TEST(InitializeAndDisposeMultiple) { for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());}THREADED_TEST(Handles) { v8::HandleScope scope(CcTest::isolate()); Local<Context> local_env; { LocalContext env; local_env = env.local(); } // Local context should still be live. CHECK(!local_env.IsEmpty()); local_env->Enter(); v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate()); CHECK(!undef.IsEmpty()); CHECK(undef->IsUndefined()); const char* source = "1 + 2 + 3"; Local<Script> script = v8_compile(source); CHECK_EQ(6, script->Run()->Int32Value()); local_env->Exit();}THREADED_TEST(IsolateOfContext) { v8::HandleScope scope(CcTest::isolate()); v8::Handle<Context> env = Context::New(CcTest::isolate()); CHECK(!env->GetIsolate()->InContext()); CHECK(env->GetIsolate() == CcTest::isolate()); env->Enter(); CHECK(env->GetIsolate()->InContext()); CHECK(env->GetIsolate() == CcTest::isolate()); env->Exit(); CHECK(!env->GetIsolate()->InContext()); CHECK(env->GetIsolate() == CcTest::isolate());}static void TestSignature(const char* loop_js, Local<Value> receiver, v8::Isolate* isolate) { i::ScopedVector<char> source(200); i::SNPrintF(source, "for (var i = 0; i < 10; i++) {" " %s" "}", loop_js); signature_callback_count = 0; signature_expected_receiver = receiver; bool expected_to_throw = receiver.IsEmpty(); v8::TryCatch try_catch(isolate); CompileRun(source.start()); CHECK_EQ(expected_to_throw, try_catch.HasCaught()); if (!expected_to_throw) { CHECK_EQ(10, signature_callback_count); } else { CHECK(v8_str("TypeError: Illegal invocation") ->Equals(try_catch.Exception()->ToString(isolate))); }}THREADED_TEST(ReceiverSignature) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); // Setup templates. v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun); v8::Handle<v8::FunctionTemplate> callback_sig = v8::FunctionTemplate::New( isolate, IncrementingSignatureCallback, Local<Value>(), sig); v8::Handle<v8::FunctionTemplate> callback = v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback); v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate); sub_fun->Inherit(fun); v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New(isolate); // Install properties. v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate(); fun_proto->Set(v8_str("prop_sig"), callback_sig); fun_proto->Set(v8_str("prop"), callback); fun_proto->SetAccessorProperty( v8_str("accessor_sig"), callback_sig, callback_sig); fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback); // Instantiate templates. Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance(); Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance(); // Setup global variables. env->Global()->Set(v8_str("Fun"), fun->GetFunction()); env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction()); env->Global()->Set(v8_str("fun_instance"), fun_instance); env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance); CompileRun( "var accessor_sig_key = 'accessor_sig';" "var accessor_key = 'accessor';" "var prop_sig_key = 'prop_sig';" "var prop_key = 'prop';" "" "function copy_props(obj) {" " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];" " var source = Fun.prototype;" " for (var i in keys) {" " var key = keys[i];" " var desc = Object.getOwnPropertyDescriptor(source, key);" " Object.defineProperty(obj, key, desc);" " }" "}" "" "var obj = {};" "copy_props(obj);" "var unrel = new UnrelFun();" "copy_props(unrel);"); // Test with and without ICs const char* test_objects[] = { "fun_instance", "sub_fun_instance", "obj", "unrel" }; unsigned bad_signature_start_offset = 2; for (unsigned i = 0; i < arraysize(test_objects); i++) { i::ScopedVector<char> source(200); i::SNPrintF( source, "var test_object = %s; test_object", test_objects[i]); Local<Value> test_object = CompileRun(source.start()); TestSignature("test_object.prop();", test_object, isolate); TestSignature("test_object.accessor;", test_object, isolate); TestSignature("test_object[accessor_key];", test_object, isolate); TestSignature("test_object.accessor = 1;", test_object, isolate); TestSignature("test_object[accessor_key] = 1;", test_object, isolate); if (i >= bad_signature_start_offset) test_object = Local<Value>(); TestSignature("test_object.prop_sig();", test_object, isolate); TestSignature("test_object.accessor_sig;", test_object, isolate); TestSignature("test_object[accessor_sig_key];", test_object, isolate); TestSignature("test_object.accessor_sig = 1;", test_object, isolate); TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate); }}THREADED_TEST(HulIgennem) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); v8::Handle<v8::Primitive> undef = v8::Undefined(isolate); Local<String> undef_str = undef->ToString(isolate); char* value = i::NewArray<char>(undef_str->Utf8Length() + 1); undef_str->WriteUtf8(value); CHECK_EQ(0, strcmp(value, "undefined")); i::DeleteArray(value);}THREADED_TEST(Access) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); Local<v8::Object> obj = v8::Object::New(isolate); Local<Value> foo_before = obj->Get(v8_str("foo")); CHECK(foo_before->IsUndefined()); Local<String> bar_str = v8_str("bar"); obj->Set(v8_str("foo"), bar_str); Local<Value> foo_after = obj->Get(v8_str("foo")); CHECK(!foo_after->IsUndefined()); CHECK(foo_after->IsString()); CHECK(bar_str->Equals(foo_after));}THREADED_TEST(AccessElement) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); Local<Value> before = obj->Get(1); CHECK(before->IsUndefined()); Local<String> bar_str = v8_str("bar"); obj->Set(1, bar_str); Local<Value> after = obj->Get(1); CHECK(!after->IsUndefined()); CHECK(after->IsString()); CHECK(bar_str->Equals(after)); Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>(); CHECK(v8_str("a")->Equals(value->Get(0))); CHECK(v8_str("b")->Equals(value->Get(1)));}THREADED_TEST(Script) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); const char* source = "1 + 2 + 3"; Local<Script> script = v8_compile(source); CHECK_EQ(6, script->Run()->Int32Value());}class TestResource: public String::ExternalStringResource { public: explicit TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true) : data_(data), length_(0), counter_(counter), owning_data_(owning_data) { while (data[length_]) ++length_; } ~TestResource() { if (owning_data_) i::DeleteArray(data_); if (counter_ != NULL) ++*counter_; } const uint16_t* data() const { return data_; } size_t length() const { return length_; } private: uint16_t* data_; size_t length_; int* counter_; bool owning_data_;};class TestOneByteResource : public String::ExternalOneByteStringResource { public: explicit TestOneByteResource(const char* data, int* counter = NULL, size_t offset = 0) : orig_data_(data), data_(data + offset), length_(strlen(data) - offset), counter_(counter) {} ~TestOneByteResource() { i::DeleteArray(orig_data_); if (counter_ != NULL) ++*counter_; } const char* data() const { return data_; } size_t length() const { return length_; } private: const char* orig_data_; const char* data_; size_t length_; int* counter_;};THREADED_TEST(ScriptUsingStringResource) { int dispose_count = 0; const char* c_source = "1 + 2 * 3"; uint16_t* two_byte_source = AsciiToTwoByteString(c_source); { LocalContext env; v8::HandleScope scope(env->GetIsolate()); TestResource* resource = new TestResource(two_byte_source, &dispose_count); Local<String> source = String::NewExternal(env->GetIsolate(), resource); Local<Script> script = v8_compile(source); Local<Value> value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value()); CHECK(source->IsExternal()); CHECK_EQ(resource, static_cast<TestResource*>(source->GetExternalStringResource())); String::Encoding encoding = String::UNKNOWN_ENCODING; CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), source->GetExternalStringResourceBase(&encoding)); CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); CcTest::heap()->CollectAllGarbage(); CHECK_EQ(0, dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(1, dispose_count);}THREADED_TEST(ScriptUsingOneByteStringResource) { int dispose_count = 0; const char* c_source = "1 + 2 * 3"; { LocalContext env; v8::HandleScope scope(env->GetIsolate()); TestOneByteResource* resource = new TestOneByteResource(i::StrDup(c_source), &dispose_count); Local<String> source = String::NewExternal(env->GetIsolate(), resource); CHECK(source->IsExternalOneByte()); CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), source->GetExternalOneByteStringResource()); String::Encoding encoding = String::UNKNOWN_ENCODING; CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), source->GetExternalStringResourceBase(&encoding)); CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); Local<Script> script = v8_compile(source); Local<Value> value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value()); CcTest::heap()->CollectAllGarbage(); CHECK_EQ(0, dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(1, dispose_count);}THREADED_TEST(ScriptMakingExternalString) { int dispose_count = 0; uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3"); { LocalContext env; v8::HandleScope scope(env->GetIsolate()); Local<String> source = String::NewFromTwoByte(env->GetIsolate(), two_byte_source); // Trigger GCs so that the newly allocated string moves to old gen. CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now CHECK_EQ(source->IsExternal(), false); CHECK_EQ(source->IsExternalOneByte(), false); String::Encoding encoding = String::UNKNOWN_ENCODING; CHECK(!source->GetExternalStringResourceBase(&encoding)); CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); bool success = source->MakeExternal(new TestResource(two_byte_source, &dispose_count)); CHECK(success); Local<Script> script = v8_compile(source); Local<Value> value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value()); CcTest::heap()->CollectAllGarbage(); CHECK_EQ(0, dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); CcTest::heap()->CollectAllGarbage(); CHECK_EQ(1, dispose_count);}THREADED_TEST(ScriptMakingExternalOneByteString) { int dispose_count = 0; const char* c_source = "1 + 2 * 3"; { LocalContext env; v8::HandleScope scope(env->GetIsolate()); Local<String> source = v8_str(c_source); // Trigger GCs so that the newly allocated string moves to old gen. CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now bool success = source->MakeExternal( new TestOneByteResource(i::StrDup(c_source), &dispose_count)); CHECK(success); Local<Script> script = v8_compile(source); Local<Value> value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value()); CcTest::heap()->CollectAllGarbage(); CHECK_EQ(0, dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); CcTest::heap()->CollectAllGarbage(); CHECK_EQ(1, dispose_count);}TEST(MakingExternalStringConditions) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); // Free some space in the new space so that we can check freshness. CcTest::heap()->CollectGarbage(i::NEW_SPACE); CcTest::heap()->CollectGarbage(i::NEW_SPACE); uint16_t* two_byte_string = AsciiToTwoByteString("s1"); Local<String> small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string); i::DeleteArray(two_byte_string); // We should refuse to externalize newly created small string. CHECK(!small_string->CanMakeExternal()); // Trigger GCs so that the newly allocated string moves to old gen. CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now // Old space strings should be accepted. CHECK(small_string->CanMakeExternal()); two_byte_string = AsciiToTwoByteString("small string 2"); small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string); i::DeleteArray(two_byte_string); // We should refuse externalizing newly created small string. CHECK(!small_string->CanMakeExternal()); for (int i = 0; i < 100; i++) { String::Value value(small_string); } // Frequently used strings should be accepted. CHECK(small_string->CanMakeExternal()); const int buf_size = 10 * 1024; char* buf = i::NewArray<char>(buf_size); memset(buf, 'a', buf_size); buf[buf_size - 1] = '\0'; two_byte_string = AsciiToTwoByteString(buf); Local<String> large_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string); i::DeleteArray(buf); i::DeleteArray(two_byte_string); // Large strings should be immediately accepted. CHECK(large_string->CanMakeExternal());}TEST(MakingExternalOneByteStringConditions) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); // Free some space in the new space so that we can check freshness. CcTest::heap()->CollectGarbage(i::NEW_SPACE); CcTest::heap()->CollectGarbage(i::NEW_SPACE); Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1"); // We should refuse to externalize newly created small string. CHECK(!small_string->CanMakeExternal()); // Trigger GCs so that the newly allocated string moves to old gen. CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now // Old space strings should be accepted. CHECK(small_string->CanMakeExternal()); small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2"); // We should refuse externalizing newly created small string. CHECK(!small_string->CanMakeExternal()); for (int i = 0; i < 100; i++) { String::Value value(small_string); } // Frequently used strings should be accepted. CHECK(small_string->CanMakeExternal()); const int buf_size = 10 * 1024; char* buf = i::NewArray<char>(buf_size); memset(buf, 'a', buf_size); buf[buf_size - 1] = '\0'; Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf); i::DeleteArray(buf); // Large strings should be immediately accepted. CHECK(large_string->CanMakeExternal());}TEST(MakingExternalUnalignedOneByteString) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); CompileRun("function cons(a, b) { return a + b; }" "function slice(a) { return a.substring(1); }"); // Create a cons string that will land in old pointer space. Local<String> cons = Local<String>::Cast(CompileRun( "cons('abcdefghijklm', 'nopqrstuvwxyz');")); // Create a sliced string that will land in old pointer space. Local<String> slice = Local<String>::Cast(CompileRun( "slice('abcdefghijklmnopqrstuvwxyz');")); // Trigger GCs so that the newly allocated string moves to old gen. SimulateFullSpace(CcTest::heap()->old_space()); CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now // Turn into external string with unaligned resource data. const char* c_cons = "_abcdefghijklmnopqrstuvwxyz"; bool success = cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1)); CHECK(success); const char* c_slice = "_bcdefghijklmnopqrstuvwxyz"; success = slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1)); CHECK(success); // Trigger GCs and force evacuation. CcTest::heap()->CollectAllGarbage(); CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);}THREADED_TEST(UsingExternalString) { i::Factory* factory = CcTest::i_isolate()->factory(); { v8::HandleScope scope(CcTest::isolate()); uint16_t* two_byte_string = AsciiToTwoByteString("test string"); Local<String> string = String::NewExternal( CcTest::isolate(), new TestResource(two_byte_string)); i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); // Trigger GCs so that the newly allocated string moves to old gen. CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now i::Handle<i::String> isymbol = factory->InternalizeString(istring); CHECK(isymbol->IsInternalizedString()); } CcTest::heap()->CollectAllGarbage(); CcTest::heap()->CollectAllGarbage();}THREADED_TEST(UsingExternalOneByteString) { i::Factory* factory = CcTest::i_isolate()->factory(); { v8::HandleScope scope(CcTest::isolate()); const char* one_byte_string = "test string"; Local<String> string = String::NewExternal( CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string))); i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); // Trigger GCs so that the newly allocated string moves to old gen. CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now i::Handle<i::String> isymbol = factory->InternalizeString(istring); CHECK(isymbol->IsInternalizedString()); } CcTest::heap()->CollectAllGarbage(); CcTest::heap()->CollectAllGarbage();}class RandomLengthResource : public v8::String::ExternalStringResource { public: explicit RandomLengthResource(int length) : length_(length) {} virtual const uint16_t* data() const { return string_; } virtual size_t length() const { return length_; } private: uint16_t string_[10]; int length_;};class RandomLengthOneByteResource : public v8::String::ExternalOneByteStringResource { public: explicit RandomLengthOneByteResource(int length) : length_(length) {} virtual const char* data() const { return string_; } virtual size_t length() const { return length_; } private: char string_[10]; int length_;};THREADED_TEST(NewExternalForVeryLongString) { auto isolate = CcTest::isolate(); { v8::HandleScope scope(isolate); v8::TryCatch try_catch(isolate); RandomLengthOneByteResource r(1 << 30); v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r); CHECK(str.IsEmpty()); CHECK(!try_catch.HasCaught()); } { v8::HandleScope scope(isolate); v8::TryCatch try_catch(isolate); RandomLengthResource r(1 << 30); v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r); CHECK(str.IsEmpty()); CHECK(!try_catch.HasCaught()); }}THREADED_TEST(ScavengeExternalString) { i::FLAG_stress_compaction = false; i::FLAG_gc_global = false; int dispose_count = 0; bool in_new_space = false; { v8::HandleScope scope(CcTest::isolate()); uint16_t* two_byte_string = AsciiToTwoByteString("test string"); Local<String> string = String::NewExternal( CcTest::isolate(), new TestResource(two_byte_string, &dispose_count)); i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); CcTest::heap()->CollectGarbage(i::NEW_SPACE); in_new_space = CcTest::heap()->InNewSpace(*istring); CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring)); CHECK_EQ(0, dispose_count); } CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE); CHECK_EQ(1, dispose_count);}THREADED_TEST(ScavengeExternalOneByteString) { i::FLAG_stress_compaction = false; i::FLAG_gc_global = false; int dispose_count = 0; bool in_new_space = false; { v8::HandleScope scope(CcTest::isolate()); const char* one_byte_string = "test string"; Local<String> string = String::NewExternal( CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count)); i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); CcTest::heap()->CollectGarbage(i::NEW_SPACE); in_new_space = CcTest::heap()->InNewSpace(*istring); CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring)); CHECK_EQ(0, dispose_count); } CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE); CHECK_EQ(1, dispose_count);}class TestOneByteResourceWithDisposeControl : public TestOneByteResource { public: // Only used by non-threaded tests, so it can use static fields. static int dispose_calls; static int dispose_count; TestOneByteResourceWithDisposeControl(const char* data, bool dispose) : TestOneByteResource(data, &dispose_count), dispose_(dispose) {} void Dispose() { ++dispose_calls; if (dispose_) delete this; } private: bool dispose_;};int TestOneByteResourceWithDisposeControl::dispose_count = 0;int TestOneByteResourceWithDisposeControl::dispose_calls = 0;TEST(ExternalStringWithDisposeHandling) { const char* c_source = "1 + 2 * 3"; // Use a stack allocated external string resource allocated object. TestOneByteResourceWithDisposeControl::dispose_count = 0; TestOneByteResourceWithDisposeControl::dispose_calls = 0; TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false); { LocalContext env; v8::HandleScope scope(env->GetIsolate()); Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack); Local<Script> script = v8_compile(source); Local<Value> value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value()); CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls); CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); // Use a heap allocated external string resource allocated object. TestOneByteResourceWithDisposeControl::dispose_count = 0; TestOneByteResourceWithDisposeControl::dispose_calls = 0; TestOneByteResource* res_heap = new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true); { LocalContext env; v8::HandleScope scope(env->GetIsolate()); Local<String> source = String::NewExternal(env->GetIsolate(), res_heap); Local<Script> script = v8_compile(source); Local<Value> value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value()); CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls); CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);}THREADED_TEST(StringConcat) { { LocalContext env; v8::HandleScope scope(env->GetIsolate()); const char* one_byte_string_1 = "function a_times_t"; const char* two_byte_string_1 = "wo_plus_b(a, b) {return "; const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + "; const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + "; const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + "; const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + "; const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);"; Local<String> left = v8_str(one_byte_string_1); uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1); Local<String> right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source); i::DeleteArray(two_byte_source); Local<String> source = String::Concat(left, right); right = String::NewExternal( env->GetIsolate(), new TestOneByteResource(i::StrDup(one_byte_extern_1))); source = String::Concat(source, right); right = String::NewExternal( env->GetIsolate(), new TestResource(AsciiToTwoByteString(two_byte_extern_1))); source = String::Concat(source, right); right = v8_str(one_byte_string_2); source = String::Concat(source, right); two_byte_source = AsciiToTwoByteString(two_byte_string_2); right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source); i::DeleteArray(two_byte_source); source = String::Concat(source, right); right = String::NewExternal( env->GetIsolate(), new TestResource(AsciiToTwoByteString(two_byte_extern_2))); source = String::Concat(source, right); Local<Script> script = v8_compile(source); Local<Value> value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(68, value->Int32Value()); } CcTest::i_isolate()->compilation_cache()->Clear(); CcTest::heap()->CollectAllGarbage(); CcTest::heap()->CollectAllGarbage();}THREADED_TEST(GlobalProperties) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Handle<v8::Object> global = env->Global(); global->Set(v8_str("pi"), v8_num(3.1415926)); Local<Value> pi = global->Get(v8_str("pi")); CHECK_EQ(3.1415926, pi->NumberValue());}static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info, i::Address callback) { ApiTestFuzzer::Fuzz(); CheckReturnValue(info, callback); info.GetReturnValue().Set(v8_str("bad value")); info.GetReturnValue().Set(v8_num(102));}static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) { return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));}static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) { return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));}static void construct_callback( const v8::FunctionCallbackInfo<Value>& info) { ApiTestFuzzer::Fuzz(); CheckReturnValue(info, FUNCTION_ADDR(construct_callback)); info.This()->Set(v8_str("x"), v8_num(1)); info.This()->Set(v8_str("y"), v8_num(2)); info.GetReturnValue().Set(v8_str("bad value")); info.GetReturnValue().Set(info.This());}static void Return239Callback( Local<String> name, const v8::PropertyCallbackInfo<Value>& info) { ApiTestFuzzer::Fuzz(); CheckReturnValue(info, FUNCTION_ADDR(Return239Callback)); info.GetReturnValue().Set(v8_str("bad value")); info.GetReturnValue().Set(v8_num(239));}template<typename Handler>static void TestFunctionTemplateInitializer(Handler handler, Handler handler_2) { // Test constructor calls. { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate, handler); Local<Function> fun = fun_templ->GetFunction(); env->Global()->Set(v8_str("obj"), fun); Local<Script> script = v8_compile("obj()"); for (int i = 0; i < 30; i++) { CHECK_EQ(102, script->Run()->Int32Value()); } } // Use SetCallHandler to initialize a function template, should work like // the previous one. { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); fun_templ->SetCallHandler(handler_2); Local<Function> fun = fun_templ->GetFunction(); env->Global()->Set(v8_str("obj"), fun); Local<Script> script = v8_compile("obj()"); for (int i = 0; i < 30; i++) { CHECK_EQ(102, script->Run()->Int32Value()); } }}template<typename Constructor, typename Accessor>static void TestFunctionTemplateAccessor(Constructor constructor, Accessor accessor) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(env->GetIsolate(), constructor); fun_templ->SetClassName(v8_str("funky")); fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor); Local<Function> fun = fun_templ->GetFunction(); env->Global()->Set(v8_str("obj"), fun); Local<Value> result = v8_compile("(new obj()).toString()")->Run(); CHECK(v8_str("[object funky]")->Equals(result)); CompileRun("var obj_instance = new obj();"); Local<Script> script; script = v8_compile("obj_instance.x"); for (int i = 0; i < 30; i++) { CHECK_EQ(1, script->Run()->Int32Value()); } script = v8_compile("obj_instance.m"); for (int i = 0; i < 30; i++) { CHECK_EQ(239, script->Run()->Int32Value()); }}THREADED_PROFILED_TEST(FunctionTemplate) { TestFunctionTemplateInitializer(handle_callback, handle_callback_2); TestFunctionTemplateAccessor(construct_callback, Return239Callback);}static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { ApiTestFuzzer::Fuzz(); CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback)); info.GetReturnValue().Set(v8_num(51423 + info.Length()));}template<typename Callback>static void TestSimpleCallback(Callback callback) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); object_template->Set(isolate, "callback", v8::FunctionTemplate::New(isolate, callback)); v8::Local<v8::Object> object = object_template->NewInstance(); (*env)->Global()->Set(v8_str("callback_object"), object); v8::Handle<v8::Script> script; script = v8_compile("callback_object.callback(17)"); for (int i = 0; i < 30; i++) { CHECK_EQ(51424, script->Run()->Int32Value()); } script = v8_compile("callback_object.callback(17, 24)"); for (int i = 0; i < 30; i++) { CHECK_EQ(51425, script->Run()->Int32Value()); }}THREADED_PROFILED_TEST(SimpleCallback) { TestSimpleCallback(SimpleCallback);}template<typename T>void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);// constant return valuesstatic int32_t fast_return_value_int32 = 471;static uint32_t fast_return_value_uint32 = 571;static const double kFastReturnValueDouble = 2.7;// variable return valuesstatic bool fast_return_value_bool = false;enum ReturnValueOddball { kNullReturnValue, kUndefinedReturnValue, kEmptyStringReturnValue};static ReturnValueOddball fast_return_value_void;static bool fast_return_value_object_is_empty = false;// Helper function to avoid compiler error: insufficient contextual information// to determine type when applying FUNCTION_ADDR to a template function.static i::Address address_of(v8::FunctionCallback callback) { return FUNCTION_ADDR(callback);}template<>void FastReturnValueCallback<int32_t>( const v8::FunctionCallbackInfo<v8::Value>& info) { CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>)); info.GetReturnValue().Set(fast_return_value_int32);}template<>void FastReturnValueCallback<uint32_t>( const v8::FunctionCallbackInfo<v8::Value>& info) { CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>)); info.GetReturnValue().Set(fast_return_value_uint32);}template<>void FastReturnValueCallback<double>( const v8::FunctionCallbackInfo<v8::Value>& info) { CheckReturnValue(info, address_of(FastReturnValueCallback<double>)); info.GetReturnValue().Set(kFastReturnValueDouble);}template<>void FastReturnValueCallback<bool>( const v8::FunctionCallbackInfo<v8::Value>& info) { CheckReturnValue(info, address_of(FastReturnValueCallback<bool>)); info.GetReturnValue().Set(fast_return_value_bool);}template<>void FastReturnValueCallback<void>( const v8::FunctionCallbackInfo<v8::Value>& info) { CheckReturnValue(info, address_of(FastReturnValueCallback<void>)); switch (fast_return_value_void) { case kNullReturnValue: info.GetReturnValue().SetNull(); break; case kUndefinedReturnValue: info.GetReturnValue().SetUndefined(); break; case kEmptyStringReturnValue: info.GetReturnValue().SetEmptyString(); break; }}template<>void FastReturnValueCallback<Object>( const v8::FunctionCallbackInfo<v8::Value>& info) { v8::Handle<v8::Object> object; if (!fast_return_value_object_is_empty) { object = Object::New(info.GetIsolate()); } info.GetReturnValue().Set(object);}template<typename T>Handle<Value> TestFastReturnValues() { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::EscapableHandleScope scope(isolate); v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); v8::FunctionCallback callback = &FastReturnValueCallback<T>; object_template->Set(isolate, "callback", v8::FunctionTemplate::New(isolate, callback)); v8::Local<v8::Object> object = object_template->NewInstance(); (*env)->Global()->Set(v8_str("callback_object"), object); return scope.Escape(CompileRun("callback_object.callback()"));}THREADED_PROFILED_TEST(FastReturnValues) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); v8::Handle<v8::Value> value; // check int32_t and uint32_t int32_t int_values[] = { 0, 234, -723, i::Smi::kMinValue, i::Smi::kMaxValue }; for (size_t i = 0; i < arraysize(int_values); i++) { for (int modifier = -1; modifier <= 1; modifier++) { int int_value = int_values[i] + modifier; // check int32_t fast_return_value_int32 = int_value; value = TestFastReturnValues<int32_t>(); CHECK(value->IsInt32()); CHECK(fast_return_value_int32 == value->Int32Value()); // check uint32_t fast_return_value_uint32 = static_cast<uint32_t>(int_value); value = TestFastReturnValues<uint32_t>(); CHECK(value->IsUint32()); CHECK(fast_return_value_uint32 == value->Uint32Value()); } } // check double value = TestFastReturnValues<double>(); CHECK(value->IsNumber()); CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value()); // check bool values for (int i = 0; i < 2; i++) { fast_return_value_bool = i == 0; value = TestFastReturnValues<bool>(); CHECK(value->IsBoolean()); CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value()); } // check oddballs ReturnValueOddball oddballs[] = { kNullReturnValue, kUndefinedReturnValue, kEmptyStringReturnValue }; for (size_t i = 0; i < arraysize(oddballs); i++) { fast_return_value_void = oddballs[i]; value = TestFastReturnValues<void>(); switch (fast_return_value_void) { case kNullReturnValue: CHECK(value->IsNull()); break; case kUndefinedReturnValue: CHECK(value->IsUndefined()); break; case kEmptyStringReturnValue: CHECK(value->IsString()); CHECK_EQ(0, v8::String::Cast(*value)->Length()); break; } } // check handles fast_return_value_object_is_empty = false; value = TestFastReturnValues<Object>(); CHECK(value->IsObject()); fast_return_value_object_is_empty = true; value = TestFastReturnValues<Object>(); CHECK(value->IsUndefined());}THREADED_TEST(FunctionTemplateSetLength) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); { Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate, handle_callback, Handle<v8::Value>(), Handle<v8::Signature>(), 23); Local<Function> fun = fun_templ->GetFunction(); env->Global()->Set(v8_str("obj"), fun); Local<Script> script = v8_compile("obj.length"); CHECK_EQ(23, script->Run()->Int32Value()); } { Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate, handle_callback); fun_templ->SetLength(22); Local<Function> fun = fun_templ->GetFunction(); env->Global()->Set(v8_str("obj"), fun); Local<Script> script = v8_compile("obj.length"); CHECK_EQ(22, script->Run()->Int32Value()); } { // Without setting length it defaults to 0. Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate, handle_callback); Local<Function> fun = fun_templ->GetFunction(); env->Global()->Set(v8_str("obj"), fun); Local<Script> script = v8_compile("obj.length"); CHECK_EQ(0, script->Run()->Int32Value()); }}static void* expected_ptr;static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) { void* ptr = v8::External::Cast(*args.Data())->Value(); CHECK_EQ(expected_ptr, ptr); args.GetReturnValue().Set(true);}static void TestExternalPointerWrapping() { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); v8::Handle<v8::Value> data = v8::External::New(isolate, expected_ptr); v8::Handle<v8::Object> obj = v8::Object::New(isolate); obj->Set(v8_str("func"), v8::FunctionTemplate::New(isolate, callback, data)->GetFunction()); env->Global()->Set(v8_str("obj"), obj); CHECK(CompileRun( "function foo() {\n" " for (var i = 0; i < 13; i++) obj.func();\n" "}\n" "foo(), true")->BooleanValue());}THREADED_TEST(ExternalWrap) { // Check heap allocated object. int* ptr = new int; expected_ptr = ptr; TestExternalPointerWrapping(); delete ptr; // Check stack allocated object. int foo; expected_ptr = &foo; TestExternalPointerWrapping(); // Check not aligned addresses. const int n = 100; char* s = new char[n]; for (int i = 0; i < n; i++) { expected_ptr = s + i; TestExternalPointerWrapping(); } delete[] s; // Check several invalid addresses. expected_ptr = reinterpret_cast<void*>(1); TestExternalPointerWrapping(); expected_ptr = reinterpret_cast<void*>(0xdeadbeef); TestExternalPointerWrapping(); expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1); TestExternalPointerWrapping();#if defined(V8_HOST_ARCH_X64) // Check a value with a leading 1 bit in x64 Smi encoding. expected_ptr = reinterpret_cast<void*>(0x400000000); TestExternalPointerWrapping(); expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef); TestExternalPointerWrapping(); expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1); TestExternalPointerWrapping();#endif}THREADED_TEST(FindInstanceInPrototypeChain) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate); Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate); Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate); derived->Inherit(base); Local<v8::Function> base_function = base->GetFunction(); Local<v8::Function> derived_function = derived->GetFunction(); Local<v8::Function> other_function = other->GetFunction(); Local<v8::Object> base_instance = base_function->NewInstance(); Local<v8::Object> derived_instance = derived_function->NewInstance(); Local<v8::Object> derived_instance2 = derived_function->NewInstance(); Local<v8::Object> other_instance = other_function->NewInstance(); derived_instance2->Set(v8_str("__proto__"), derived_instance); other_instance->Set(v8_str("__proto__"), derived_instance2); // base_instance is only an instance of base. CHECK( base_instance->Equals(base_instance->FindInstanceInPrototypeChain(base))); CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty()); CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty()); // derived_instance is an instance of base and derived. CHECK(derived_instance->Equals( derived_instance->FindInstanceInPrototypeChain(base))); CHECK(derived_instance->Equals( derived_instance->FindInstanceInPrototypeChain(derived))); CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty()); // other_instance is an instance of other and its immediate // prototype derived_instance2 is an instance of base and derived. // Note, derived_instance is an instance of base and derived too, // but it comes after derived_instance2 in the prototype chain of // other_instance. CHECK(derived_instance2->Equals( other_instance->FindInstanceInPrototypeChain(base))); CHECK(derived_instance2->Equals( other_instance->FindInstanceInPrototypeChain(derived))); CHECK(other_instance->Equals( other_instance->FindInstanceInPrototypeChain(other)));}THREADED_TEST(TinyInteger) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); int32_t value = 239; Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); value_obj = v8::Integer::New(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());}THREADED_TEST(BigSmiInteger) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Isolate* isolate = CcTest::isolate(); int32_t value = i::Smi::kMaxValue; // We cannot add one to a Smi::kMaxValue without wrapping. if (i::SmiValuesAre31Bits()) { CHECK(i::Smi::IsValid(value)); CHECK(!i::Smi::IsValid(value + 1)); Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); value_obj = v8::Integer::New(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); }}THREADED_TEST(BigInteger) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Isolate* isolate = CcTest::isolate(); // We cannot add one to a Smi::kMaxValue without wrapping. if (i::SmiValuesAre31Bits()) { // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1. // The code will not be run in that case, due to the "if" guard. int32_t value = static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1); CHECK(value > i::Smi::kMaxValue); CHECK(!i::Smi::IsValid(value)); Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); value_obj = v8::Integer::New(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); }}THREADED_TEST(TinyUnsignedInteger) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Isolate* isolate = CcTest::isolate(); uint32_t value = 239; Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); value_obj = v8::Integer::NewFromUnsigned(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());}THREADED_TEST(BigUnsignedSmiInteger) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Isolate* isolate = CcTest::isolate(); uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue); CHECK(i::Smi::IsValid(value)); CHECK(!i::Smi::IsValid(value + 1)); Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); value_obj = v8::Integer::NewFromUnsigned(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());}THREADED_TEST(BigUnsignedInteger) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Isolate* isolate = CcTest::isolate(); uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1; CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue)); CHECK(!i::Smi::IsValid(value)); Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); value_obj = v8::Integer::NewFromUnsigned(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());}THREADED_TEST(OutOfSignedRangeUnsignedInteger) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Isolate* isolate = CcTest::isolate(); uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1; uint32_t value = INT32_MAX_AS_UINT + 1; CHECK(value > INT32_MAX_AS_UINT); // No overflow. Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); value_obj = v8::Integer::NewFromUnsigned(isolate, value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());}THREADED_TEST(IsNativeError) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Handle<Value> syntax_error = CompileRun( "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; "); CHECK(syntax_error->IsNativeError()); v8::Handle<Value> not_error = CompileRun("{a:42}"); CHECK(!not_error->IsNativeError()); v8::Handle<Value> not_object = CompileRun("42"); CHECK(!not_object->IsNativeError());}THREADED_TEST(IsGeneratorFunctionOrObject) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); CompileRun("function *gen() { yield 1; }\nfunction func() {}"); v8::Handle<Value> gen = CompileRun("gen"); v8::Handle<Value> genObj = CompileRun("gen()"); v8::Handle<Value> object = CompileRun("{a:42}"); v8::Handle<Value> func = CompileRun("func"); CHECK(gen->IsGeneratorFunction()); CHECK(gen->IsFunction()); CHECK(!gen->IsGeneratorObject()); CHECK(!genObj->IsGeneratorFunction()); CHECK(!genObj->IsFunction()); CHECK(genObj->IsGeneratorObject()); CHECK(!object->IsGeneratorFunction()); CHECK(!object->IsFunction()); CHECK(!object->IsGeneratorObject()); CHECK(!func->IsGeneratorFunction()); CHECK(func->IsFunction()); CHECK(!func->IsGeneratorObject());}THREADED_TEST(ArgumentsObject) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Handle<Value> arguments_object = CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;"); CHECK(arguments_object->IsArgumentsObject()); v8::Handle<Value> array = CompileRun("[1,2,3]"); CHECK(!array->IsArgumentsObject()); v8::Handle<Value> object = CompileRun("{a:42}"); CHECK(!object->IsArgumentsObject());}THREADED_TEST(IsMapOrSet) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Handle<Value> map = CompileRun("new Map()"); v8::Handle<Value> set = CompileRun("new Set()"); v8::Handle<Value> weak_map = CompileRun("new WeakMap()"); v8::Handle<Value> weak_set = CompileRun("new WeakSet()"); CHECK(map->IsMap()); CHECK(set->IsSet()); CHECK(weak_map->IsWeakMap()); CHECK(weak_set->IsWeakSet()); CHECK(!map->IsSet()); CHECK(!map->IsWeakMap()); CHECK(!map->IsWeakSet()); CHECK(!set->IsMap()); CHECK(!set->IsWeakMap()); CHECK(!set->IsWeakSet()); CHECK(!weak_map->IsMap()); CHECK(!weak_map->IsSet()); CHECK(!weak_map->IsWeakSet()); CHECK(!weak_set->IsMap()); CHECK(!weak_set->IsSet()); CHECK(!weak_set->IsWeakMap()); v8::Handle<Value> object = CompileRun("{a:42}"); CHECK(!object->IsMap()); CHECK(!object->IsSet()); CHECK(!object->IsWeakMap()); CHECK(!object->IsWeakSet());}THREADED_TEST(StringObject) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")"); CHECK(boxed_string->IsStringObject()); v8::Handle<Value> unboxed_string = CompileRun("\"test\""); CHECK(!unboxed_string->IsStringObject()); v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)"); CHECK(!boxed_not_string->IsStringObject()); v8::Handle<Value> not_object = CompileRun("0"); CHECK(!not_object->IsStringObject()); v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>(); CHECK(!as_boxed.IsEmpty()); Local<v8::String> the_string = as_boxed->ValueOf(); CHECK(!the_string.IsEmpty()); ExpectObject("\"test\"", the_string); v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string); CHECK(new_boxed_string->IsStringObject()); as_boxed = new_boxed_string.As<v8::StringObject>(); the_string = as_boxed->ValueOf(); CHECK(!the_string.IsEmpty()); ExpectObject("\"test\"", the_string);}TEST(StringObjectDelete) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")"); CHECK(boxed_string->IsStringObject()); v8::Handle<v8::Object> str_obj = boxed_string.As<v8::Object>(); CHECK(!str_obj->Delete(2)); CHECK(!str_obj->Delete(v8_num(2)));}THREADED_TEST(NumberObject) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Handle<Value> boxed_number = CompileRun("new Number(42)"); CHECK(boxed_number->IsNumberObject()); v8::Handle<Value> unboxed_number = CompileRun("42"); CHECK(!unboxed_number->IsNumberObject()); v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)"); CHECK(!boxed_not_number->IsNumberObject()); v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>(); CHECK(!as_boxed.IsEmpty()); double the_number = as_boxed->ValueOf(); CHECK_EQ(42.0, the_number); v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(env->GetIsolate(), 43); CHECK(new_boxed_number->IsNumberObject()); as_boxed = new_boxed_number.As<v8::NumberObject>(); the_number = as_boxed->ValueOf(); CHECK_EQ(43.0, the_number);}THREADED_TEST(BooleanObject) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)"); CHECK(boxed_boolean->IsBooleanObject()); v8::Handle<Value> unboxed_boolean = CompileRun("true"); CHECK(!unboxed_boolean->IsBooleanObject()); v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)"); CHECK(!boxed_not_boolean->IsBooleanObject()); v8::Handle<v8::BooleanObject> as_boxed = boxed_boolean.As<v8::BooleanObject>(); CHECK(!as_boxed.IsEmpty()); bool the_boolean = as_boxed->ValueOf(); CHECK_EQ(true, the_boolean); v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true); v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false); CHECK(boxed_true->IsBooleanObject()); CHECK(boxed_false->IsBooleanObject()); as_boxed = boxed_true.As<v8::BooleanObject>(); CHECK_EQ(true, as_boxed->ValueOf()); as_boxed = boxed_false.As<v8::BooleanObject>(); CHECK_EQ(false, as_boxed->ValueOf());}THREADED_TEST(PrimitiveAndWrappedBooleans) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false); CHECK(primitive_false->IsBoolean()); CHECK(!primitive_false->IsBooleanObject()); CHECK(!primitive_false->BooleanValue()); CHECK(!primitive_false->IsTrue()); CHECK(primitive_false->IsFalse()); Local<Value> false_value = BooleanObject::New(false); CHECK(!false_value->IsBoolean()); CHECK(false_value->IsBooleanObject()); CHECK(false_value->BooleanValue()); CHECK(!false_value->IsTrue()); CHECK(!false_value->IsFalse()); Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>(); CHECK(!false_boolean_object->IsBoolean()); CHECK(false_boolean_object->IsBooleanObject()); // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted. // CHECK(false_boolean_object->BooleanValue()); CHECK(!false_boolean_object->ValueOf()); CHECK(!false_boolean_object->IsTrue()); CHECK(!false_boolean_object->IsFalse()); Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true); CHECK(primitive_true->IsBoolean()); CHECK(!primitive_true->IsBooleanObject()); CHECK(primitive_true->BooleanValue()); CHECK(primitive_true->IsTrue()); CHECK(!primitive_true->IsFalse()); Local<Value> true_value = BooleanObject::New(true); CHECK(!true_value->IsBoolean()); CHECK(true_value->IsBooleanObject()); CHECK(true_value->BooleanValue()); CHECK(!true_value->IsTrue()); CHECK(!true_value->IsFalse()); Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>(); CHECK(!true_boolean_object->IsBoolean()); CHECK(true_boolean_object->IsBooleanObject()); // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted. // CHECK(true_boolean_object->BooleanValue()); CHECK(true_boolean_object->ValueOf()); CHECK(!true_boolean_object->IsTrue()); CHECK(!true_boolean_object->IsFalse());}THREADED_TEST(Number) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); double PI = 3.1415926; Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI); CHECK_EQ(PI, pi_obj->NumberValue());}THREADED_TEST(ToNumber) { LocalContext env; v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); Local<String> str = v8_str("3.1415926"); CHECK_EQ(3.1415926, str->NumberValue()); v8::Handle<v8::Boolean> t = v8::True(isolate); CHECK_EQ(1.0, t->NumberValue()); v8::Handle<v8::Boolean> f = v8::False(isolate); CHECK_EQ(0.0, f->NumberValue());}THREADED_TEST(Date) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); double PI = 3.1415926; Local<Value> date = v8::Date::New(env->GetIsolate(), PI); CHECK_EQ(3.0, date->NumberValue()); date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(env->GetIsolate(), 42)); CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());}THREADED_TEST(Boolean) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); v8::Handle<v8::Boolean> t = v8::True(isolate); CHECK(t->Value()); v8::Handle<v8::Boolean> f = v8::False(isolate); CHECK(!f->Value()); v8::Handle<v8::Primitive> u = v8::Undefined(isolate); CHECK(!u->BooleanValue()); v8::Handle<v8::Primitive> n = v8::Null(isolate); CHECK(!n->BooleanValue()); v8::Handle<String> str1 = v8_str(""); CHECK(!str1->BooleanValue()); v8::Handle<String> str2 = v8_str("x"); CHECK(str2->BooleanValue()); CHECK(!v8::Number::New(isolate, 0)->BooleanValue()); CHECK(v8::Number::New(isolate, -1)->BooleanValue()); CHECK(v8::Number::New(isolate, 1)->BooleanValue()); CHECK(v8::Number::New(isolate, 42)->BooleanValue()); CHECK(!v8_compile("NaN")->Run()->BooleanValue());}static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) { ApiTestFuzzer::Fuzz(); args.GetReturnValue().Set(v8_num(13.4));}static void GetM(Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { ApiTestFuzzer::Fuzz(); info.GetReturnValue().Set(v8_num(876));}THREADED_TEST(GlobalPrototype) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New(isolate); func_templ->PrototypeTemplate()->Set( isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler)); v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate(); templ->Set(isolate, "x", v8_num(200)); templ->SetAccessor(v8_str("m"), GetM); LocalContext env(0, templ); v8::Handle<Script> script(v8_compile("dummy()")); v8::Handle<Value> result(script->Run()); CHECK_EQ(13.4, result->NumberValue()); CHECK_EQ(200, v8_compile("x")->Run()->Int32Value()); CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());}THREADED_TEST(ObjectTemplate) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); v8::Local<v8::String> class_name = v8::String::NewFromUtf8(isolate, "the_class_name"); fun->SetClassName(class_name); Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun); templ1->Set(isolate, "x", v8_num(10)); templ1->Set(isolate, "y", v8_num(13)); LocalContext env; Local<v8::Object> instance1 = templ1->NewInstance(); CHECK(class_name->StrictEquals(instance1->GetConstructorName())); env->Global()->Set(v8_str("p"), instance1); CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue()); CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue()); Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate); fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123)); Local<ObjectTemplate> templ2 = fun2->InstanceTemplate(); templ2->Set(isolate, "a", v8_num(12)); templ2->Set(isolate, "b", templ1); Local<v8::Object> instance2 = templ2->NewInstance(); env->Global()->Set(v8_str("q"), instance2); CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue()); CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue()); CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue()); CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());}static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) { ApiTestFuzzer::Fuzz(); args.GetReturnValue().Set(v8_num(17.2));}static void GetKnurd(Local<String> property, const v8::PropertyCallbackInfo<v8::Value>& info) { ApiTestFuzzer::Fuzz(); info.GetReturnValue().Set(v8_num(15.2));}THREADED_TEST(DescriptorInheritance) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate); super->PrototypeTemplate()->Set(isolate, "flabby", v8::FunctionTemplate::New(isolate, GetFlabby)); super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14)); super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd); v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate); base1->Inherit(super); base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1)); v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate); base2->Inherit(super); base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1)); LocalContext env; env->Global()->Set(v8_str("s"), super->GetFunction()); env->Global()->Set(v8_str("base1"), base1->GetFunction()); env->Global()->Set(v8_str("base2"), base2->GetFunction()); // Checks right __proto__ chain. CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue()); CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue()); CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue()); // Instance accessor should not be visible on function object or its prototype CHECK(CompileRun("s.knurd == undefined")->BooleanValue()); CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue()); CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue()); env->Global()->Set(v8_str("obj"), base1->GetFunction()->NewInstance()); CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue()); CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue()); CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue()); CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue()); CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue()); env->Global()->Set(v8_str("obj2"), base2->GetFunction()->NewInstance()); CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue()); CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue()); CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue()); CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue()); CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue()); // base1 and base2 cannot cross reference to each's prototype CHECK(v8_compile("obj.v2")->Run()->IsUndefined()); CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());}// Helper functions for Interceptor/Accessor interaction testsvoid SimpleAccessorGetter(Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { Handle<Object> self = Handle<Object>::Cast(info.This()); info.GetReturnValue().Set( self->Get(String::Concat(v8_str("accessor_"), name)));}void SimpleAccessorSetter(Local<String> name, Local<Value> value, const v8::PropertyCallbackInfo<void>& info) { Handle<Object> self = Handle<Object>::Cast(info.This()); self->Set(String::Concat(v8_str("accessor_"), name), value);}void SymbolAccessorGetter(Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { CHECK(name->IsSymbol()); Local<Symbol> sym = Local<Symbol>::Cast(name); if (sym->Name()->IsUndefined()) return; SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);}void SymbolAccessorSetter(Local<Name> name, Local<Value> value, const v8::PropertyCallbackInfo<void>& info) { CHECK(name->IsSymbol()); Local<Symbol> sym = Local<Symbol>::Cast(name); if (sym->Name()->IsUndefined()) return; SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);}void SymbolAccessorGetterReturnsDefault( Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { CHECK(name->IsSymbol()); Local<Symbol> sym = Local<Symbol>::Cast(name); if (sym->Name()->IsUndefined()) return; info.GetReturnValue().Set(info.Data());}static void ThrowingSymbolAccessorGetter( Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));}THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); LocalContext env; v8::Local<v8::Value> res = CompileRun("var a = []; a;"); i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res))); CHECK(a->map()->instance_descriptors()->IsFixedArray()); CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); CompileRun("Object.defineProperty(a, 'length', { writable: false });"); CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); // But we should still have an ExecutableAccessorInfo. i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length"))); i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR); CHECK_EQ(i::LookupIterator::ACCESSOR, it.state()); CHECK(it.GetAccessors()->IsExecutableAccessorInfo());}THREADED_TEST(UndefinedIsNotEnumerable) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)"); CHECK(result->IsFalse());}v8::Handle<Script> call_recursively_script;static const int kTargetRecursionDepth = 200; // near maximumstatic void CallScriptRecursivelyCall( const v8::FunctionCallbackInfo<v8::Value>& args) { ApiTestFuzzer::Fuzz(); int depth = args.This()->Get(v8_str("depth"))->Int32Value(); if (depth == kTargetRecursionDepth) return; args.This()->Set(v8_str("depth"), v8::Integer::New(args.GetIsolate(), depth + 1)); args.GetReturnValue().Set(call_recursively_script->Run());}static void CallFunctionRecursivelyCall( const v8::FunctionCallbackInfo<v8::Value>& args) { ApiTestFuzzer::Fuzz(); int depth = args.This()->Get(v8_str("depth"))->Int32Value(); if (depth == kTargetRecursionDepth) { printf("[depth = %d]\n", depth); return; } args.This()->Set(v8_str("depth"), v8::Integer::New(args.GetIsolate(), depth + 1)); v8::Handle<Value> function = args.This()->Get(v8_str("callFunctionRecursively")); args.GetReturnValue().Set( function.As<Function>()->Call(args.This(), 0, NULL));}THREADED_TEST(DeepCrossLanguageRecursion) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate); global->Set(v8_str("callScriptRecursively"), v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall)); global->Set(v8_str("callFunctionRecursively"), v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall)); LocalContext env(NULL, global); env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0)); call_recursively_script = v8_compile("callScriptRecursively()"); call_recursively_script->Run(); call_recursively_script = v8::Handle<Script>(); env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0)); CompileRun("callFunctionRecursively()");}static void ThrowingPropertyHandlerGet( Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) { // Since this interceptor is used on "with" objects, the runtime will look up // @@unscopables. Punt. if (key->IsSymbol()) return; ApiTestFuzzer::Fuzz(); info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));}static void ThrowingPropertyHandlerSet( Local<Name> key, Local<Value>, const v8::PropertyCallbackInfo<v8::Value>& info) { info.GetIsolate()->ThrowException(key); info.GetReturnValue().SetUndefined(); // not the same as empty handle}THREADED_TEST(CallbackExceptionRegression) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); obj->SetHandler(v8::NamedPropertyHandlerConfiguration( ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet)); LocalContext env; env->Global()->Set(v8_str("obj"), obj->NewInstance()); v8::Handle<Value> otto = CompileRun("try { with (obj) { otto; } } catch (e) { e; }"); CHECK(v8_str("otto")->Equals(otto)); v8::Handle<Value> netto = CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }"); CHECK(v8_str("netto")->Equals(netto));}THREADED_TEST(FunctionPrototype) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate); Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321)); LocalContext env; env->Global()->Set(v8_str("Foo"), Foo->GetFunction()); Local<Script> script = v8_compile("Foo.prototype.plak"); CHECK_EQ(script->Run()->Int32Value(), 321);}THREADED_TEST(InternalFields) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); instance_templ->SetInternalFieldCount(1); Local<v8::Object> obj = templ->GetFunction()->NewInstance(); CHECK_EQ(1, obj->InternalFieldCount()); CHECK(obj->GetInternalField(0)->IsUndefined()); obj->SetInternalField(0, v8_num(17)); CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());}THREADED_TEST(GlobalObjectInternalFields) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); global_template->SetInternalFieldCount(1); LocalContext env(NULL, global_template); v8::Handle<v8::Object> global_proxy = env->Global(); v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>(); CHECK_EQ(1, global->InternalFieldCount()); CHECK(global->GetInternalField(0)->IsUndefined()); global->SetInternalField(0, v8_num(17)); CHECK_EQ(17, global->GetInternalField(0)->Int32Value());}THREADED_TEST(GlobalObjectHasRealIndexedProperty) { LocalContext env; v8::HandleScope scope(CcTest::isolate()); v8::Local<v8::Object> global = env->Global(); global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value")); CHECK(global->HasRealIndexedProperty(0));}static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj, void* value) { CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); obj->SetAlignedPointerInInternalField(0, value); CcTest::heap()->CollectAllGarbage(); CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));}THREADED_TEST(InternalFieldsAlignedPointers) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); instance_templ->SetInternalFieldCount(1); Local<v8::Object> obj = templ->GetFunction()->NewInstance(); CHECK_EQ(1, obj->InternalFieldCount()); CheckAlignedPointerInInternalField(obj, NULL); int* heap_allocated = new int[100]; CheckAlignedPointerInInternalField(obj, heap_allocated); delete[] heap_allocated; int stack_allocated[100]; CheckAlignedPointerInInternalField(obj, stack_allocated); void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); CheckAlignedPointerInInternalField(obj, huge); v8::Global<v8::Object> persistent(isolate, obj); CHECK_EQ(1, Object::InternalFieldCount(persistent)); CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));}static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index, void* value) { CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); (*env)->SetAlignedPointerInEmbedderData(index, value); CcTest::heap()->CollectAllGarbage(); CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));}static void* AlignedTestPointer(int i) { return reinterpret_cast<void*>(i * 1234);}THREADED_TEST(EmbedderDataAlignedPointers) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); CheckAlignedPointerInEmbedderData(&env, 0, NULL); int* heap_allocated = new int[100]; CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated); delete[] heap_allocated; int stack_allocated[100]; CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated); void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); CheckAlignedPointerInEmbedderData(&env, 3, huge); // Test growing of the embedder data's backing store. for (int i = 0; i < 100; i++) { env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i)); } CcTest::heap()->CollectAllGarbage(); for (int i = 0; i < 100; i++) { CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i)); }}static void CheckEmbedderData(LocalContext* env, int index, v8::Handle<Value> data) { (*env)->SetEmbedderData(index, data);

Read the original on chromium.googlesource.com ↗