#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/snapshot.h"
#include "src/unicode-inl.h"
#include "src/utils.h"
#include "src/vm-state.h"
using ::v8::Handle;
using ::v8::HandleScope;
using ::v8::Local;
-using ::v8::Name;
+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;
signature_callback_count = 0;
signature_expected_receiver = receiver;
bool expected_to_throw = receiver.IsEmpty();
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(source.start());
CHECK_EQ(expected_to_throw, try_catch.HasCaught());
if (!expected_to_throw) {
CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
source->GetExternalStringResourceBase(&encoding));
CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(0, dispose_count);
}
CcTest::i_isolate()->compilation_cache()->Clear();
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(0, dispose_count);
}
CcTest::i_isolate()->compilation_cache()->Clear();
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(0, dispose_count);
}
CcTest::i_isolate()->compilation_cache()->Clear();
- CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(1, dispose_count);
}
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(0, dispose_count);
}
CcTest::i_isolate()->compilation_cache()->Clear();
- CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(1, dispose_count);
}
"slice('abcdefghijklmnopqrstuvwxyz');"));
// Trigger GCs so that the newly allocated string moves to old gen.
- SimulateFullSpace(CcTest::heap()->old_pointer_space());
+ 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
CHECK(success);
// Trigger GCs and force evacuation.
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
}
factory->InternalizeString(istring);
CHECK(isymbol->IsInternalizedString());
}
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
+ CcTest::heap()->CollectAllGarbage();
}
factory->InternalizeString(istring);
CHECK(isymbol->IsInternalizedString());
}
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
+ CcTest::heap()->CollectAllGarbage();
}
THREADED_TEST(NewExternalForVeryLongString) {
+ auto isolate = CcTest::isolate();
{
- LocalContext env;
- v8::HandleScope scope(env->GetIsolate());
- v8::TryCatch try_catch;
+ v8::HandleScope scope(isolate);
+ v8::TryCatch try_catch(isolate);
RandomLengthOneByteResource r(1 << 30);
- v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
+ v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
CHECK(str.IsEmpty());
- CHECK(try_catch.HasCaught());
- String::Utf8Value exception_value(try_catch.Exception());
- CHECK_EQ(0, strcmp("RangeError: Invalid string length", *exception_value));
+ CHECK(!try_catch.HasCaught());
}
{
- LocalContext env;
- v8::HandleScope scope(env->GetIsolate());
- v8::TryCatch try_catch;
+ v8::HandleScope scope(isolate);
+ v8::TryCatch try_catch(isolate);
RandomLengthResource r(1 << 30);
- v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
+ v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
CHECK(str.IsEmpty());
- CHECK(try_catch.HasCaught());
- String::Utf8Value exception_value(try_catch.Exception());
- CHECK_EQ(0, strcmp("RangeError: Invalid string length", *exception_value));
+ CHECK(!try_catch.HasCaught());
}
}
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_data_space()->Contains(*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_DATA_SPACE);
+ CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
CHECK_EQ(1, 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_data_space()->Contains(*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_DATA_SPACE);
+ CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
CHECK_EQ(1, dispose_count);
}
CHECK_EQ(68, value->Int32Value());
}
CcTest::i_isolate()->compilation_cache()->Clear();
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
+ CcTest::heap()->CollectAllGarbage();
}
}
+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());
THREADED_TEST(ObjectTemplate) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
- Local<ObjectTemplate> templ1 = ObjectTemplate::New(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> fun = v8::FunctionTemplate::New(isolate);
- fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
- Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
+ 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();
void* value) {
CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
obj->SetAlignedPointerInInternalField(0, value);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
}
void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
CheckAlignedPointerInInternalField(obj, huge);
- v8::UniquePersistent<v8::Object> persistent(isolate, obj);
+ v8::Global<v8::Object> persistent(isolate, obj);
CHECK_EQ(1, Object::InternalFieldCount(persistent));
CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
}
void* value) {
CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
(*env)->SetAlignedPointerInEmbedderData(index, value);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
}
for (int i = 0; i < 100; i++) {
env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
}
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
for (int i = 0; i < 100; i++) {
CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
}
// Ensure that the test starts with an fresh heap to test whether the hash
// code is based on the address.
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
Local<v8::Object> obj = v8::Object::New(isolate);
int hash = obj->GetIdentityHash();
int hash1 = obj->GetIdentityHash();
// objects should not be assigned the same hash code. If the test below fails
// the random number generator should be evaluated.
CHECK_NE(hash, hash2);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
int hash3 = v8::Object::New(isolate)->GetIdentityHash();
// Make sure that the identity hash is not based on the initial address of
// the object alone. If the test below fails the random number generator
}
-THREADED_TEST(GlobalProxyIdentityHash) {
+void GlobalProxyIdentityHash(bool set_in_js) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
v8::HandleScope scope(isolate);
Handle<Object> global_proxy = env->Global();
- int hash1 = global_proxy->GetIdentityHash();
+ i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy);
+ env->Global()->Set(v8_str("global"), global_proxy);
+ i::Handle<i::Object> original_hash;
+ if (set_in_js) {
+ CompileRun("var m = new Set(); m.add(global);");
+ original_hash = i::Handle<i::Object>(i_global_proxy->GetHash(), i_isolate);
+ } else {
+ original_hash = i::Handle<i::Object>(
+ i::Object::GetOrCreateHash(i_isolate, i_global_proxy));
+ }
+ CHECK(original_hash->IsSmi());
+ int32_t hash1 = i::Handle<i::Smi>::cast(original_hash)->value();
// Hash should be retained after being detached.
env->DetachGlobal();
int hash2 = global_proxy->GetIdentityHash();
}
+THREADED_TEST(GlobalProxyIdentityHash) {
+ GlobalProxyIdentityHash(true);
+ GlobalProxyIdentityHash(false);
+}
+
+
TEST(SymbolIdentityHash) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
int hash = symbol->GetIdentityHash();
int hash1 = symbol->GetIdentityHash();
CHECK_EQ(hash, hash1);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
int hash3 = symbol->GetIdentityHash();
CHECK_EQ(hash, hash3);
}
int hash = js_symbol->GetIdentityHash();
int hash1 = js_symbol->GetIdentityHash();
CHECK_EQ(hash, hash1);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
int hash3 = js_symbol->GetIdentityHash();
CHECK_EQ(hash, hash3);
}
int hash = str->GetIdentityHash();
int hash1 = str->GetIdentityHash();
CHECK_EQ(hash, hash1);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
int hash3 = str->GetIdentityHash();
CHECK_EQ(hash, hash3);
v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
// Check basic symbol functionality.
CHECK(sym1->IsSymbol());
CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
CHECK(obj->Get(sym3)->IsUndefined());
}
-THREADED_TEST(PrivateProperties) {
- LocalContext env;
- v8::Isolate* isolate = env->GetIsolate();
- v8::HandleScope scope(isolate);
-
- v8::Local<v8::Object> obj = v8::Object::New(isolate);
- v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
- v8::Local<v8::Private> priv2 =
- v8::Private::New(isolate, v8_str("my-private"));
-
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
-
- CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
-
- // Make sure delete of a non-existent private symbol property works.
- CHECK(obj->DeletePrivate(priv1));
- CHECK(!obj->HasPrivate(priv1));
-
- CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
- CHECK(obj->HasPrivate(priv1));
- CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
- CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
- CHECK(obj->HasPrivate(priv1));
- CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
-
- CHECK_EQ(0u, obj->GetOwnPropertyNames()->Length());
- unsigned num_props = obj->GetPropertyNames()->Length();
- CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
- v8::Integer::New(isolate, 20)));
- CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
- CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
-
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
-
- // Add another property and delete it afterwards to force the object in
- // slow case.
- CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
- CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
- CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
- CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
- CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
-
- CHECK(obj->HasPrivate(priv1));
- CHECK(obj->HasPrivate(priv2));
- CHECK(obj->DeletePrivate(priv2));
- CHECK(obj->HasPrivate(priv1));
- CHECK(!obj->HasPrivate(priv2));
- CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
- CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
-
- // Private properties are inherited (for the time being).
- v8::Local<v8::Object> child = v8::Object::New(isolate);
- child->SetPrototype(obj);
- CHECK(child->HasPrivate(priv1));
- CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
- CHECK_EQ(0u, child->GetOwnPropertyNames()->Length());
-}
-
-
THREADED_TEST(GlobalSymbols) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
}
-THREADED_TEST(GlobalPrivates) {
- LocalContext env;
- v8::Isolate* isolate = env->GetIsolate();
- v8::HandleScope scope(isolate);
-
- v8::Local<String> name = v8_str("my-private");
- v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
- v8::Local<v8::Object> obj = v8::Object::New(isolate);
- CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
-
- v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
- CHECK(obj->HasPrivate(glob2));
-
- v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
- CHECK(!obj->HasPrivate(priv));
-
- CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
- v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
- CHECK(!obj->Has(intern));
-}
-
-
class ScopedArrayBufferContents {
public:
explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
CheckInternalFieldsAreZero(ab);
CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
CHECK(!ab->IsExternal());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
ScopedArrayBufferContents ab_contents(ab->Externalize());
CHECK(ab->IsExternal());
}
+class ScopedSharedArrayBufferContents {
+ public:
+ explicit ScopedSharedArrayBufferContents(
+ const v8::SharedArrayBuffer::Contents& contents)
+ : contents_(contents) {}
+ ~ScopedSharedArrayBufferContents() { free(contents_.Data()); }
+ void* Data() const { return contents_.Data(); }
+ size_t ByteLength() const { return contents_.ByteLength(); }
+
+ private:
+ const v8::SharedArrayBuffer::Contents contents_;
+};
+
+
+THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+
+ Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024);
+ CheckInternalFieldsAreZero(ab);
+ CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
+ CHECK(!ab->IsExternal());
+ CcTest::heap()->CollectAllGarbage();
+
+ ScopedSharedArrayBufferContents ab_contents(ab->Externalize());
+ CHECK(ab->IsExternal());
+
+ CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
+ uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
+ DCHECK(data != NULL);
+ env->Global()->Set(v8_str("ab"), ab);
+
+ v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
+ CHECK_EQ(1024, result->Int32Value());
+
+ result = CompileRun(
+ "var u8 = new Uint8Array(ab);"
+ "u8[0] = 0xFF;"
+ "u8[1] = 0xAA;"
+ "u8.length");
+ CHECK_EQ(1024, result->Int32Value());
+ CHECK_EQ(0xFF, data[0]);
+ CHECK_EQ(0xAA, data[1]);
+ data[0] = 0xCC;
+ data[1] = 0x11;
+ result = CompileRun("u8[0] + u8[1]");
+ CHECK_EQ(0xDD, result->Int32Value());
+}
+
+
+THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+
+
+ v8::Local<v8::Value> result = CompileRun(
+ "var ab1 = new SharedArrayBuffer(2);"
+ "var u8_a = new Uint8Array(ab1);"
+ "u8_a[0] = 0xAA;"
+ "u8_a[1] = 0xFF; u8_a.buffer");
+ Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result);
+ CheckInternalFieldsAreZero(ab1);
+ CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
+ CHECK(!ab1->IsExternal());
+ ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize());
+ CHECK(ab1->IsExternal());
+
+ result = CompileRun("ab1.byteLength");
+ CHECK_EQ(2, result->Int32Value());
+ result = CompileRun("u8_a[0]");
+ CHECK_EQ(0xAA, result->Int32Value());
+ result = CompileRun("u8_a[1]");
+ CHECK_EQ(0xFF, result->Int32Value());
+ result = CompileRun(
+ "var u8_b = new Uint8Array(ab1);"
+ "u8_b[0] = 0xBB;"
+ "u8_a[0]");
+ CHECK_EQ(0xBB, result->Int32Value());
+ result = CompileRun("u8_b[1]");
+ CHECK_EQ(0xFF, result->Int32Value());
+
+ CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
+ uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
+ CHECK_EQ(0xBB, ab1_data[0]);
+ CHECK_EQ(0xFF, ab1_data[1]);
+ ab1_data[0] = 0xCC;
+ ab1_data[1] = 0x11;
+ result = CompileRun("u8_a[0] + u8_a[1]");
+ CHECK_EQ(0xDD, result->Int32Value());
+}
+
+
+THREADED_TEST(SharedArrayBuffer_External) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+
+ i::ScopedVector<uint8_t> my_data(100);
+ memset(my_data.start(), 0, 100);
+ Local<v8::SharedArrayBuffer> ab3 =
+ v8::SharedArrayBuffer::New(isolate, my_data.start(), 100);
+ CheckInternalFieldsAreZero(ab3);
+ CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
+ CHECK(ab3->IsExternal());
+
+ env->Global()->Set(v8_str("ab3"), ab3);
+
+ v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
+ CHECK_EQ(100, result->Int32Value());
+
+ result = CompileRun(
+ "var u8_b = new Uint8Array(ab3);"
+ "u8_b[0] = 0xBB;"
+ "u8_b[1] = 0xCC;"
+ "u8_b.length");
+ CHECK_EQ(100, result->Int32Value());
+ CHECK_EQ(0xBB, my_data[0]);
+ CHECK_EQ(0xCC, my_data[1]);
+ my_data[0] = 0xCC;
+ my_data[1] = 0x11;
+ result = CompileRun("u8_b[0] + u8_b[1]");
+ CHECK_EQ(0xDD, result->Int32Value());
+}
+
+
THREADED_TEST(HiddenProperties) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::Local<v8::String> empty = v8_str("");
v8::Local<v8::String> prop_name = v8_str("prop_name");
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
// Make sure delete of a non-existent hidden value works
CHECK(obj->DeleteHiddenValue(key));
CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
// Make sure we do not find the hidden property.
CHECK(!obj->Has(empty));
CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
CHECK_EQ(2003, obj->Get(empty)->Int32Value());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
// Add another property and delete it afterwards to force the object in
// slow case.
CHECK(obj->Delete(prop_name));
CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK(obj->SetHiddenValue(key, Handle<Value>()));
CHECK(obj->GetHiddenValue(key).IsEmpty());
template <class T>
-static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
+static v8::Global<T> PassUnique(v8::Global<T> unique) {
return unique.Pass();
}
template <class T>
-static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
- const v8::Persistent<T>& global) {
- v8::UniquePersistent<String> unique(isolate, global);
+static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
+ const v8::Persistent<T>& global) {
+ v8::Global<String> unique(isolate, global);
return unique.Pass();
}
-THREADED_TEST(UniquePersistent) {
+THREADED_TEST(Global) {
v8::Isolate* isolate = CcTest::isolate();
v8::Persistent<String> global;
{
reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
int initial_handle_count = global_handles->global_handles_count();
{
- v8::UniquePersistent<String> unique(isolate, global);
+ v8::Global<String> unique(isolate, global);
CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
// Test assignment via Pass
{
- v8::UniquePersistent<String> copy = unique.Pass();
+ v8::Global<String> copy = unique.Pass();
CHECK(unique.IsEmpty());
CHECK(copy == global);
CHECK_EQ(initial_handle_count + 1,
}
// Test ctor via Pass
{
- v8::UniquePersistent<String> copy(unique.Pass());
+ v8::Global<String> copy(unique.Pass());
CHECK(unique.IsEmpty());
CHECK(copy == global);
CHECK_EQ(initial_handle_count + 1,
}
// Test pass through function call
{
- v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
+ v8::Global<String> copy = PassUnique(unique.Pass());
CHECK(unique.IsEmpty());
CHECK(copy == global);
CHECK_EQ(initial_handle_count + 1,
}
// Test pass from function call
{
- v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
+ v8::Global<String> unique = ReturnUnique(isolate, global);
CHECK(unique == global);
CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
}
}
+namespace {
+
+class TwoPassCallbackData;
+void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
+void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
+
+
+class TwoPassCallbackData {
+ public:
+ TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
+ : first_pass_called_(false),
+ second_pass_called_(false),
+ trigger_gc_(false),
+ instance_counter_(instance_counter) {
+ HandleScope scope(isolate);
+ i::ScopedVector<char> buffer(40);
+ i::SNPrintF(buffer, "%p", static_cast<void*>(this));
+ auto string =
+ v8::String::NewFromUtf8(isolate, buffer.start(),
+ v8::NewStringType::kNormal).ToLocalChecked();
+ cell_.Reset(isolate, string);
+ (*instance_counter_)++;
+ }
+
+ ~TwoPassCallbackData() {
+ CHECK(first_pass_called_);
+ CHECK(second_pass_called_);
+ CHECK(cell_.IsEmpty());
+ (*instance_counter_)--;
+ }
+
+ void FirstPass() {
+ CHECK(!first_pass_called_);
+ CHECK(!second_pass_called_);
+ CHECK(!cell_.IsEmpty());
+ cell_.Reset();
+ first_pass_called_ = true;
+ }
+
+ void SecondPass() {
+ CHECK(first_pass_called_);
+ CHECK(!second_pass_called_);
+ CHECK(cell_.IsEmpty());
+ second_pass_called_ = true;
+ delete this;
+ }
+
+ void SetWeak() {
+ cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
+ }
+
+ void MarkTriggerGc() { trigger_gc_ = true; }
+ bool trigger_gc() { return trigger_gc_; }
+
+ int* instance_counter() { return instance_counter_; }
+
+ private:
+ bool first_pass_called_;
+ bool second_pass_called_;
+ bool trigger_gc_;
+ v8::Global<v8::String> cell_;
+ int* instance_counter_;
+};
+
+
+void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
+ ApiTestFuzzer::Fuzz();
+ bool trigger_gc = data.GetParameter()->trigger_gc();
+ int* instance_counter = data.GetParameter()->instance_counter();
+ data.GetParameter()->SecondPass();
+ if (!trigger_gc) return;
+ auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
+ data_2->SetWeak();
+ CcTest::heap()->CollectAllGarbage();
+}
+
+
+void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
+ data.GetParameter()->FirstPass();
+ data.SetSecondPassCallback(SecondPassCallback);
+}
+
+} // namespace
+
+
+TEST(TwoPassPhantomCallbacks) {
+ auto isolate = CcTest::isolate();
+ const size_t kLength = 20;
+ int instance_counter = 0;
+ for (size_t i = 0; i < kLength; ++i) {
+ auto data = new TwoPassCallbackData(isolate, &instance_counter);
+ data->SetWeak();
+ }
+ CHECK_EQ(static_cast<int>(kLength), instance_counter);
+ CcTest::heap()->CollectAllGarbage();
+ CHECK_EQ(0, instance_counter);
+}
+
+
+TEST(TwoPassPhantomCallbacksNestedGc) {
+ auto isolate = CcTest::isolate();
+ const size_t kLength = 20;
+ TwoPassCallbackData* array[kLength];
+ int instance_counter = 0;
+ for (size_t i = 0; i < kLength; ++i) {
+ array[i] = new TwoPassCallbackData(isolate, &instance_counter);
+ array[i]->SetWeak();
+ }
+ array[5]->MarkTriggerGc();
+ array[10]->MarkTriggerGc();
+ array[15]->MarkTriggerGc();
+ CHECK_EQ(static_cast<int>(kLength), instance_counter);
+ CcTest::heap()->CollectAllGarbage();
+ CHECK_EQ(0, instance_counter);
+}
+
+
+namespace {
+
+void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
+
+
+Local<v8::Object> NewObjectForIntKey(
+ v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
+ int key) {
+ auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
+ auto obj = local->NewInstance();
+ obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
+ return obj;
+}
+
+
template <typename K, typename V>
-class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
+class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
public:
- typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V>> MapType;
- static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
+ typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
+ static const v8::PersistentContainerCallbackType kCallbackType =
+ v8::kWeakWithInternalFields;
struct WeakCallbackDataType {
MapType* map;
K key;
data->key = key;
return data;
}
- static MapType* MapFromWeakCallbackData(
- const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
+ static MapType* MapFromWeakCallbackInfo(
+ const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
return data.GetParameter()->map;
}
- static K KeyFromWeakCallbackData(
- const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
+ static K KeyFromWeakCallbackInfo(
+ const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
return data.GetParameter()->key;
}
static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
- static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
- K key) {}
+ static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
+ CHECK_EQ(IntKeyToVoidPointer(key),
+ v8::Object::GetAlignedPointerFromInternalField(value, 0));
+ }
+ static void DisposeWeak(
+ const v8::WeakCallbackInfo<WeakCallbackDataType>& info) {
+ K key = KeyFromWeakCallbackInfo(info);
+ CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
+ DisposeCallbackData(info.GetParameter());
+ }
};
template <typename Map>
-static void TestPersistentValueMap() {
+void TestGlobalValueMap() {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
+ v8::Global<ObjectTemplate> templ;
+ {
+ HandleScope scope(isolate);
+ auto t = ObjectTemplate::New(isolate);
+ t->SetInternalFieldCount(1);
+ templ.Reset(isolate, t);
+ }
Map map(isolate);
v8::internal::GlobalHandles* global_handles =
reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
typename Map::PersistentValueReference ref = map.GetReference(7);
CHECK(expected->Equals(ref.NewLocal(isolate)));
}
- v8::UniquePersistent<v8::Object> removed = map.Remove(7);
+ v8::Global<v8::Object> removed = map.Remove(7);
CHECK_EQ(0, static_cast<int>(map.Size()));
CHECK(expected == removed);
removed = map.Remove(7);
CHECK_EQ(1, static_cast<int>(map.Size()));
{
typename Map::PersistentValueReference ref;
- Local<v8::Object> expected2 = v8::Object::New(isolate);
- removed = map.Set(8, v8::UniquePersistent<v8::Object>(isolate, expected2),
- &ref);
+ Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
+ removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
CHECK_EQ(1, static_cast<int>(map.Size()));
CHECK(expected == removed);
CHECK(expected2->Equals(ref.NewLocal(isolate)));
}
CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
if (map.IsWeak()) {
- reinterpret_cast<v8::internal::Isolate*>(isolate)
- ->heap()
- ->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ CcTest::i_isolate()->heap()->CollectAllGarbage(
+ i::Heap::kAbortIncrementalMarkingMask);
} else {
map.Clear();
}
CHECK_EQ(0, static_cast<int>(map.Size()));
CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
+ {
+ HandleScope scope(isolate);
+ Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
+ map.Set(9, value);
+ map.Clear();
+ }
+ CHECK_EQ(0, static_cast<int>(map.Size()));
+ CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
}
+} // namespace
-TEST(PersistentValueMap) {
+
+TEST(GlobalValueMap) {
// Default case, w/o weak callbacks:
- TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object>>();
+ TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>();
// Custom traits with weak callbacks:
- typedef v8::PersistentValueMap<int, v8::Object,
- WeakStdMapTraits<int, v8::Object>>
- WeakPersistentValueMap;
- TestPersistentValueMap<WeakPersistentValueMap>();
+ typedef v8::GlobalValueMap<int, v8::Object,
+ PhantomStdMapTraits<int, v8::Object>> WeakMap;
+ TestGlobalValueMap<WeakMap>();
}
Local<v8::Object> obj1 = v8::Object::New(isolate);
Local<v8::Object> obj2 = v8::Object::New(isolate);
- v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
+ v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
CHECK(vector.IsEmpty());
CHECK_EQ(0, static_cast<int>(vector.Size()));
template <typename T>
static void WeakPointerCallback(
- const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T>>& data) {
+ const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) {
CHECK_EQ(1234, data.GetParameter()->counter->id());
data.GetParameter()->counter->increment();
data.GetParameter()->handle.Reset();
g1s1.handle.Reset(iso, Object::New(iso));
g1s2.handle.Reset(iso, Object::New(iso));
g1c1.handle.Reset(iso, Object::New(iso));
- g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
- g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
- g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
+ g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
g2s1.handle.Reset(iso, Object::New(iso));
g2s2.handle.Reset(iso, Object::New(iso));
g2c1.handle.Reset(iso, Object::New(iso));
- g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
- g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
- g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
+ g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
}
WeakCallCounterAndPersistent<Value> root(&counter);
// Do a single full GC, ensure incremental marking is stopped.
v8::internal::Heap* heap =
reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
- heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ heap->CollectAllGarbage();
// All object should be alive.
CHECK_EQ(0, counter.NumberOfWeakCalls());
// Weaken the root.
- root.handle.SetWeak(&root, &WeakPointerCallback);
+ root.handle.SetWeak(&root, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
// But make children strong roots---all the objects (except for children)
// should be collectable now.
g1c1.handle.ClearWeak();
iso->SetReferenceFromGroup(id2, g2c1.handle);
}
- heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ heap->CollectAllGarbage();
// All objects should be gone. 5 global handles in total.
CHECK_EQ(5, counter.NumberOfWeakCalls());
// And now make children weak again and collect them.
- g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
- g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
+ g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
- heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ heap->CollectAllGarbage();
CHECK_EQ(7, counter.NumberOfWeakCalls());
}
g1s1.handle.Reset(iso, Object::New(iso));
g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
- g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
- g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
- g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
+ g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
g2s1.handle.Reset(iso, Object::New(iso));
g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
- g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
- g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
- g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
+ g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
}
WeakCallCounterAndPersistent<Value> root(&counter);
// Do a single full GC, ensure incremental marking is stopped.
v8::internal::Heap* heap =
reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
- heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ heap->CollectAllGarbage();
// All object should be alive.
CHECK_EQ(0, counter.NumberOfWeakCalls());
// Weaken the root.
- root.handle.SetWeak(&root, &WeakPointerCallback);
+ root.handle.SetWeak(&root, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
// But make children strong roots---all the objects (except for children)
// should be collectable now.
g1c1.handle.ClearWeak();
iso->SetReferenceFromGroup(id2, g2c1.handle);
}
- heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ heap->CollectAllGarbage();
// All objects should be gone. 5 global handles in total.
CHECK_EQ(5, counter.NumberOfWeakCalls());
// And now make children weak again and collect them.
- g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
- g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
+ g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
- heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ heap->CollectAllGarbage();
CHECK_EQ(7, counter.NumberOfWeakCalls());
}
HandleScope scope(iso);
g1s1.handle.Reset(iso, Object::New(iso));
g1s2.handle.Reset(iso, Object::New(iso));
- g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
- g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
+ g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
CHECK(g1s1.handle.IsWeak());
CHECK(g1s2.handle.IsWeak());
g2s1.handle.Reset(iso, Object::New(iso));
g2s2.handle.Reset(iso, Object::New(iso));
- g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
- g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
+ g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
CHECK(g2s1.handle.IsWeak());
CHECK(g2s2.handle.IsWeak());
g3s1.handle.Reset(iso, Object::New(iso));
g3s2.handle.Reset(iso, Object::New(iso));
- g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
- g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
+ g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
CHECK(g3s1.handle.IsWeak());
CHECK(g3s2.handle.IsWeak());
g4s1.handle.Reset(iso, Object::New(iso));
g4s2.handle.Reset(iso, Object::New(iso));
- g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
- g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
+ g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
CHECK(g4s1.handle.IsWeak());
CHECK(g4s2.handle.IsWeak());
}
// Do a single full GC
v8::internal::Heap* heap =
reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
- heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ heap->CollectAllGarbage();
// All object should be alive.
CHECK_EQ(0, counter.NumberOfWeakCalls());
// Weaken the root.
- root.handle.SetWeak(&root, &WeakPointerCallback);
+ root.handle.SetWeak(&root, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
// Groups are deleted, rebuild groups.
{
iso->SetReferenceFromGroup(id4, g1s1.handle);
}
- heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ heap->CollectAllGarbage();
// All objects should be gone. 9 global handles in total.
CHECK_EQ(9, counter.NumberOfWeakCalls());
}
-THREADED_TEST(WeakRootsSurviveTwoRoundsOfGC) {
+// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
+// on the buildbots, so was made non-threaded for the time being.
+TEST(ApiObjectGroupsCycleForScavenger) {
+ i::FLAG_stress_compaction = false;
+ i::FLAG_gc_global = false;
LocalContext env;
v8::Isolate* iso = env->GetIsolate();
HandleScope scope(iso);
WeakCallCounter counter(1234);
- WeakCallCounterAndPersistent<Value> weak_obj(&counter);
+ WeakCallCounterAndPersistent<Value> g1s1(&counter);
+ WeakCallCounterAndPersistent<Value> g1s2(&counter);
+ WeakCallCounterAndPersistent<Value> g2s1(&counter);
+ WeakCallCounterAndPersistent<Value> g2s2(&counter);
+ WeakCallCounterAndPersistent<Value> g3s1(&counter);
+ WeakCallCounterAndPersistent<Value> g3s2(&counter);
- // Create a weak object that references a internalized string.
{
HandleScope scope(iso);
- weak_obj.handle.Reset(iso, Object::New(iso));
- weak_obj.handle.SetWeak(&weak_obj, &WeakPointerCallback);
- CHECK(weak_obj.handle.IsWeak());
- Local<Object>::New(iso, weak_obj.handle.As<Object>())
- ->Set(v8_str("x"), String::NewFromUtf8(iso, "magic cookie",
- String::kInternalizedString));
- }
- // Do a single full GC
- i::Isolate* i_iso = reinterpret_cast<v8::internal::Isolate*>(iso);
- i::Heap* heap = i_iso->heap();
- heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
-
- // We should have received the weak callback.
- CHECK_EQ(1, counter.NumberOfWeakCalls());
-
- // Check that the string is still alive.
- {
- HandleScope scope(iso);
- i::MaybeHandle<i::String> magic_string =
- i::StringTable::LookupStringIfExists(
- i_iso,
- v8::Utils::OpenHandle(*String::NewFromUtf8(iso, "magic cookie")));
- magic_string.Check();
- }
-}
-
-
-// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
-// on the buildbots, so was made non-threaded for the time being.
-TEST(ApiObjectGroupsCycleForScavenger) {
- i::FLAG_stress_compaction = false;
- i::FLAG_gc_global = false;
- LocalContext env;
- v8::Isolate* iso = env->GetIsolate();
- HandleScope scope(iso);
-
- WeakCallCounter counter(1234);
-
- WeakCallCounterAndPersistent<Value> g1s1(&counter);
- WeakCallCounterAndPersistent<Value> g1s2(&counter);
- WeakCallCounterAndPersistent<Value> g2s1(&counter);
- WeakCallCounterAndPersistent<Value> g2s2(&counter);
- WeakCallCounterAndPersistent<Value> g3s1(&counter);
- WeakCallCounterAndPersistent<Value> g3s2(&counter);
-
- {
- HandleScope scope(iso);
- g1s1.handle.Reset(iso, Object::New(iso));
- g1s2.handle.Reset(iso, Object::New(iso));
- g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
- g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
+ g1s1.handle.Reset(iso, Object::New(iso));
+ g1s2.handle.Reset(iso, Object::New(iso));
+ g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
g2s1.handle.Reset(iso, Object::New(iso));
g2s2.handle.Reset(iso, Object::New(iso));
- g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
- g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
+ g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
g3s1.handle.Reset(iso, Object::New(iso));
g3s2.handle.Reset(iso, Object::New(iso));
- g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
- g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
+ g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
}
// Make a root.
v8::internal::Heap* heap =
reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
- heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+ heap->CollectAllGarbage();
// All objects should be alive.
CHECK_EQ(0, counter.NumberOfWeakCalls());
// Weaken the root.
- root.handle.SetWeak(&root, &WeakPointerCallback);
+ root.handle.SetWeak(&root, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
root.handle.MarkPartiallyDependent();
// Groups are deleted, rebuild groups.
->Set(v8_str("x"), Local<Value>::New(iso, g1s1.handle));
}
- heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+ heap->CollectAllGarbage();
// All objects should be gone. 7 global handles in total.
CHECK_EQ(7, counter.NumberOfWeakCalls());
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
Local<Script> script = v8_compile("throw 'panama!';");
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(env->GetIsolate());
Local<Value> result = script->Run();
CHECK(result.IsEmpty());
CHECK(try_catch.HasCaught());
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"function CustomError() { this.a = 'b'; }"
"(function f() { throw new CustomError(); })();");
static void check_message_3(v8::Handle<v8::Message> message,
v8::Handle<Value> data) {
CHECK(message->IsSharedCrossOrigin());
- CHECK(message->GetScriptOrigin().ResourceIsSharedCrossOrigin()->Value());
- CHECK(message->GetScriptOrigin().ResourceIsEmbedderDebugScript()->Value());
+ CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin());
+ CHECK(message->GetScriptOrigin().Options().IsEmbedderDebugScript());
+ CHECK(message->GetScriptOrigin().Options().IsOpaque());
CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
+ CHECK_EQ(7.40, message->GetScriptOrigin().SourceMapUrl()->NumberValue());
message_received = true;
}
CHECK(!message_received);
v8::V8::AddMessageListener(check_message_3);
LocalContext context;
- v8::ScriptOrigin origin =
- v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
- v8::Integer::New(isolate, 2), v8::True(isolate),
- Handle<v8::Integer>(), v8::True(isolate));
+ v8::ScriptOrigin origin = v8::ScriptOrigin(
+ v8_str("6.75"), v8::Integer::New(isolate, 1),
+ v8::Integer::New(isolate, 2), v8::True(isolate), Handle<v8::Integer>(),
+ v8::True(isolate), v8_str("7.40"), v8::True(isolate));
v8::Handle<v8::Script> script =
Script::Compile(v8_str("throw 'error'"), &origin);
script->Run();
CHECK(!message_received);
v8::V8::AddMessageListener(check_message_5a);
LocalContext context;
- v8::ScriptOrigin origin =
+ v8::ScriptOrigin origin1 =
v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
v8::Integer::New(isolate, 2), v8::True(isolate));
v8::Handle<v8::Script> script =
- Script::Compile(v8_str("throw 'error'"), &origin);
+ Script::Compile(v8_str("throw 'error'"), &origin1);
script->Run();
CHECK(message_received);
// clear out the message listener
message_received = false;
v8::V8::AddMessageListener(check_message_5b);
- origin = v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
- v8::Integer::New(isolate, 2), v8::False(isolate));
- script = Script::Compile(v8_str("throw 'error'"), &origin);
+ v8::ScriptOrigin origin2 =
+ v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
+ v8::Integer::New(isolate, 2), v8::False(isolate));
+ script = Script::Compile(v8_str("throw 'error'"), &origin2);
script->Run();
CHECK(message_received);
// clear out the message listener
CHECK(value->Equals(weak_map->Get(obj2)));
CHECK(value->Equals(weak_map->Get(sym1)));
}
- CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
{
HandleScope scope(isolate);
CHECK(value->Equals(weak_map->Get(local1)));
CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, s1.handle))));
}
- o1.handle.SetWeak(&o1, &WeakPointerCallback);
- o2.handle.SetWeak(&o2, &WeakPointerCallback);
- s1.handle.SetWeak(&s1, &WeakPointerCallback);
+ o1.handle.SetWeak(&o1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ o2.handle.SetWeak(&o2, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
+ s1.handle.SetWeak(&s1, &WeakPointerCallback,
+ v8::WeakCallbackType::kParameter);
- CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(3, counter.NumberOfWeakCalls());
CHECK(o1.handle.IsEmpty());
Local<Value> fake_prop = v8_num(1);
CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
// exception
- TryCatch try_catch;
+ TryCatch try_catch(context->GetIsolate());
Local<Value> exception =
CompileRun("({ toString: function() { throw 'exception';} })");
CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
return;
}
v8::HandleScope scope(args.GetIsolate());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(args.GetIsolate());
Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
CHECK(!try_catch.HasCaught() || result.IsEmpty());
args.GetReturnValue().Set(try_catch.HasCaught());
templ->Set(v8_str("ThrowFromC"),
v8::FunctionTemplate::New(isolate, ThrowFromC));
LocalContext context(0, templ);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun("ThrowFromC();");
CHECK(try_catch.HasCaught());
}
}
+static void check_custom_rethrowing_message(v8::Handle<v8::Message> message,
+ v8::Handle<v8::Value> data) {
+ const char* uncaught_error = "Uncaught exception";
+ CHECK(message->Get()->Equals(v8_str(uncaught_error)));
+}
+
+
+TEST(CustomErrorRethrowsOnToString) {
+ LocalContext context;
+ v8::HandleScope scope(context->GetIsolate());
+ v8::V8::AddMessageListener(check_custom_rethrowing_message);
+
+ CompileRun(
+ "var e = { toString: function() { throw e; } };"
+ "try { throw e; } finally {}");
+
+ v8::V8::RemoveMessageListeners(check_custom_rethrowing_message);
+}
+
+
static void receive_message(v8::Handle<v8::Message> message,
v8::Handle<v8::Value> data) {
message->Get();
templ->Set(v8_str("ThrowFromC"),
v8::FunctionTemplate::New(isolate, ThrowFromC));
LocalContext context(0, templ);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
try_catch.SetVerbose(true);
Local<Value> result = CompileRun("ThrowFromC();");
CHECK(try_catch.HasCaught());
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
v8::V8::AddMessageListener(receive_message);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
try_catch.SetVerbose(true);
Local<Value> result = CompileRun("function foo() { foo(); } foo();");
CHECK(try_catch.HasCaught());
v8::FunctionTemplate::New(isolate, ThrowFromC));
LocalContext context(0, templ);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
CHECK(result.IsEmpty());
CHECK(try_catch.HasCaught());
Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
v8::Handle<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
if (count % cInterval == 0) {
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(args.GetIsolate());
Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
int expected = args[3]->Int32Value();
if (try_catch.HasCaught()) {
THREADED_TEST(EvalInTryFinally) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
CompileRun(
"(function() {"
" try {"
THREADED_TEST(CatchZero) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
CHECK(!try_catch.HasCaught());
CompileRun("throw 10");
CHECK(try_catch.HasCaught());
THREADED_TEST(CatchExceptionFromWith) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
CHECK(!try_catch.HasCaught());
CompileRun("var o = {}; with (o) { throw 42; }");
CHECK(try_catch.HasCaught());
THREADED_TEST(TryCatchAndFinallyHidingException) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
CHECK(!try_catch.HasCaught());
CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
CompileRun("f({toString: function() { throw 42; }});");
void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(args.GetIsolate());
}
context->Global()->Set(
v8_str("native_with_try_catch"),
v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CHECK(!try_catch.HasCaught());
CompileRun(
"try {\n"
static void TryCatchNested1Helper(int depth) {
if (depth > 0) {
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(CcTest::isolate());
try_catch.SetVerbose(true);
TryCatchNested1Helper(depth - 1);
CHECK(try_catch.HasCaught());
static void TryCatchNested2Helper(int depth) {
if (depth > 0) {
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(CcTest::isolate());
try_catch.SetVerbose(true);
TryCatchNested2Helper(depth - 1);
CHECK(try_catch.HasCaught());
{
// Test nested try-catch with a native throw in the end.
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
TryCatchNested1Helper(5);
CHECK(try_catch.HasCaught());
CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
{
// Test nested try-catch with a JavaScript throw in the end.
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
TryCatchNested2Helper(5);
CHECK(try_catch.HasCaught());
CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
CHECK_EQ(0,
strcmp(*v8::String::Utf8Value(message->Get()), "Uncaught Error: a"));
CHECK_EQ(1, message->GetLineNumber());
- CHECK_EQ(6, message->GetStartColumn());
+ CHECK_EQ(0, message->GetStartColumn());
}
void TryCatchMixedNestingHelper(
const v8::FunctionCallbackInfo<v8::Value>& args) {
ApiTestFuzzer::Fuzz();
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(args.GetIsolate());
CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
CHECK(try_catch.HasCaught());
TryCatchMixedNestingCheck(&try_catch);
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
v8::V8::Initialize();
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
templ->Set(v8_str("TryCatchMixedNestingHelper"),
v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
ApiTestFuzzer::Fuzz();
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(args.GetIsolate());
args.GetIsolate()->ThrowException(v8_str("boom"));
CHECK(try_catch.HasCaught());
}
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
v8::V8::Initialize();
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
templ->Set(v8_str("TryCatchNativeHelper"),
v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
void TryCatchNativeResetHelper(
const v8::FunctionCallbackInfo<v8::Value>& args) {
ApiTestFuzzer::Fuzz();
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(args.GetIsolate());
args.GetIsolate()->ThrowException(v8_str("boom"));
CHECK(try_catch.HasCaught());
try_catch.Reset();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
v8::V8::Initialize();
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
templ->Set(v8_str("TryCatchNativeResetHelper"),
v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
CHECK_EQ(result->BooleanValue(), false);
// Make sure that it is not possible to redefine again
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
result = script_define->Run();
CHECK(try_catch.HasCaught());
String::Utf8Value exception_value(try_catch.Exception());
CHECK_EQ(result->BooleanValue(), false);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
result = script_define->Run();
CHECK(try_catch.HasCaught());
String::Utf8Value exception_value(try_catch.Exception());
->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
{
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"Object.defineProperty(obj1, 'x',"
"{get: function() { return 'func'; }})");
0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
}
{
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"Object.defineProperty(obj2, 'x',"
"{get: function() { return 'func'; }})");
struct FlagAndPersistent {
bool flag;
- v8::Persistent<v8::Object> handle;
+ v8::Global<v8::Object> handle;
};
-static void SetFlag(const v8::PhantomCallbackData<FlagAndPersistent>& data) {
+static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
data.GetParameter()->flag = true;
+ data.GetParameter()->handle.Reset();
}
b->Set(v8_str("x"), a);
}
if (global_gc) {
- CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
} else {
CcTest::heap()->CollectGarbage(i::NEW_SPACE);
}
object_a.flag = false;
object_b.flag = false;
- object_a.handle.SetPhantom(&object_a, &SetFlag);
- object_b.handle.SetPhantom(&object_b, &SetFlag);
+ object_a.handle.SetWeak(&object_a, &SetFlag,
+ v8::WeakCallbackType::kParameter);
+ object_b.handle.SetWeak(&object_b, &SetFlag,
+ v8::WeakCallbackType::kParameter);
CHECK(!object_b.handle.IsIndependent());
object_a.handle.MarkIndependent();
object_b.handle.MarkIndependent();
CHECK(object_b.handle.IsIndependent());
if (global_gc) {
- CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
} else {
CcTest::heap()->CollectGarbage(i::NEW_SPACE);
}
}
-THREADED_TEST(IndependentWeakHandle) {
+TEST(IndependentWeakHandle) {
IndependentWeakHandle(false, false);
IndependentWeakHandle(false, true);
IndependentWeakHandle(true, false);
void CheckInternalFields(
- const v8::PhantomCallbackData<v8::Persistent<v8::Object>>& data) {
+ const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
v8::Persistent<v8::Object>* handle = data.GetParameter();
handle->Reset();
Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField1());
reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
CHECK_EQ(103, t2->x());
- handle.SetPhantom<v8::Persistent<v8::Object>>(&handle, CheckInternalFields,
- 0, 1);
+ handle.SetWeak<v8::Persistent<v8::Object>>(
+ &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
if (!global_gc) {
handle.MarkIndependent();
}
}
if (global_gc) {
- CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
} else {
CcTest::heap()->CollectGarbage(i::NEW_SPACE);
}
static void ResetUseValueAndSetFlag(
- const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
+ const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
// Blink will reset the handle, and then use the other handle, so they
// can't use the same backing slot.
data.GetParameter()->handle.Reset();
- data.GetValue()->IsBoolean(); // Make sure the handle still works.
data.GetParameter()->flag = true;
}
object_a.flag = false;
object_b.flag = false;
- object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
- object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
+ object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag,
+ v8::WeakCallbackType::kParameter);
+ object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag,
+ v8::WeakCallbackType::kParameter);
if (!global_gc) {
object_a.handle.MarkIndependent();
object_b.handle.MarkIndependent();
static void InvokeScavenge() { CcTest::heap()->CollectGarbage(i::NEW_SPACE); }
-static void InvokeMarkSweep() {
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
-}
+static void InvokeMarkSweep() { CcTest::heap()->CollectAllGarbage(); }
-static void ForceScavenge(
- const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
- data.GetParameter()->handle.Reset();
+static void ForceScavenge2(
+ const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
data.GetParameter()->flag = true;
InvokeScavenge();
}
-
-static void ForceMarkSweep(
- const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
+static void ForceScavenge1(
+ const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
data.GetParameter()->handle.Reset();
+ data.SetSecondPassCallback(ForceScavenge2);
+}
+
+
+static void ForceMarkSweep2(
+ const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
data.GetParameter()->flag = true;
InvokeMarkSweep();
}
+static void ForceMarkSweep1(
+ const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
+ data.GetParameter()->handle.Reset();
+ data.SetSecondPassCallback(ForceMarkSweep2);
+}
+
THREADED_TEST(GCFromWeakCallbacks) {
v8::Isolate* isolate = CcTest::isolate();
Context::Scope context_scope(context);
static const int kNumberOfGCTypes = 2;
- typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
- Callback;
- Callback gc_forcing_callback[kNumberOfGCTypes] =
- {&ForceScavenge, &ForceMarkSweep};
+ typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
+ Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
+ &ForceMarkSweep1};
typedef void (*GCInvoker)();
GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
object.handle.Reset(isolate, v8::Object::New(isolate));
}
object.flag = false;
- object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
+ object.handle.SetWeak(&object, gc_forcing_callback[inner_gc],
+ v8::WeakCallbackType::kParameter);
object.handle.MarkIndependent();
invoke_gc[outer_gc]();
CHECK(object.flag);
}
-static void RevivingCallback(
- const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
- data.GetParameter()->handle.ClearWeak();
- data.GetParameter()->flag = true;
-}
-
-
-THREADED_TEST(IndependentHandleRevival) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope scope(isolate);
- v8::Handle<Context> context = Context::New(isolate);
- Context::Scope context_scope(context);
-
- FlagAndPersistent object;
- {
- v8::HandleScope handle_scope(isolate);
- v8::Local<v8::Object> o = v8::Object::New(isolate);
- object.handle.Reset(isolate, o);
- o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
- v8::Local<String> y_str = v8_str("y");
- o->Set(y_str, y_str);
- }
- object.flag = false;
- object.handle.SetWeak(&object, &RevivingCallback);
- object.handle.MarkIndependent();
- CcTest::heap()->CollectGarbage(i::NEW_SPACE);
- CHECK(object.flag);
- CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
- {
- v8::HandleScope handle_scope(isolate);
- v8::Local<v8::Object> o =
- v8::Local<v8::Object>::New(isolate, object.handle);
- v8::Local<String> y_str = v8_str("y");
- CHECK(v8::Integer::New(isolate, 1)->Equals(o->Get(v8_str("x"))));
- CHECK(o->Get(y_str)->Equals(y_str));
- }
-}
-
-
v8::Handle<Function> args_fun;
CHECK(v8::Integer::New(isolate, 3)->Equals(args[2]));
CHECK(v8::Undefined(isolate)->Equals(args[3]));
v8::HandleScope scope(args.GetIsolate());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
}
}
-static uint16_t StringGet(Handle<String> str, int index) {
- i::Handle<i::String> istring =
- v8::Utils::OpenHandle(String::Cast(*str));
- return istring->Get(index);
-}
-
-
-static void WriteUtf8Helper(
- LocalContext& context, // NOLINT
- const char* name,
- const char* lengths_name,
- int len) {
- Local<v8::Array> b =
- Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
- Local<v8::Array> alens =
- Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
- char buffer[1000];
- char buffer2[1000];
- for (int i = 0; i < len; i++) {
- Local<v8::String> string =
- Local<v8::String>::Cast(b->Get(i));
- Local<v8::Number> expected_len =
- Local<v8::Number>::Cast(alens->Get(i));
- int utf8_length = static_cast<int>(expected_len->Value());
- for (int j = utf8_length + 1; j >= 0; j--) {
- memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
- memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
- int nchars;
- int utf8_written =
- string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
- int utf8_written2 =
- string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
- CHECK_GE(utf8_length + 1, utf8_written);
- CHECK_GE(utf8_length, utf8_written2);
- for (int k = 0; k < utf8_written2; k++) {
- CHECK_EQ(buffer[k], buffer2[k]);
- }
- CHECK(nchars * 3 >= utf8_written - 1);
- CHECK(nchars <= utf8_written);
- if (j == utf8_length + 1) {
- CHECK_EQ(utf8_written2, utf8_length);
- CHECK_EQ(utf8_written2 + 1, utf8_written);
- }
- CHECK_EQ(buffer[utf8_written], 42);
- if (j > utf8_length) {
- if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
- if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
- Handle<String> roundtrip = v8_str(buffer);
- CHECK(roundtrip->Equals(string));
- } else {
- if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
- }
- if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
- if (nchars >= 2) {
- uint16_t trail = StringGet(string, nchars - 1);
- uint16_t lead = StringGet(string, nchars - 2);
- if (((lead & 0xfc00) == 0xd800) &&
- ((trail & 0xfc00) == 0xdc00)) {
- unsigned u1 = buffer2[utf8_written2 - 4];
- unsigned u2 = buffer2[utf8_written2 - 3];
- unsigned u3 = buffer2[utf8_written2 - 2];
- unsigned u4 = buffer2[utf8_written2 - 1];
- CHECK_EQ((u1 & 0xf8), 0xf0u);
- CHECK_EQ((u2 & 0xc0), 0x80u);
- CHECK_EQ((u3 & 0xc0), 0x80u);
- CHECK_EQ((u4 & 0xc0), 0x80u);
- uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
- CHECK_EQ((u4 & 0x3f), (c & 0x3f));
- CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
- CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
- CHECK_EQ((u1 & 0x3), c >> 18);
- }
- }
- }
- }
-}
-
-
THREADED_TEST(Utf16) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
"}");
Utf16Helper(context, "a", "alens", 9);
Utf16Helper(context, "a2", "a2lens", 81);
- WriteUtf8Helper(context, "b", "alens", 9);
- WriteUtf8Helper(context, "b2", "a2lens", 81);
- WriteUtf8Helper(context, "c2", "a2lens", 81);
}
return *is1 == *is2;
}
-static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
- const char* b) {
- Handle<String> symbol1 =
- v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
- Handle<String> symbol2 =
- v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
- CHECK(SameSymbol(symbol1, symbol2));
-}
-
THREADED_TEST(Utf16Symbol) {
LocalContext context;
context->GetIsolate(), "abc", v8::String::kInternalizedString);
CHECK(SameSymbol(symbol1, symbol2));
- SameSymbolHelper(context->GetIsolate(),
- "\360\220\220\205", // 4 byte encoding.
- "\355\240\201\355\260\205"); // 2 3-byte surrogates.
- SameSymbolHelper(context->GetIsolate(),
- "\355\240\201\355\260\206", // 2 3-byte surrogates.
- "\360\220\220\206"); // 4 byte encoding.
- SameSymbolHelper(context->GetIsolate(),
- "x\360\220\220\205", // 4 byte encoding.
- "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
- SameSymbolHelper(context->GetIsolate(),
- "x\355\240\201\355\260\206", // 2 3-byte surrogates.
- "x\360\220\220\206"); // 4 byte encoding.
CompileRun(
"var sym0 = 'benedictus';"
"var sym0b = 'S\303\270ren';"
}
+THREADED_TEST(Utf16MissingTrailing) {
+ LocalContext context;
+ v8::HandleScope scope(context->GetIsolate());
+
+ // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
+ int size = 1024 * 64;
+ uint8_t* buffer = new uint8_t[size];
+ for (int i = 0; i < size; i += 4) {
+ buffer[i] = 0xf0;
+ buffer[i + 1] = 0x9d;
+ buffer[i + 2] = 0x80;
+ buffer[i + 3] = 0x9e;
+ }
+
+ // Now invoke the decoder without last 3 bytes
+ v8::Local<v8::String> str =
+ v8::String::NewFromUtf8(
+ context->GetIsolate(), reinterpret_cast<char*>(buffer),
+ v8::NewStringType::kNormal, size - 3).ToLocalChecked();
+ USE(str);
+ delete[] buffer;
+}
+
+
+THREADED_TEST(Utf16Trailing3Byte) {
+ LocalContext context;
+ v8::HandleScope scope(context->GetIsolate());
+
+ // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
+ int size = 1024 * 63;
+ uint8_t* buffer = new uint8_t[size];
+ for (int i = 0; i < size; i += 3) {
+ buffer[i] = 0xe2;
+ buffer[i + 1] = 0x80;
+ buffer[i + 2] = 0xa6;
+ }
+
+ // Now invoke the decoder without last 3 bytes
+ v8::Local<v8::String> str =
+ v8::String::NewFromUtf8(
+ context->GetIsolate(), reinterpret_cast<char*>(buffer),
+ v8::NewStringType::kNormal, size).ToLocalChecked();
+
+ v8::String::Value value(str);
+ CHECK_EQ(value.length(), size / 3);
+ CHECK_EQ((*value)[value.length() - 1], 0x2026);
+
+ delete[] buffer;
+}
+
+
THREADED_TEST(ToArrayIndex) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
str = v8_str("-42");
index = str->ToArrayIndex();
CHECK(index.IsEmpty());
- str = v8_str("4294967295");
+ str = v8_str("4294967294");
index = str->ToArrayIndex();
CHECK(!index.IsEmpty());
- CHECK_EQ(4294967295.0, index->Uint32Value());
+ CHECK_EQ(4294967294.0, index->Uint32Value());
v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
index = num->ToArrayIndex();
CHECK(!index.IsEmpty());
v8::Local<v8::Object> global = context->Global();
global->Set(v8_str("throwV8Exception"), fun->GetFunction());
- TryCatch try_catch;
+ TryCatch try_catch(context->GetIsolate());
CompileRun(
"function f1() {\n"
" throwV8Exception();\n"
}
+THREADED_TEST(ExceptionCreateMessageLength) {
+ LocalContext context;
+ v8::HandleScope scope(context->GetIsolate());
+
+ // Test that the message is not truncated.
+ TryCatch try_catch(context->GetIsolate());
+ CompileRun(
+ "var message = 'm';"
+ "while (message.length < 1000) message += message;"
+ "throw message;");
+ CHECK(try_catch.HasCaught());
+
+ CHECK_LT(1000, try_catch.Message()->Get()->Length());
+}
+
+
static void YGetter(Local<String> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
ApiTestFuzzer::Fuzz();
TEST(CompilationErrorUsingTryCatchHandler) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(env->GetIsolate());
v8_compile("This doesn't &*&@#$&*^ compile.");
CHECK(*try_catch.Exception());
CHECK(try_catch.HasCaught());
TEST(TryCatchFinallyUsingTryCatchHandler) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(env->GetIsolate());
CompileRun("try { throw ''; } catch (e) {}");
CHECK(!try_catch.HasCaught());
CompileRun("try { throw ''; } finally {}");
templ->Set(v8_str("CEvaluate"),
v8::FunctionTemplate::New(isolate, CEvaluate));
LocalContext context(0, templ);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun("try {"
" CEvaluate('throw 1;');"
"} finally {"
// For use within the TestSecurityHandler() test.
static bool g_security_callback_result = false;
-static bool NamedSecurityTestCallback(Local<v8::Object> global,
- Local<Value> name,
- v8::AccessType type,
- Local<Value> data) {
+static bool SecurityTestCallback(Local<v8::Object> global, Local<Value> name,
+ v8::AccessType type, Local<Value> data) {
printf("a\n");
- // Always allow read access.
- if (type == v8::ACCESS_GET)
- return true;
-
- // Sometimes allow other access.
- return g_security_callback_result;
-}
-
-
-static bool IndexedSecurityTestCallback(Local<v8::Object> global,
- uint32_t key,
- v8::AccessType type,
- Local<Value> data) {
- printf("b\n");
- // Always allow read access.
- if (type == v8::ACCESS_GET)
- return true;
-
- // Sometimes allow other access.
return g_security_callback_result;
}
v8::HandleScope scope0(isolate);
v8::Handle<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate);
- global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
- IndexedSecurityTestCallback);
+ global_template->SetAccessCheckCallbacks(SecurityTestCallback, NULL);
// Create an environment
v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
context0->Enter();
v8::Handle<Script> script1 =
v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
script1->Run();
+ g_security_callback_result = true;
// This read will pass the security check.
v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
CHECK_EQ(111, foo1->Int32Value());
CHECK_EQ(999, z1->Int32Value());
// Create another environment, should pass security checks.
- { g_security_callback_result = true; // allow security handler to pass.
+ {
v8::HandleScope scope2(isolate);
LocalContext context2;
v8::Handle<v8::Object> global2 = context2->Global();
Context::Scope scope_env2(env2);
// Call cross_domain_call, it should throw an exception
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(env1->GetIsolate());
Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
CHECK(try_catch.HasCaught());
}
}
-static bool named_security_check_with_gc_called;
+static bool security_check_with_gc_called;
-static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
- Local<Value> name,
- v8::AccessType type,
- Local<Value> data) {
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- named_security_check_with_gc_called = true;
- return true;
-}
-
-
-static bool indexed_security_check_with_gc_called;
-
-static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
- uint32_t key,
- v8::AccessType type,
- Local<Value> data) {
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- indexed_security_check_with_gc_called = true;
+static bool SecurityTestCallbackWithGC(Local<v8::Object> global,
+ Local<v8::Value> name,
+ v8::AccessType type, Local<Value> data) {
+ CcTest::heap()->CollectAllGarbage();
+ security_check_with_gc_called = true;
return true;
}
v8::HandleScope handle_scope(isolate);
v8::Handle<v8::ObjectTemplate> object_template =
v8::ObjectTemplate::New(isolate);
- object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
- IndexedSecurityTestCallbackWithGC);
+ object_template->SetAccessCheckCallbacks(SecurityTestCallbackWithGC, NULL);
v8::Handle<Context> context = Context::New(isolate);
v8::Context::Scope context_scope(context);
context->Global()->Set(v8_str("obj"), object_template->NewInstance());
- named_security_check_with_gc_called = false;
- CompileRun("obj.foo = new String(1001);");
- CHECK(named_security_check_with_gc_called);
-
- indexed_security_check_with_gc_called = false;
+ security_check_with_gc_called = false;
CompileRun("obj[0] = new String(1002);");
- CHECK(indexed_security_check_with_gc_called);
-
- named_security_check_with_gc_called = false;
- CHECK(CompileRun("obj.foo")->ToString(isolate)->Equals(v8_str("1001")));
- CHECK(named_security_check_with_gc_called);
+ CHECK(security_check_with_gc_called);
- indexed_security_check_with_gc_called = false;
+ security_check_with_gc_called = false;
CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
- CHECK(indexed_security_check_with_gc_called);
+ CHECK(security_check_with_gc_called);
}
{
Local<Value> get_prop = global1->Get(v8_str("getProp"));
CHECK(get_prop->IsFunction());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(env1->GetIsolate());
Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
CHECK(!try_catch.HasCaught());
CHECK_EQ(1, r->Int32Value());
}
Local<Object> env2_global = env2->Global();
- env2_global->TurnOnAccessCheck();
env2->DetachGlobal();
Local<Value> result;
}
-static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
-static bool NamedAccessBlocker(Local<v8::Object> global,
- Local<Value> name,
- v8::AccessType type,
- Local<Value> data) {
- return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
- allowed_access_type[type];
-}
-
-
-static bool IndexedAccessBlocker(Local<v8::Object> global,
- uint32_t key,
- v8::AccessType type,
- Local<Value> data) {
+static bool allowed_access = false;
+static bool AccessBlocker(Local<v8::Object> global, Local<Value> name,
+ v8::AccessType type, Local<Value> data) {
return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
- allowed_access_type[type];
+ allowed_access;
}
v8::Handle<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate);
- global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
- IndexedAccessBlocker);
+ global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
// Add an accessor accessible by cross-domain JS code.
global_template->SetAccessor(
CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
- // Enable ACCESS_HAS
- allowed_access_type[v8::ACCESS_HAS] = true;
- CHECK(CompileRun("other[239]").IsEmpty());
- // ... and now we can get the descriptor...
- CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
- .IsEmpty());
- // ... and enumerate the property.
+ allowed_access = true;
+ // Now we can enumerate the property.
ExpectTrue("propertyIsEnumerable.call(other, '239')");
- allowed_access_type[v8::ACCESS_HAS] = false;
+ allowed_access = false;
// Access a property with JS accessor.
CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
.IsEmpty());
- // Enable both ACCESS_HAS and ACCESS_GET.
- allowed_access_type[v8::ACCESS_HAS] = true;
- allowed_access_type[v8::ACCESS_GET] = true;
+ allowed_access = true;
ExpectString("other.js_accessor_p", "getter");
ExpectObject(
ExpectUndefined(
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
- allowed_access_type[v8::ACCESS_HAS] = false;
- allowed_access_type[v8::ACCESS_GET] = false;
+ allowed_access = false;
// Access an element with JS accessor.
CHECK(CompileRun("other[42] = 2").IsEmpty());
CHECK(CompileRun("other[42]").IsEmpty());
CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
- // Enable both ACCESS_HAS and ACCESS_GET.
- allowed_access_type[v8::ACCESS_HAS] = true;
- allowed_access_type[v8::ACCESS_GET] = true;
+ allowed_access = true;
ExpectString("other[42]", "el_getter");
ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
- allowed_access_type[v8::ACCESS_HAS] = false;
- allowed_access_type[v8::ACCESS_GET] = false;
+ allowed_access = false;
v8::Handle<Value> value;
v8::Handle<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate);
- global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
- IndexedAccessBlocker);
+ global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
// Add accessible accessor.
global_template->SetAccessor(
}
-static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
- v8::AccessType type, Local<Value> data) {
- return false;
-}
-
-
-static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
- v8::AccessType type, Local<Value> data) {
+static bool AccessAlwaysBlocked(Local<v8::Object> global, Local<Value> name,
+ v8::AccessType type, Local<Value> data) {
+ i::PrintF("Access blocked.\n");
return false;
}
v8::ObjectTemplate::New(isolate);
obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
- obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
- BlockEverythingIndexed);
+ obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
// Create an environment
v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
TEST(SuperAccessControl) {
i::FLAG_allow_natives_syntax = true;
- i::FLAG_harmony_classes = true;
- i::FLAG_harmony_object_literals = true;
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
v8::Handle<v8::ObjectTemplate> obj_template =
v8::ObjectTemplate::New(isolate);
- obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
- BlockEverythingIndexed);
+ obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
LocalContext env;
env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
{
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"var f = { m() { return super.hasOwnProperty; } }.m;"
"var m = %ToMethod(f, prohibited);"
}
{
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"var f = {m() { return super[42]; } }.m;"
"var m = %ToMethod(f, prohibited);"
}
{
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"var f = {m() { super.hasOwnProperty = function () {}; } }.m;"
"var m = %ToMethod(f, prohibited);"
}
{
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
"var f = {"
}
+TEST(Regress470113) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::ObjectTemplate> obj_template =
+ v8::ObjectTemplate::New(isolate);
+ obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
+ LocalContext env;
+ env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
+
+ {
+ v8::TryCatch try_catch(isolate);
+ CompileRun(
+ "'use strict';\n"
+ "class C extends Object {\n"
+ " m() { super.powned = 'Powned!'; }\n"
+ "}\n"
+ "let c = new C();\n"
+ "c.m.call(prohibited)");
+
+ CHECK(try_catch.HasCaught());
+ }
+}
+
+
static void ConstTenGetter(Local<String> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(v8_num(10));
}
-static int named_access_count = 0;
-static int indexed_access_count = 0;
-
-static bool NamedAccessCounter(Local<v8::Object> global,
- Local<Value> name,
- v8::AccessType type,
- Local<Value> data) {
- named_access_count++;
- return true;
-}
-
+static int access_count = 0;
-static bool IndexedAccessCounter(Local<v8::Object> global,
- uint32_t key,
- v8::AccessType type,
- Local<Value> data) {
- indexed_access_count++;
+static bool AccessCounter(Local<v8::Object> global, Local<Value> name,
+ v8::AccessType type, Local<Value> data) {
+ access_count++;
return true;
}
// This one is too easily disturbed by other tests.
TEST(AccessControlIC) {
- named_access_count = 0;
- indexed_access_count = 0;
+ access_count = 0;
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
// called for cross-domain access.
v8::Handle<v8::ObjectTemplate> object_template =
v8::ObjectTemplate::New(isolate);
- object_template->SetAccessCheckCallbacks(NamedAccessCounter,
- IndexedAccessCounter);
+ object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
Local<v8::Object> object = object_template->NewInstance();
v8::HandleScope scope1(isolate);
value = CompileRun("testProp(obj)");
CHECK(value->IsNumber());
CHECK_EQ(1, value->Int32Value());
- CHECK_EQ(21, named_access_count);
+ CHECK_EQ(21, access_count);
// Check that the named access-control function is called every time.
CompileRun("var p = 'prop';"
value = CompileRun("testKeyed(obj)");
CHECK(value->IsNumber());
CHECK_EQ(1, value->Int32Value());
- CHECK_EQ(42, named_access_count);
+ CHECK_EQ(42, access_count);
// Force the inline caches into generic state and try again.
CompileRun("testKeyed({ a: 0 })");
CompileRun("testKeyed({ b: 0 })");
value = CompileRun("testKeyed(obj)");
CHECK(value->IsNumber());
CHECK_EQ(1, value->Int32Value());
- CHECK_EQ(63, named_access_count);
+ CHECK_EQ(63, access_count);
// Check that the indexed access-control function is called every time.
+ access_count = 0;
+
CompileRun("function testIndexed(obj) {"
" for (var i = 0; i < 10; i++) obj[0] = 1;"
" for (var j = 0; j < 10; j++) obj[0];"
value = CompileRun("testIndexed(obj)");
CHECK(value->IsNumber());
CHECK_EQ(1, value->Int32Value());
- CHECK_EQ(21, indexed_access_count);
+ CHECK_EQ(21, access_count);
// Force the inline caches into generic state.
CompileRun("testIndexed(new Array(1))");
// Test that the indexed access check is called.
value = CompileRun("testIndexed(obj)");
CHECK(value->IsNumber());
CHECK_EQ(1, value->Int32Value());
- CHECK_EQ(42, indexed_access_count);
+ CHECK_EQ(42, access_count);
+ access_count = 0;
// Check that the named access check is called when invoking
// functions on an object that requires access checks.
CompileRun("obj.f = function() {}");
" for (var i = 0; i < 10; i++) obj.f();"
"}");
CompileRun("testCallNormal(obj)");
- CHECK_EQ(74, named_access_count);
+ printf("%i\n", access_count);
+ CHECK_EQ(11, access_count);
// Force obj into slow case.
value = CompileRun("delete obj.prop");
value = CompileRun("testProp(obj);");
CHECK(value->IsNumber());
CHECK_EQ(1, value->Int32Value());
- CHECK_EQ(96, named_access_count);
+ CHECK_EQ(33, access_count);
// Force the call inline cache into dictionary probing mode.
CompileRun("o.f = function() {}; testCallNormal(o)");
// Test that the named access check is still called for each
// invocation of the function.
value = CompileRun("testCallNormal(obj)");
- CHECK_EQ(106, named_access_count);
+ CHECK_EQ(43, access_count);
context1->Exit();
context0->Exit();
}
-static bool NamedAccessFlatten(Local<v8::Object> global,
- Local<Value> name,
- v8::AccessType type,
- Local<Value> data) {
- char buf[100];
- int len;
+THREADED_TEST(Version) { v8::V8::GetVersion(); }
- CHECK(name->IsString());
- memset(buf, 0x1, sizeof(buf));
- len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
- CHECK_EQ(4, len);
+static void InstanceFunctionCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ ApiTestFuzzer::Fuzz();
+ args.GetReturnValue().Set(v8_num(12));
+}
- uint16_t buf2[100];
- memset(buf, 0x1, sizeof(buf));
- len = name.As<String>()->Write(buf2);
- CHECK_EQ(4, len);
+THREADED_TEST(InstanceProperties) {
+ LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
- return true;
-}
+ Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
+ Local<ObjectTemplate> instance = t->InstanceTemplate();
+ instance->Set(v8_str("x"), v8_num(42));
+ instance->Set(v8_str("f"),
+ v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
-static bool IndexedAccessFlatten(Local<v8::Object> global,
- uint32_t key,
- v8::AccessType type,
- Local<Value> data) {
- return true;
+ Local<Value> o = t->GetFunction()->NewInstance();
+
+ context->Global()->Set(v8_str("i"), o);
+ Local<Value> value = CompileRun("i.x");
+ CHECK_EQ(42, value->Int32Value());
+
+ value = CompileRun("i.f()");
+ CHECK_EQ(12, value->Int32Value());
}
-// Regression test. In access checks, operations that may cause
-// garbage collection are not allowed. It used to be the case that
-// using the Write operation on a string could cause a garbage
-// collection due to flattening of the string. This is no longer the
-// case.
-THREADED_TEST(AccessControlFlatten) {
- named_access_count = 0;
- indexed_access_count = 0;
+static void GlobalObjectInstancePropertiesGet(
+ Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
+ ApiTestFuzzer::Fuzz();
+}
+
+THREADED_TEST(GlobalObjectInstanceProperties) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
- // Create an environment.
- v8::Local<Context> context0 = Context::New(isolate);
- context0->Enter();
-
- // Create an object that requires access-check functions to be
- // called for cross-domain access.
- v8::Handle<v8::ObjectTemplate> object_template =
- v8::ObjectTemplate::New(isolate);
- object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
- IndexedAccessFlatten);
- Local<v8::Object> object = object_template->NewInstance();
-
- v8::HandleScope scope1(isolate);
-
- // Create another environment.
- v8::Local<Context> context1 = Context::New(isolate);
- context1->Enter();
-
- // Make easy access to the object from the other environment.
- v8::Handle<v8::Object> global1 = context1->Global();
- global1->Set(v8_str("obj"), object);
-
- v8::Handle<Value> value;
-
- value = v8_compile("var p = 'as' + 'df';")->Run();
- value = v8_compile("obj[p];")->Run();
-
- context1->Exit();
- context0->Exit();
-}
-
-
-THREADED_TEST(Version) { v8::V8::GetVersion(); }
-
-
-static void InstanceFunctionCallback(
- const v8::FunctionCallbackInfo<v8::Value>& args) {
- ApiTestFuzzer::Fuzz();
- args.GetReturnValue().Set(v8_num(12));
-}
-
-
-THREADED_TEST(InstanceProperties) {
- LocalContext context;
- v8::Isolate* isolate = context->GetIsolate();
- v8::HandleScope handle_scope(isolate);
-
- Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
- Local<ObjectTemplate> instance = t->InstanceTemplate();
-
- instance->Set(v8_str("x"), v8_num(42));
- instance->Set(v8_str("f"),
- v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
-
- Local<Value> o = t->GetFunction()->NewInstance();
-
- context->Global()->Set(v8_str("i"), o);
- Local<Value> value = CompileRun("i.x");
- CHECK_EQ(42, value->Int32Value());
-
- value = CompileRun("i.f()");
- CHECK_EQ(12, value->Int32Value());
-}
-
-
-static void GlobalObjectInstancePropertiesGet(
- Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
- ApiTestFuzzer::Fuzz();
-}
-
-
-THREADED_TEST(GlobalObjectInstanceProperties) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope handle_scope(isolate);
-
- Local<Value> global_object;
+ Local<Value> global_object;
Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
t->InstanceTemplate()->SetHandler(
CHECK(o0->SetPrototype(o1));
// If setting the prototype leads to the cycle, SetPrototype should
// return false and keep VM in sane state.
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CHECK(!o1->SetPrototype(o0));
CHECK(!try_catch.HasCaught());
DCHECK(!CcTest::i_isolate()->has_pending_exception());
context->Global()->Set(v8_str("fun"), fun);
CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun("new fun()");
CHECK(try_catch.HasCaught());
"x.__defineGetter__('get', Throw);");
Local<v8::Object> x =
Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
x->Get(v8_str("get"));
x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
instance_template->SetCallAsFunctionHandler(ConstructorCallback);
Local<Object> instance = instance_template->NewInstance();
context->Global()->Set(v8_str("obj"), instance);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
Local<Value> value;
CHECK(!try_catch.HasCaught());
Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Local<Object> instance = instance_template->NewInstance();
context->Global()->Set(v8_str("obj2"), instance);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
Local<Value> value;
CHECK(!try_catch.HasCaught());
instance_template->SetCallAsFunctionHandler(ThrowValue);
Local<Object> instance = instance_template->NewInstance();
context->Global()->Set(v8_str("obj3"), instance);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
Local<Value> value;
CHECK(!try_catch.HasCaught());
Local<Function> function = function_template->GetFunction();
Local<Object> instance1 = function;
context->Global()->Set(v8_str("obj4"), instance1);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
Local<Value> value;
CHECK(!try_catch.HasCaught());
CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(current->GetIsolate());
script = v8_compile(
"function f(x) { "
" var bar = 2;"
// Check that global variables in current context are not visible in other
// context.
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(CcTest::isolate());
script = v8_compile("var bar = 42; other.eval('bar');");
Local<Value> result = script->Run();
CHECK(try_catch.HasCaught());
v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
CHECK_EQ(42, x_value->Int32Value());
context0->DetachGlobal();
- v8::TryCatch catcher;
+ v8::TryCatch catcher(isolate);
x_value = CompileRun("fun('x')");
CHECK_EQ(42, x_value->Int32Value());
context1->Exit();
instance_template->SetCallAsFunctionHandler(call_as_function);
Local<v8::Object> instance = t->GetFunction()->NewInstance();
context->Global()->Set(v8_str("obj"), instance);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
Local<Value> value;
CHECK(!try_catch.HasCaught());
USE(instance_template);
Local<v8::Object> instance = t->GetFunction()->NewInstance();
context->Global()->Set(v8_str("obj2"), instance);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
Local<Value> value;
CHECK(!try_catch.HasCaught());
instance_template->SetCallAsFunctionHandler(ThrowValue);
Local<v8::Object> instance = t->GetFunction()->NewInstance();
context->Global()->Set(v8_str("obj3"), instance);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
Local<Value> value;
CHECK(!try_catch.HasCaught());
Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
instance_template->SetCallAsFunctionHandler(call_as_function);
Local<Object> instance = instance_template->NewInstance();
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CHECK(instance->IsCallable());
CHECK(!try_catch.HasCaught());
{
Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Local<Object> instance = instance_template->NewInstance();
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CHECK(!instance->IsCallable());
CHECK(!try_catch.HasCaught());
FunctionTemplate::New(isolate, call_as_function);
Local<Function> function = function_template->GetFunction();
Local<Object> instance = function;
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CHECK(instance->IsCallable());
CHECK(!try_catch.HasCaught());
Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
Local<Function> function = function_template->GetFunction();
Local<Object> instance = function;
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CHECK(instance->IsCallable());
CHECK(!try_catch.HasCaught());
reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
++(*call_count);
if ((*call_count) % 20 == 0) {
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
}
}
void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
static int count = 0;
if (count++ % 3 == 0) {
- CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ CcTest::heap()->CollectAllGarbage();
// This should move the stub
GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
}
static Handle<Value> DoDirectGetter() {
if (++p_getter_count_3 % 3 == 0) {
- CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ CcTest::heap()->CollectAllGarbage();
GenerateSomeGarbage();
}
return v8_str("Direct Getter Result");
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"o.foo = 17;"
"var receiver = {};"
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"o.foo = 17;"
"var receiver = {};"
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"o.foo = 17;"
"var receiver = {};"
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"o.foo = 17;"
"var receiver = {};"
"o\n").As<Object>();
CHECK(!with_js_getter.IsEmpty());
- TryCatch try_catch;
+ TryCatch try_catch(context->GetIsolate());
Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
CHECK(try_catch.HasCaught());
try_catch.Reset();
CHECK(result.IsEmpty());
+ Maybe<PropertyAttribute> attr =
+ instance->GetRealNamedPropertyAttributes(v8_str("f"));
+ CHECK(!try_catch.HasCaught());
+ CHECK(Just(None) == attr);
+
result = another->GetRealNamedProperty(v8_str("f"));
CHECK(try_catch.HasCaught());
try_catch.Reset();
CHECK(result.IsEmpty());
+ attr = another->GetRealNamedPropertyAttributes(v8_str("f"));
+ CHECK(!try_catch.HasCaught());
+ CHECK(Just(None) == attr);
+
result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
CHECK(try_catch.HasCaught());
try_catch.Reset();
CHECK(result.IsEmpty());
+ attr = another->GetRealNamedPropertyAttributesInPrototypeChain(v8_str("f"));
+ CHECK(!try_catch.HasCaught());
+ CHECK(Just(None) == attr);
+
result = another->Get(v8_str("f"));
CHECK(try_catch.HasCaught());
try_catch.Reset();
try_catch.Reset();
CHECK(result.IsEmpty());
+ attr = with_js_getter->GetRealNamedPropertyAttributes(v8_str("f"));
+ CHECK(!try_catch.HasCaught());
+ CHECK(Just(None) == attr);
+
result = with_js_getter->Get(v8_str("f"));
CHECK(try_catch.HasCaught());
try_catch.Reset();
static void ThrowingCallbackWithTryCatch(
const v8::FunctionCallbackInfo<v8::Value>& args) {
- TryCatch try_catch;
+ TryCatch try_catch(args.GetIsolate());
// Verboseness is important: it triggers message delivery which can call into
// external code.
try_catch.SetVerbose(true);
static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
- TryCatch try_catch;
+ TryCatch try_catch(CcTest::isolate());
}
Local<Value> obj = v8::Object::New(isolate);
obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
{
- TryCatch try_catch;
+ TryCatch try_catch(isolate);
value = obj.As<v8::Object>()->ObjectProtoToString();
CHECK(value.IsEmpty());
CHECK(try_catch.HasCaught());
obj.As<v8::Object>()->SetAccessor(
toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
{
- TryCatch try_catch;
+ TryCatch try_catch(isolate);
value = obj.As<v8::Object>()->ObjectProtoToString();
CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
CHECK(!try_catch.HasCaught());
// JS @@toStringTag value
obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
{
- TryCatch try_catch;
+ TryCatch try_catch(isolate);
value = obj.As<v8::Object>()->ObjectProtoToString();
CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
CHECK(!try_catch.HasCaught());
" get: function() { throw 'Test'; }"
"}); obj");
{
- TryCatch try_catch;
+ TryCatch try_catch(isolate);
value = obj.As<v8::Object>()->ObjectProtoToString();
CHECK(value.IsEmpty());
CHECK(try_catch.HasCaught());
" get: function() { return 'Test'; }"
"}); obj");
{
- TryCatch try_catch;
+ TryCatch try_catch(isolate);
value = obj.As<v8::Object>()->ObjectProtoToString();
CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
CHECK(!try_catch.HasCaught());
v8::Isolate* isolate = CcTest::isolate();
LocalContext context;
v8::HandleScope scope(isolate);
- v8_compile("function Parent() {};"
- "function Child() {};"
- "Child.prototype = new Parent();"
- "var outer = { inner: function() { } };"
- "var p = new Parent();"
- "var c = new Child();"
- "var x = new outer.inner();")->Run();
+ v8_compile(
+ "function Parent() {};"
+ "function Child() {};"
+ "Child.prototype = new Parent();"
+ "var outer = { inner: function() { } };"
+ "var p = new Parent();"
+ "var c = new Child();"
+ "var x = new outer.inner();"
+ "var proto = Child.prototype;")->Run();
Local<v8::Value> p = context->Global()->Get(v8_str("p"));
CHECK(p->IsObject() &&
CHECK(x->IsObject() &&
x->ToObject(isolate)->GetConstructorName()->Equals(
v8_str("outer.inner")));
+
+ Local<v8::Value> child_prototype = context->Global()->Get(v8_str("proto"));
+ CHECK(child_prototype->IsObject() &&
+ child_prototype->ToObject(isolate)->GetConstructorName()->Equals(
+ v8_str("Parent")));
}
v8::Locker nested_locker(isolate);
v8::HandleScope scope(isolate);
v8::Handle<Value> exception;
- { v8::TryCatch try_catch;
+ {
+ v8::TryCatch try_catch(isolate);
v8::Handle<Value> value = CompileRun(code);
CHECK(value.IsEmpty());
CHECK(try_catch.HasCaught());
// the first garbage collection but some of the maps have already
// been marked at that point. Therefore some of the maps are not
// collected until the second garbage collection.
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
int count = GetGlobalObjectsCount();
#ifdef DEBUG
static void WeakApiCallback(
- const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
- Local<Value> value = data.GetValue()->Get(v8_str("key"));
- CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
+ const v8::WeakCallbackInfo<Persistent<v8::Object>>& data) {
data.GetParameter()->Reset();
delete data.GetParameter();
}
obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
v8::Persistent<v8::Object>* handle =
new v8::Persistent<v8::Object>(isolate, obj);
- handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
- WeakApiCallback);
+ handle->SetWeak<v8::Persistent<v8::Object>>(
+ handle, WeakApiCallback, v8::WeakCallbackType::kParameter);
}
- reinterpret_cast<i::Isolate*>(isolate)->heap()->
- CollectAllGarbage(i::Heap::kNoGCFlags);
+ reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage(
+ i::Heap::kAbortIncrementalMarkingMask);
// Verify disposed.
CHECK_EQ(initial_handles, globals->global_handles_count());
}
v8::Persistent<v8::Object> some_object;
v8::Persistent<v8::Object> bad_handle;
-void NewPersistentHandleCallback(
- const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
+
+void NewPersistentHandleCallback2(
+ const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
v8::HandleScope scope(data.GetIsolate());
bad_handle.Reset(data.GetIsolate(), some_object);
+}
+
+
+void NewPersistentHandleCallback1(
+ const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
data.GetParameter()->Reset();
+ data.SetSecondPassCallback(NewPersistentHandleCallback2);
}
// global handle nodes are processed by PostGarbageCollectionProcessing
// in reverse allocation order, so if second allocated handle is deleted,
// weak callback of the first handle would be able to 'reallocate' it.
- handle1.SetWeak(&handle1, NewPersistentHandleCallback);
+ handle1.SetWeak(&handle1, NewPersistentHandleCallback1,
+ v8::WeakCallbackType::kParameter);
handle2.Reset();
- CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ CcTest::heap()->CollectAllGarbage();
}
v8::Persistent<v8::Object> to_be_disposed;
-void DisposeAndForceGcCallback(
- const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
+
+void DisposeAndForceGcCallback2(
+ const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
to_be_disposed.Reset();
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
+}
+
+
+void DisposeAndForceGcCallback1(
+ const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
data.GetParameter()->Reset();
+ data.SetSecondPassCallback(DisposeAndForceGcCallback2);
}
handle1.Reset(isolate, v8::Object::New(isolate));
handle2.Reset(isolate, v8::Object::New(isolate));
}
- handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
+ handle1.SetWeak(&handle1, DisposeAndForceGcCallback1,
+ v8::WeakCallbackType::kParameter);
to_be_disposed.Reset(isolate, handle2);
- CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ CcTest::heap()->CollectAllGarbage();
}
void DisposingCallback(
- const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
+ const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
data.GetParameter()->Reset();
}
-void HandleCreatingCallback(
- const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
+void HandleCreatingCallback2(
+ const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
v8::HandleScope scope(data.GetIsolate());
- v8::Persistent<v8::Object>(data.GetIsolate(),
- v8::Object::New(data.GetIsolate()));
+ v8::Global<v8::Object>(data.GetIsolate(), v8::Object::New(data.GetIsolate()));
+}
+
+
+void HandleCreatingCallback1(
+ const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
data.GetParameter()->Reset();
+ data.SetSecondPassCallback(HandleCreatingCallback2);
}
handle2.Reset(isolate, v8::Object::New(isolate));
handle1.Reset(isolate, v8::Object::New(isolate));
}
- handle2.SetWeak(&handle2, DisposingCallback);
- handle3.SetWeak(&handle3, HandleCreatingCallback);
- CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ handle2.SetWeak(&handle2, DisposingCallback,
+ v8::WeakCallbackType::kParameter);
+ handle3.SetWeak(&handle3, HandleCreatingCallback1,
+ v8::WeakCallbackType::kParameter);
+ CcTest::heap()->CollectAllGarbage();
}
v8::Isolate::CreateParams create_params;
create_params.entry_hook = EntryHook;
create_params.code_event_handler = JitEvent;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
Reset();
// Make sure a second isolate is unaffected by the previous entry hook.
- isolate = v8::Isolate::New();
+ create_params = v8::Isolate::CreateParams();
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope scope(isolate);
CHECK(event->code_start != NULL);
CHECK_NE(0, static_cast<int>(event->code_len));
CHECK(event->name.str != NULL);
- i::HashMap::Entry* entry =
- code_map->Lookup(event->code_start,
- i::ComputePointerHash(event->code_start),
- true);
+ i::HashMap::Entry* entry = code_map->LookupOrInsert(
+ event->code_start, i::ComputePointerHash(event->code_start));
entry->value = reinterpret_cast<void*>(event->code_len);
if (FunctionNameIs("bar", event)) {
// Compiler::RecordFunctionCompilation) and the line endings
// calculations can cause a GC, which can move the newly created code
// before its existence can be logged.
- i::HashMap::Entry* entry =
- code_map->Lookup(event->code_start, hash, false);
+ i::HashMap::Entry* entry = code_map->Lookup(event->code_start, hash);
if (entry != NULL) {
++move_events;
CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
code_map->Remove(event->code_start, hash);
- entry = code_map->Lookup(event->new_code_start,
- i::ComputePointerHash(event->new_code_start),
- true);
- CHECK(entry != NULL);
+ entry = code_map->LookupOrInsert(
+ event->new_code_start,
+ i::ComputePointerHash(event->new_code_start));
entry->value = reinterpret_cast<void*>(event->code_len);
}
}
DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
temp_event->user_data = line_info;
- i::HashMap::Entry* entry =
- jitcode_line_info->Lookup(line_info,
- i::ComputePointerHash(line_info),
- true);
+ i::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert(
+ line_info, i::ComputePointerHash(line_info));
entry->value = reinterpret_cast<void*>(line_info);
}
break;
CHECK(event->user_data != NULL);
uint32_t hash = i::ComputePointerHash(event->user_data);
i::HashMap::Entry* entry =
- jitcode_line_info->Lookup(event->user_data, hash, false);
+ jitcode_line_info->Lookup(event->user_data, hash);
CHECK(entry != NULL);
delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
}
CHECK(event->user_data != NULL);
uint32_t hash = i::ComputePointerHash(event->user_data);
i::HashMap::Entry* entry =
- jitcode_line_info->Lookup(event->user_data, hash, false);
+ jitcode_line_info->Lookup(event->user_data, hash);
CHECK(entry != NULL);
}
break;
// Run this test in a new isolate to make sure we don't
// have remnants of state from other code.
- v8::Isolate* isolate = v8::Isolate::New();
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
isolate->Enter();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Heap* heap = i_isolate->heap();
isolate->Dispose();
// Do this in a new isolate.
- isolate = v8::Isolate::New();
+ isolate = v8::Isolate::New(create_params);
isolate->Enter();
// Verify that we get callbacks for existing code objects when we
TEST(CatchStackOverflow) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
v8::Handle<v8::Value> result = CompileRun(
"function f() {"
" return f();"
const char* resource_name,
int line_offset) {
v8::HandleScope scope(CcTest::isolate());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(CcTest::isolate());
v8::Handle<v8::Value> result = script->Run();
CHECK(result.IsEmpty());
CHECK(try_catch.HasCaught());
}
+THREADED_TEST(TryCatchSourceInfoForEOSError) {
+ LocalContext context;
+ v8::HandleScope scope(context->GetIsolate());
+ v8::TryCatch try_catch(context->GetIsolate());
+ v8::Script::Compile(v8_str("!\n"));
+ CHECK(try_catch.HasCaught());
+ v8::Handle<v8::Message> message = try_catch.Message();
+ CHECK_EQ(1, message->GetLineNumber());
+ CHECK_EQ(0, message->GetStartColumn());
+}
+
+
THREADED_TEST(CompilationCache) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
}
}
-static bool NamedSetAccessBlocker(Local<v8::Object> obj,
- Local<Value> name,
- v8::AccessType type,
- Local<Value> data) {
- return type != v8::ACCESS_SET;
-}
-
-
-static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
- uint32_t key,
- v8::AccessType type,
- Local<Value> data) {
- return type != v8::ACCESS_SET;
-}
-
-
-THREADED_TEST(DisableAccessChecksWhileConfiguring) {
- LocalContext context;
- v8::Isolate* isolate = context->GetIsolate();
- v8::HandleScope scope(isolate);
- Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
- templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
- IndexedSetAccessBlocker);
- templ->Set(v8_str("x"), v8::True(isolate));
- Local<v8::Object> instance = templ->NewInstance();
- context->Global()->Set(v8_str("obj"), instance);
- Local<Value> value = CompileRun("obj.x");
- CHECK(value->BooleanValue());
-}
-
-
-static bool NamedGetAccessBlocker(Local<v8::Object> obj,
- Local<Value> name,
- v8::AccessType type,
- Local<Value> data) {
- return false;
-}
-
-
-static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
- uint32_t key,
- v8::AccessType type,
- Local<Value> data) {
- return false;
-}
-
-
THREADED_TEST(AccessChecksReenabledCorrectly) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope scope(isolate);
Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
- templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
- IndexedGetAccessBlocker);
+ templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
templ->Set(v8_str("a"), v8_str("a"));
// Add more than 8 (see kMaxFastProperties) properties
// so that the constructor will force copying map.
}
-// This tests that access check information remains on the global
-// object template when creating contexts.
-THREADED_TEST(AccessControlRepeatedContextCreation) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::ObjectTemplate> global_template =
- v8::ObjectTemplate::New(isolate);
- global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
- IndexedSetAccessBlocker);
- i::Handle<i::ObjectTemplateInfo> internal_template =
- v8::Utils::OpenHandle(*global_template);
- CHECK(!internal_template->constructor()->IsUndefined());
- i::Handle<i::FunctionTemplateInfo> constructor(
- i::FunctionTemplateInfo::cast(internal_template->constructor()));
- CHECK(!constructor->access_check_info()->IsUndefined());
- v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
- CHECK(!context0.IsEmpty());
- CHECK(!constructor->access_check_info()->IsUndefined());
-}
-
-
-THREADED_TEST(TurnOnAccessCheck) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope handle_scope(isolate);
-
- // Create an environment with access check to the global object disabled by
- // default.
- v8::Handle<v8::ObjectTemplate> global_template =
- v8::ObjectTemplate::New(isolate);
- global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
- IndexedGetAccessBlocker,
- v8::Handle<v8::Value>(),
- false);
- v8::Local<Context> context = Context::New(isolate, NULL, global_template);
- Context::Scope context_scope(context);
-
- // Set up a property and a number of functions.
- context->Global()->Set(v8_str("a"), v8_num(1));
- CompileRun("function f1() {return a;}"
- "function f2() {return a;}"
- "function g1() {return h();}"
- "function g2() {return h();}"
- "function h() {return 1;}");
- Local<Function> f1 =
- Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
- Local<Function> f2 =
- Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
- Local<Function> g1 =
- Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
- Local<Function> g2 =
- Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
- Local<Function> h =
- Local<Function>::Cast(context->Global()->Get(v8_str("h")));
-
- // Get the global object.
- v8::Handle<v8::Object> global = context->Global();
-
- // Call f1 one time and f2 a number of times. This will ensure that f1 still
- // uses the runtime system to retreive property a whereas f2 uses global load
- // inline cache.
- CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
- for (int i = 0; i < 4; i++) {
- CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
- }
-
- // Same for g1 and g2.
- CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
- for (int i = 0; i < 4; i++) {
- CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
- }
-
- // Detach the global and turn on access check.
- Local<Object> hidden_global = Local<Object>::Cast(
- context->Global()->GetPrototype());
- context->DetachGlobal();
- hidden_global->TurnOnAccessCheck();
-
- // Failing access check results in exception.
- CHECK(f1->Call(global, 0, NULL).IsEmpty());
- CHECK(f2->Call(global, 0, NULL).IsEmpty());
- CHECK(g1->Call(global, 0, NULL).IsEmpty());
- CHECK(g2->Call(global, 0, NULL).IsEmpty());
-
- // No failing access check when just returning a constant.
- CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
-}
-
-
-static const char* kPropertyA = "a";
-static const char* kPropertyH = "h";
-
-static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
- Local<Value> name,
- v8::AccessType type,
- Local<Value> data) {
- if (!name->IsString()) return false;
- i::Handle<i::String> name_handle =
- v8::Utils::OpenHandle(String::Cast(*name));
- return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
- && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
-}
-
-
-THREADED_TEST(TurnOnAccessCheckAndRecompile) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope handle_scope(isolate);
-
- // Create an environment with access check to the global object disabled by
- // default. When the registered access checker will block access to properties
- // a and h.
- v8::Handle<v8::ObjectTemplate> global_template =
- v8::ObjectTemplate::New(isolate);
- global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
- IndexedGetAccessBlocker,
- v8::Handle<v8::Value>(),
- false);
- v8::Local<Context> context = Context::New(isolate, NULL, global_template);
- Context::Scope context_scope(context);
-
- // Set up a property and a number of functions.
- context->Global()->Set(v8_str("a"), v8_num(1));
- static const char* source = "function f1() {return a;}"
- "function f2() {return a;}"
- "function g1() {return h();}"
- "function g2() {return h();}"
- "function h() {return 1;}";
-
- CompileRun(source);
- Local<Function> f1;
- Local<Function> f2;
- Local<Function> g1;
- Local<Function> g2;
- Local<Function> h;
- f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
- f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
- g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
- g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
- h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
-
- // Get the global object.
- v8::Handle<v8::Object> global = context->Global();
-
- // Call f1 one time and f2 a number of times. This will ensure that f1 still
- // uses the runtime system to retreive property a whereas f2 uses global load
- // inline cache.
- CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
- for (int i = 0; i < 4; i++) {
- CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
- }
-
- // Same for g1 and g2.
- CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
- for (int i = 0; i < 4; i++) {
- CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
- }
-
- // Detach the global and turn on access check now blocking access to property
- // a and function h.
- Local<Object> hidden_global = Local<Object>::Cast(
- context->Global()->GetPrototype());
- context->DetachGlobal();
- hidden_global->TurnOnAccessCheck();
-
- // Failing access check results in exception.
- CHECK(f1->Call(global, 0, NULL).IsEmpty());
- CHECK(f2->Call(global, 0, NULL).IsEmpty());
- CHECK(g1->Call(global, 0, NULL).IsEmpty());
- CHECK(g2->Call(global, 0, NULL).IsEmpty());
-
- // No failing access check when just returning a constant.
- CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
-
- // Now compile the source again. And get the newly compiled functions, except
- // for h for which access is blocked.
- CompileRun(source);
- f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
- f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
- g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
- g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
- CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
-
- // Failing access check results in exception.
- v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
- CHECK(result.IsEmpty());
- CHECK(f1->Call(global, 0, NULL).IsEmpty());
- CHECK(f2->Call(global, 0, NULL).IsEmpty());
- CHECK(g1->Call(global, 0, NULL).IsEmpty());
- CHECK(g2->Call(global, 0, NULL).IsEmpty());
-}
-
-
// Tests that ScriptData can be serialized and deserialized.
TEST(PreCompileSerialization) {
v8::V8::Initialize();
v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) < 7;
v8::base::NoBarrier_AtomicIncrement(
®exp_interruption_data.loop_count, 1)) {
- v8::base::OS::Sleep(50); // Wait a bit before requesting GC.
+ // Wait a bit before requesting GC.
+ v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
}
- v8::base::OS::Sleep(50); // Wait a bit before terminating.
+ // Wait a bit before terminating.
+ v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
v8::V8::TerminateExecution(isolate_);
}
regexp_interruption_data.string_resource = new UC16VectorResource(
i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(CcTest::isolate());
timeout_thread.Start();
CompileRun("/((a*)*)*b/.exec(a)");
CHECK_EQ(3, global->Get(access_property)->Int32Value());
CHECK_EQ(1, force_set_set_count);
CHECK_EQ(2, force_set_get_count);
- // Forcing the property to be set should override the accessor without
- // calling it
+ // ForceSet doesn't call the accessors for now.
+ // TODO(verwaest): Update once blink doesn't rely on ForceSet to delete api
+ // accessors.
global->ForceSet(access_property, v8::Int32::New(isolate, 8));
CHECK_EQ(8, global->Get(access_property)->Int32Value());
CHECK_EQ(1, force_set_set_count);
TEST(ForceSetWithInterceptor) {
- force_set_get_count = 0;
- force_set_set_count = 0;
- pass_on_get = false;
-
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
ForceSetInterceptGetter, ForceSetInterceptSetter));
+ pass_on_get = true;
LocalContext context(NULL, templ);
v8::Handle<v8::Object> global = context->Global();
+ force_set_get_count = 0;
+ force_set_set_count = 0;
+ pass_on_get = false;
+
v8::Handle<v8::String> some_property =
v8::String::NewFromUtf8(isolate, "a");
CHECK_EQ(0, force_set_set_count);
}
-static v8::Local<Context> calling_context0;
-static v8::Local<Context> calling_context1;
-static v8::Local<Context> calling_context2;
-
+TEST(CreateDataProperty) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
-// Check that the call to the callback is initiated in
-// calling_context2, the directly calling context is calling_context1
-// and the callback itself is in calling_context0.
-static void GetCallingContextCallback(
- const v8::FunctionCallbackInfo<v8::Value>& args) {
- ApiTestFuzzer::Fuzz();
- CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
- CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
- CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
- args.GetReturnValue().Set(42);
-}
+ CompileRun(
+ "var a = {};"
+ "var b = [];"
+ "Object.defineProperty(a, 'foo', {value: 23});"
+ "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
+ v8::Local<v8::Object> obj =
+ v8::Local<v8::Object>::Cast(env->Global()->Get(v8_str("a")));
+ v8::Local<v8::Array> arr =
+ v8::Local<v8::Array>::Cast(env->Global()->Get(v8_str("b")));
+ {
+ // Can't change a non-configurable properties.
+ v8::TryCatch try_catch(isolate);
+ CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"),
+ v8::Integer::New(isolate, 42)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"),
+ v8::Integer::New(isolate, 42)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
-THREADED_TEST(GetCurrentContextWhenNotInContext) {
- i::Isolate* isolate = CcTest::i_isolate();
- CHECK(isolate != NULL);
- CHECK(isolate->context() == NULL);
- v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
- v8::HandleScope scope(v8_isolate);
- // The following should not crash, but return an empty handle.
- v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
- CHECK(current.IsEmpty());
-}
+ {
+ // Set a regular property.
+ v8::TryCatch try_catch(isolate);
+ CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"),
+ v8::Integer::New(isolate, 42)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
+ {
+ // Set an indexed property.
+ v8::TryCatch try_catch(isolate);
+ CHECK(obj->CreateDataProperty(env.local(), v8_str("1"),
+ v8::Integer::New(isolate, 42)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
-THREADED_TEST(GetCallingContext) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope scope(isolate);
+ {
+ // Special cases for arrays.
+ v8::TryCatch try_catch(isolate);
+ CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"),
+ v8::Integer::New(isolate, 1)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ }
+ {
+ // Special cases for arrays: index exceeds the array's length
+ v8::TryCatch try_catch(isolate);
+ CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23))
+ .FromJust());
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(2U, arr->Length());
+ v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
+
+ // Set an existing entry.
+ CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42))
+ .FromJust());
+ CHECK(!try_catch.HasCaught());
+ val = arr->Get(env.local(), 0).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
+
+ CompileRun("Object.freeze(a);");
+ {
+ // Can't change non-extensible objects.
+ v8::TryCatch try_catch(isolate);
+ CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"),
+ v8::Integer::New(isolate, 42)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ }
+
+ v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
+ templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
+ v8::Local<v8::Object> access_checked =
+ templ->NewInstance(env.local()).ToLocalChecked();
+ {
+ v8::TryCatch try_catch(isolate);
+ CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"),
+ v8::Integer::New(isolate, 42))
+ .IsNothing());
+ CHECK(try_catch.HasCaught());
+ }
+}
+
+
+TEST(DefineOwnProperty) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+
+ CompileRun(
+ "var a = {};"
+ "var b = [];"
+ "Object.defineProperty(a, 'foo', {value: 23});"
+ "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
+
+ v8::Local<v8::Object> obj =
+ v8::Local<v8::Object>::Cast(env->Global()->Get(v8_str("a")));
+ v8::Local<v8::Array> arr =
+ v8::Local<v8::Array>::Cast(env->Global()->Get(v8_str("b")));
+ {
+ // Can't change a non-configurable properties.
+ v8::TryCatch try_catch(isolate);
+ CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"),
+ v8::Integer::New(isolate, 42)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"),
+ v8::Integer::New(isolate, 42)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
+
+ {
+ // Set a regular property.
+ v8::TryCatch try_catch(isolate);
+ CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"),
+ v8::Integer::New(isolate, 42)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
+
+ {
+ // Set an indexed property.
+ v8::TryCatch try_catch(isolate);
+ CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"),
+ v8::Integer::New(isolate, 42)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
+
+ {
+ // Special cases for arrays.
+ v8::TryCatch try_catch(isolate);
+ CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"),
+ v8::Integer::New(isolate, 1)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ }
+ {
+ // Special cases for arrays: index exceeds the array's length
+ v8::TryCatch try_catch(isolate);
+ CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"),
+ v8::Integer::New(isolate, 23)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(2U, arr->Length());
+ v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
+
+ // Set an existing entry.
+ CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"),
+ v8::Integer::New(isolate, 42)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ val = arr->Get(env.local(), 0).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
+
+ {
+ // Set a non-writable property.
+ v8::TryCatch try_catch(isolate);
+ CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"),
+ v8::Integer::New(isolate, 42),
+ v8::ReadOnly).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("lala")).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes(
+ env.local(), v8_str("lala")).FromJust());
+ CHECK(!try_catch.HasCaught());
+ }
+
+ CompileRun("Object.freeze(a);");
+ {
+ // Can't change non-extensible objects.
+ v8::TryCatch try_catch(isolate);
+ CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"),
+ v8::Integer::New(isolate, 42)).FromJust());
+ CHECK(!try_catch.HasCaught());
+ }
+
+ v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
+ templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
+ v8::Local<v8::Object> access_checked =
+ templ->NewInstance(env.local()).ToLocalChecked();
+ {
+ v8::TryCatch try_catch(isolate);
+ CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"),
+ v8::Integer::New(isolate, 42))
+ .IsNothing());
+ CHECK(try_catch.HasCaught());
+ }
+}
+
+
+static v8::Local<Context> calling_context0;
+static v8::Local<Context> calling_context1;
+static v8::Local<Context> calling_context2;
+
+
+// Check that the call to the callback is initiated in
+// calling_context2, the directly calling context is calling_context1
+// and the callback itself is in calling_context0.
+static void GetCallingContextCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ ApiTestFuzzer::Fuzz();
+ CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
+ CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
+ CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
+ args.GetReturnValue().Set(42);
+}
+
+
+THREADED_TEST(GetCurrentContextWhenNotInContext) {
+ i::Isolate* isolate = CcTest::i_isolate();
+ CHECK(isolate != NULL);
+ CHECK(isolate->context() == NULL);
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+ v8::HandleScope scope(v8_isolate);
+ // The following should not crash, but return an empty handle.
+ v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
+ CHECK(current.IsEmpty());
+}
+
+
+THREADED_TEST(GetCallingContext) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
Local<Context> calling_context0(Context::New(isolate));
Local<Context> calling_context1(Context::New(isolate));
}
-THREADED_TEST(PixelArray) {
- LocalContext context;
- i::Isolate* isolate = CcTest::i_isolate();
- i::Factory* factory = isolate->factory();
- v8::HandleScope scope(context->GetIsolate());
- const int kElementCount = 260;
- uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
- i::Handle<i::ExternalUint8ClampedArray> pixels =
- i::Handle<i::ExternalUint8ClampedArray>::cast(
- factory->NewExternalArray(kElementCount,
- v8::kExternalUint8ClampedArray,
- pixel_data));
- // Force GC to trigger verification.
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- for (int i = 0; i < kElementCount; i++) {
- pixels->set(i, i % 256);
- }
- // Force GC to trigger verification.
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- for (int i = 0; i < kElementCount; i++) {
- CHECK_EQ(i % 256, pixels->get_scalar(i));
- CHECK_EQ(i % 256, pixel_data[i]);
- }
-
- v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
+template <class ExternalArrayClass, class ElementType>
+static void ObjectWithExternalArrayTestHelper(Handle<Context> context,
+ v8::Handle<Object> obj,
+ int element_count,
+ i::ExternalArrayType array_type,
+ int64_t low, int64_t high) {
i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
- // Set the elements to be the pixels.
- // jsobj->set_elements(*pixels);
- obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
- CheckElementValue(isolate, 1, jsobj, 1);
- obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
- context->Global()->Set(v8_str("pixels"), obj);
- v8::Handle<v8::Value> result = CompileRun("pixels.field");
+ i::Isolate* isolate = jsobj->GetIsolate();
+ obj->Set(v8_str("field"),
+ v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
+ context->Global()->Set(v8_str("ext_array"), obj);
+ v8::Handle<v8::Value> result = CompileRun("ext_array.field");
CHECK_EQ(1503, result->Int32Value());
- result = CompileRun("pixels[1]");
+ result = CompileRun("ext_array[1]");
CHECK_EQ(1, result->Int32Value());
- result = CompileRun("var sum = 0;"
+ // Check assigned smis
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = i;"
+ "}"
+ "var sum = 0;"
"for (var i = 0; i < 8; i++) {"
- " sum += pixels[i] = pixels[i] = -i;"
+ " sum += ext_array[i];"
"}"
"sum;");
- CHECK_EQ(-28, result->Int32Value());
+ CHECK_EQ(28, result->Int32Value());
+ // Check pass through of assigned smis
result = CompileRun("var sum = 0;"
"for (var i = 0; i < 8; i++) {"
- " sum += pixels[i] = pixels[i] = 0;"
+ " sum += ext_array[i] = ext_array[i] = -i;"
"}"
"sum;");
- CHECK_EQ(0, result->Int32Value());
+ CHECK_EQ(-28, result->Int32Value());
- result = CompileRun("var sum = 0;"
+
+ // Check assigned smis in reverse order
+ result = CompileRun("for (var i = 8; --i >= 0; ) {"
+ " ext_array[i] = i;"
+ "}"
+ "var sum = 0;"
"for (var i = 0; i < 8; i++) {"
- " sum += pixels[i] = pixels[i] = 255;"
+ " sum += ext_array[i];"
"}"
"sum;");
- CHECK_EQ(8 * 255, result->Int32Value());
+ CHECK_EQ(28, result->Int32Value());
+ // Check pass through of assigned HeapNumbers
result = CompileRun("var sum = 0;"
- "for (var i = 0; i < 8; i++) {"
- " sum += pixels[i] = pixels[i] = 256 + i;"
+ "for (var i = 0; i < 16; i+=2) {"
+ " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
"}"
"sum;");
- CHECK_EQ(2076, result->Int32Value());
+ CHECK_EQ(-28, result->Int32Value());
- result = CompileRun("var sum = 0;"
- "for (var i = 0; i < 8; i++) {"
- " sum += pixels[i] = pixels[i] = i;"
+ // Check assigned HeapNumbers
+ result = CompileRun("for (var i = 0; i < 16; i+=2) {"
+ " ext_array[i] = (i * 0.5);"
+ "}"
+ "var sum = 0;"
+ "for (var i = 0; i < 16; i+=2) {"
+ " sum += ext_array[i];"
"}"
"sum;");
CHECK_EQ(28, result->Int32Value());
- result = CompileRun("var sum = 0;"
- "for (var i = 0; i < 8; i++) {"
- " sum += pixels[i];"
+ // Check assigned HeapNumbers in reverse order
+ result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
+ " ext_array[i] = (i * 0.5);"
+ "}"
+ "var sum = 0;"
+ "for (var i = 0; i < 16; i+=2) {"
+ " sum += ext_array[i];"
"}"
"sum;");
CHECK_EQ(28, result->Int32Value());
- i::Handle<i::Smi> value(i::Smi::FromInt(2),
- reinterpret_cast<i::Isolate*>(context->GetIsolate()));
- i::Handle<i::Object> no_failure;
- no_failure = i::JSObject::SetElement(
- jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
- DCHECK(!no_failure.is_null());
- USE(no_failure);
- CheckElementValue(isolate, 2, jsobj, 1);
- *value.location() = i::Smi::FromInt(256);
- no_failure = i::JSObject::SetElement(
- jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
- DCHECK(!no_failure.is_null());
- USE(no_failure);
- CheckElementValue(isolate, 255, jsobj, 1);
- *value.location() = i::Smi::FromInt(-1);
- no_failure = i::JSObject::SetElement(
- jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
- DCHECK(!no_failure.is_null());
- USE(no_failure);
- CheckElementValue(isolate, 0, jsobj, 1);
+ i::ScopedVector<char> test_buf(1024);
- result = CompileRun("for (var i = 0; i < 8; i++) {"
- " pixels[i] = (i * 65) - 109;"
- "}"
- "pixels[1] + pixels[6];");
- CHECK_EQ(255, result->Int32Value());
- CheckElementValue(isolate, 0, jsobj, 0);
- CheckElementValue(isolate, 0, jsobj, 1);
- CheckElementValue(isolate, 21, jsobj, 2);
- CheckElementValue(isolate, 86, jsobj, 3);
- CheckElementValue(isolate, 151, jsobj, 4);
- CheckElementValue(isolate, 216, jsobj, 5);
- CheckElementValue(isolate, 255, jsobj, 6);
- CheckElementValue(isolate, 255, jsobj, 7);
- result = CompileRun("var sum = 0;"
+ // Check legal boundary conditions.
+ // The repeated loads and stores ensure the ICs are exercised.
+ const char* boundary_program =
+ "var res = 0;"
+ "for (var i = 0; i < 16; i++) {"
+ " ext_array[i] = %lld;"
+ " if (i > 8) {"
+ " res = ext_array[i];"
+ " }"
+ "}"
+ "res;";
+ i::SNPrintF(test_buf,
+ boundary_program,
+ low);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(low, result->IntegerValue());
+
+ i::SNPrintF(test_buf,
+ boundary_program,
+ high);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(high, result->IntegerValue());
+
+ // Check misprediction of type in IC.
+ result = CompileRun("var tmp_array = ext_array;"
+ "var sum = 0;"
"for (var i = 0; i < 8; i++) {"
- " sum += pixels[i];"
+ " tmp_array[i] = i;"
+ " sum += tmp_array[i];"
+ " if (i == 4) {"
+ " tmp_array = {};"
+ " }"
"}"
"sum;");
- CHECK_EQ(984, result->Int32Value());
+ // Force GC to trigger verification.
+ CcTest::heap()->CollectAllGarbage();
+ CHECK_EQ(28, result->Int32Value());
- result = CompileRun("for (var i = 0; i < 8; i++) {"
- " pixels[i] = (i * 1.1);"
- "}"
- "pixels[1] + pixels[6];");
- CHECK_EQ(8, result->Int32Value());
- CheckElementValue(isolate, 0, jsobj, 0);
- CheckElementValue(isolate, 1, jsobj, 1);
- CheckElementValue(isolate, 2, jsobj, 2);
- CheckElementValue(isolate, 3, jsobj, 3);
- CheckElementValue(isolate, 4, jsobj, 4);
- CheckElementValue(isolate, 6, jsobj, 5);
- CheckElementValue(isolate, 7, jsobj, 6);
- CheckElementValue(isolate, 8, jsobj, 7);
+ // Make sure out-of-range loads do not throw.
+ i::SNPrintF(test_buf,
+ "var caught_exception = false;"
+ "try {"
+ " ext_array[%d];"
+ "} catch (e) {"
+ " caught_exception = true;"
+ "}"
+ "caught_exception;",
+ element_count);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(false, result->BooleanValue());
+
+ // Make sure out-of-range stores do not throw.
+ i::SNPrintF(test_buf,
+ "var caught_exception = false;"
+ "try {"
+ " ext_array[%d] = 1;"
+ "} catch (e) {"
+ " caught_exception = true;"
+ "}"
+ "caught_exception;",
+ element_count);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(false, result->BooleanValue());
+ // Check other boundary conditions, values and operations.
result = CompileRun("for (var i = 0; i < 8; i++) {"
- " pixels[7] = undefined;"
+ " ext_array[7] = undefined;"
"}"
- "pixels[7];");
+ "ext_array[7];");
CHECK_EQ(0, result->Int32Value());
- CheckElementValue(isolate, 0, jsobj, 7);
+ if (array_type == i::kExternalFloat64Array ||
+ array_type == i::kExternalFloat32Array) {
+ CHECK(std::isnan(
+ i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
+ } else {
+ CheckElementValue(isolate, 0, jsobj, 7);
+ }
result = CompileRun("for (var i = 0; i < 8; i++) {"
- " pixels[6] = '2.3';"
+ " ext_array[6] = '2.3';"
"}"
- "pixels[6];");
+ "ext_array[6];");
CHECK_EQ(2, result->Int32Value());
- CheckElementValue(isolate, 2, jsobj, 6);
+ CHECK_EQ(2,
+ static_cast<int>(
+ i::Object::GetElement(
+ isolate, jsobj, 6).ToHandleChecked()->Number()));
- result = CompileRun("for (var i = 0; i < 8; i++) {"
- " pixels[5] = NaN;"
- "}"
- "pixels[5];");
- CHECK_EQ(0, result->Int32Value());
- CheckElementValue(isolate, 0, jsobj, 5);
+ if (array_type != i::kExternalFloat32Array &&
+ array_type != i::kExternalFloat64Array) {
+ // Though the specification doesn't state it, be explicit about
+ // converting NaNs and +/-Infinity to zero.
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = 5;"
+ "}"
+ "for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = NaN;"
+ "}"
+ "ext_array[5];");
+ CHECK_EQ(0, result->Int32Value());
+ CheckElementValue(isolate, 0, jsobj, 5);
- result = CompileRun("for (var i = 0; i < 8; i++) {"
- " pixels[8] = Infinity;"
- "}"
- "pixels[8];");
- CHECK_EQ(255, result->Int32Value());
- CheckElementValue(isolate, 255, jsobj, 8);
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = 5;"
+ "}"
+ "for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = Infinity;"
+ "}"
+ "ext_array[5];");
+ int expected_value =
+ (array_type == i::kExternalUint8ClampedArray) ? 255 : 0;
+ CHECK_EQ(expected_value, result->Int32Value());
+ CheckElementValue(isolate, expected_value, jsobj, 5);
- result = CompileRun("for (var i = 0; i < 8; i++) {"
- " pixels[9] = -Infinity;"
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = 5;"
+ "}"
+ "for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = -Infinity;"
+ "}"
+ "ext_array[5];");
+ CHECK_EQ(0, result->Int32Value());
+ CheckElementValue(isolate, 0, jsobj, 5);
+
+ // Check truncation behavior of integral arrays.
+ const char* unsigned_data =
+ "var source_data = [0.6, 10.6];"
+ "var expected_results = [0, 10];";
+ const char* signed_data =
+ "var source_data = [0.6, 10.6, -0.6, -10.6];"
+ "var expected_results = [0, 10, 0, -10];";
+ const char* pixel_data =
+ "var source_data = [0.6, 10.6];"
+ "var expected_results = [1, 11];";
+ bool is_unsigned = (array_type == i::kExternalUint8Array ||
+ array_type == i::kExternalUint16Array ||
+ array_type == i::kExternalUint32Array);
+ bool is_pixel_data = array_type == i::kExternalUint8ClampedArray;
+
+ i::SNPrintF(test_buf,
+ "%s"
+ "var all_passed = true;"
+ "for (var i = 0; i < source_data.length; i++) {"
+ " for (var j = 0; j < 8; j++) {"
+ " ext_array[j] = source_data[i];"
+ " }"
+ " all_passed = all_passed &&"
+ " (ext_array[5] == expected_results[i]);"
+ "}"
+ "all_passed;",
+ (is_unsigned ?
+ unsigned_data :
+ (is_pixel_data ? pixel_data : signed_data)));
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(true, result->BooleanValue());
+ }
+
+ i::Handle<ExternalArrayClass> array(
+ ExternalArrayClass::cast(jsobj->elements()));
+ for (int i = 0; i < element_count; i++) {
+ array->set(i, static_cast<ElementType>(i));
+ }
+
+ // Test complex assignments
+ result = CompileRun("function ee_op_test_complex_func(sum) {"
+ " for (var i = 0; i < 40; ++i) {"
+ " sum += (ext_array[i] += 1);"
+ " sum += (ext_array[i] -= 1);"
+ " } "
+ " return sum;"
"}"
- "pixels[9];");
- CHECK_EQ(0, result->Int32Value());
- CheckElementValue(isolate, 0, jsobj, 9);
+ "sum=0;"
+ "for (var i=0;i<10000;++i) {"
+ " sum=ee_op_test_complex_func(sum);"
+ "}"
+ "sum;");
+ CHECK_EQ(16000000, result->Int32Value());
+
+ // Test count operations
+ result = CompileRun("function ee_op_test_count_func(sum) {"
+ " for (var i = 0; i < 40; ++i) {"
+ " sum += (++ext_array[i]);"
+ " sum += (--ext_array[i]);"
+ " } "
+ " return sum;"
+ "}"
+ "sum=0;"
+ "for (var i=0;i<10000;++i) {"
+ " sum=ee_op_test_count_func(sum);"
+ "}"
+ "sum;");
+ CHECK_EQ(16000000, result->Int32Value());
- result = CompileRun("pixels[3] = 33;"
- "delete pixels[3];"
- "pixels[3];");
+ result = CompileRun("ext_array[3] = 33;"
+ "delete ext_array[3];"
+ "ext_array[3];");
CHECK_EQ(33, result->Int32Value());
- result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
- "pixels[2] = 12; pixels[3] = 13;"
- "pixels.__defineGetter__('2',"
+ result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
+ "ext_array[2] = 12; ext_array[3] = 13;"
+ "ext_array.__defineGetter__('2',"
"function() { return 120; });"
- "pixels[2];");
+ "ext_array[2];");
CHECK_EQ(12, result->Int32Value());
result = CompileRun("var js_array = new Array(40);"
"js_array;");
CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
- result = CompileRun("pixels[1] = 23;"
- "pixels.__proto__ = [];"
- "js_array.__proto__ = pixels;"
- "js_array.concat(pixels);");
+ result = CompileRun("ext_array[1] = 23;"
+ "ext_array.__proto__ = [];"
+ "js_array.__proto__ = ext_array;"
+ "js_array.concat(ext_array);");
CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
- result = CompileRun("pixels[1] = 23;");
+ result = CompileRun("ext_array[1] = 23;");
CHECK_EQ(23, result->Int32Value());
+}
- // Test for index greater than 255. Regression test for:
- // http://code.google.com/p/chromium/issues/detail?id=26337.
- result = CompileRun("pixels[256] = 255;");
- CHECK_EQ(255, result->Int32Value());
- result = CompileRun("var i = 0;"
- "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
- "i");
- CHECK_EQ(255, result->Int32Value());
-
- // Make sure that pixel array ICs recognize when a non-pixel array
- // is passed to it.
- result = CompileRun("function pa_load(p) {"
- " var sum = 0;"
- " for (var j = 0; j < 256; j++) { sum += p[j]; }"
- " return sum;"
- "}"
- "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
- "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
- "just_ints = new Object();"
- "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
- "for (var i = 0; i < 10; ++i) {"
- " result = pa_load(just_ints);"
- "}"
- "result");
- CHECK_EQ(32640, result->Int32Value());
-
- // Make sure that pixel array ICs recognize out-of-bound accesses.
- result = CompileRun("function pa_load(p, start) {"
- " var sum = 0;"
- " for (var j = start; j < 256; j++) { sum += p[j]; }"
- " return sum;"
- "}"
- "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
- "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
- "for (var i = 0; i < 10; ++i) {"
- " result = pa_load(pixels,-10);"
- "}"
- "result");
- CHECK_EQ(0, result->Int32Value());
- // Make sure that generic ICs properly handles a pixel array.
- result = CompileRun("function pa_load(p) {"
- " var sum = 0;"
- " for (var j = 0; j < 256; j++) { sum += p[j]; }"
- " return sum;"
- "}"
- "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
- "just_ints = new Object();"
- "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
- "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
- "for (var i = 0; i < 10; ++i) {"
- " result = pa_load(pixels);"
- "}"
- "result");
- CHECK_EQ(32640, result->Int32Value());
-
- // Make sure that generic load ICs recognize out-of-bound accesses in
- // pixel arrays.
- result = CompileRun("function pa_load(p, start) {"
- " var sum = 0;"
- " for (var j = start; j < 256; j++) { sum += p[j]; }"
- " return sum;"
- "}"
- "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
- "just_ints = new Object();"
- "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
- "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
- "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
- "for (var i = 0; i < 10; ++i) {"
- " result = pa_load(pixels,-10);"
- "}"
- "result");
- CHECK_EQ(0, result->Int32Value());
+template <class FixedTypedArrayClass, i::ElementsKind elements_kind,
+ class ElementType>
+static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type,
+ ElementType low, ElementType high) {
+ i::FLAG_allow_natives_syntax = true;
+ LocalContext context;
+ i::Isolate* isolate = CcTest::i_isolate();
+ i::Factory* factory = isolate->factory();
+ v8::HandleScope scope(context->GetIsolate());
+ const int kElementCount = 260;
+ i::Handle<i::JSTypedArray> jsobj =
+ factory->NewJSTypedArray(elements_kind, kElementCount);
+ i::Handle<FixedTypedArrayClass> fixed_array(
+ FixedTypedArrayClass::cast(jsobj->elements()));
+ CHECK_EQ(FixedTypedArrayClass::kInstanceType,
+ fixed_array->map()->instance_type());
+ CHECK_EQ(kElementCount, fixed_array->length());
+ CcTest::heap()->CollectAllGarbage();
+ for (int i = 0; i < kElementCount; i++) {
+ fixed_array->set(i, static_cast<ElementType>(i));
+ }
+ // Force GC to trigger verification.
+ CcTest::heap()->CollectAllGarbage();
+ for (int i = 0; i < kElementCount; i++) {
+ CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
+ static_cast<int64_t>(fixed_array->get_scalar(i)));
+ }
+ v8::Handle<v8::Object> obj = v8::Utils::ToLocal(jsobj);
- // Make sure that generic ICs properly handles other types than pixel
- // arrays (that the inlined fast pixel array test leaves the right information
- // in the right registers).
- result = CompileRun("function pa_load(p) {"
- " var sum = 0;"
- " for (var j = 0; j < 256; j++) { sum += p[j]; }"
- " return sum;"
- "}"
- "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
- "just_ints = new Object();"
- "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
- "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
- "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
- "sparse_array = new Object();"
- "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
- "sparse_array[1000000] = 3;"
- "for (var i = 0; i < 10; ++i) {"
- " result = pa_load(sparse_array);"
- "}"
- "result");
- CHECK_EQ(32640, result->Int32Value());
+ ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
+ context.local(), obj, kElementCount, array_type,
+ static_cast<int64_t>(low),
+ static_cast<int64_t>(high));
+}
- // Make sure that pixel array store ICs clamp values correctly.
- result = CompileRun("function pa_store(p) {"
- " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
- "}"
- "pa_store(pixels);"
- "var sum = 0;"
- "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
- "sum");
- CHECK_EQ(48896, result->Int32Value());
-
- // Make sure that pixel array stores correctly handle accesses outside
- // of the pixel array..
- result = CompileRun("function pa_store(p,start) {"
- " for (var j = 0; j < 256; j++) {"
- " p[j+start] = j * 2;"
- " }"
- "}"
- "pa_store(pixels,0);"
- "pa_store(pixels,-128);"
- "var sum = 0;"
- "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
- "sum");
- CHECK_EQ(65280, result->Int32Value());
-
- // Make sure that the generic store stub correctly handle accesses outside
- // of the pixel array..
- result = CompileRun("function pa_store(p,start) {"
- " for (var j = 0; j < 256; j++) {"
- " p[j+start] = j * 2;"
- " }"
- "}"
- "pa_store(pixels,0);"
- "just_ints = new Object();"
- "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
- "pa_store(just_ints, 0);"
- "pa_store(pixels,-128);"
- "var sum = 0;"
- "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
- "sum");
- CHECK_EQ(65280, result->Int32Value());
-
- // Make sure that the generic keyed store stub clamps pixel array values
- // correctly.
- result = CompileRun("function pa_store(p) {"
- " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
- "}"
- "pa_store(pixels);"
- "just_ints = new Object();"
- "pa_store(just_ints);"
- "pa_store(pixels);"
- "var sum = 0;"
- "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
- "sum");
- CHECK_EQ(48896, result->Int32Value());
-
- // Make sure that pixel array loads are optimized by crankshaft.
- result = CompileRun("function pa_load(p) {"
- " var sum = 0;"
- " for (var i=0; i<256; ++i) {"
- " sum += p[i];"
- " }"
- " return sum; "
- "}"
- "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
- "for (var i = 0; i < 5000; ++i) {"
- " result = pa_load(pixels);"
- "}"
- "result");
- CHECK_EQ(32640, result->Int32Value());
- // Make sure that pixel array stores are optimized by crankshaft.
- result = CompileRun("function pa_init(p) {"
- "for (var i = 0; i < 256; ++i) { p[i] = i; }"
- "}"
- "function pa_load(p) {"
- " var sum = 0;"
- " for (var i=0; i<256; ++i) {"
- " sum += p[i];"
- " }"
- " return sum; "
- "}"
- "for (var i = 0; i < 5000; ++i) {"
- " pa_init(pixels);"
- "}"
- "result = pa_load(pixels);"
- "result");
- CHECK_EQ(32640, result->Int32Value());
+THREADED_TEST(FixedUint8Array) {
+ FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
+ i::kExternalUint8Array, 0x0, 0xFF);
+}
- free(pixel_data);
+
+THREADED_TEST(FixedUint8ClampedArray) {
+ FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
+ i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
+ i::kExternalUint8ClampedArray, 0x0, 0xFF);
}
-THREADED_TEST(PixelArrayInfo) {
- LocalContext context;
- v8::HandleScope scope(context->GetIsolate());
- for (int size = 0; size < 100; size += 10) {
- uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
- v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
- obj->SetIndexedPropertiesToPixelData(pixel_data, size);
- CHECK(obj->HasIndexedPropertiesInPixelData());
- CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
- CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
- free(pixel_data);
- }
+THREADED_TEST(FixedInt8Array) {
+ FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
+ i::kExternalInt8Array, -0x80, 0x7F);
}
-static void NotHandledIndexedPropertyGetter(
- uint32_t index,
- const v8::PropertyCallbackInfo<v8::Value>& info) {
- ApiTestFuzzer::Fuzz();
+THREADED_TEST(FixedUint16Array) {
+ FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
+ i::kExternalUint16Array, 0x0, 0xFFFF);
}
-static void NotHandledIndexedPropertySetter(
- uint32_t index,
- Local<Value> value,
- const v8::PropertyCallbackInfo<v8::Value>& info) {
- ApiTestFuzzer::Fuzz();
+THREADED_TEST(FixedInt16Array) {
+ FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
+ i::kExternalInt16Array, -0x8000, 0x7FFF);
}
-THREADED_TEST(PixelArrayWithInterceptor) {
- LocalContext context;
- i::Factory* factory = CcTest::i_isolate()->factory();
- v8::Isolate* isolate = context->GetIsolate();
- v8::HandleScope scope(isolate);
- const int kElementCount = 260;
- uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
- i::Handle<i::ExternalUint8ClampedArray> pixels =
- i::Handle<i::ExternalUint8ClampedArray>::cast(
- factory->NewExternalArray(kElementCount,
- v8::kExternalUint8ClampedArray,
- pixel_data));
- for (int i = 0; i < kElementCount; i++) {
- pixels->set(i, i % 256);
- }
- v8::Handle<v8::ObjectTemplate> templ =
- v8::ObjectTemplate::New(context->GetIsolate());
- templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
- NotHandledIndexedPropertyGetter, NotHandledIndexedPropertySetter));
- v8::Handle<v8::Object> obj = templ->NewInstance();
- obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
- context->Global()->Set(v8_str("pixels"), obj);
- v8::Handle<v8::Value> result = CompileRun("pixels[1]");
- CHECK_EQ(1, result->Int32Value());
- result = CompileRun("var sum = 0;"
- "for (var i = 0; i < 8; i++) {"
- " sum += pixels[i] = pixels[i] = -i;"
- "}"
- "sum;");
- CHECK_EQ(-28, result->Int32Value());
- result = CompileRun("pixels.hasOwnProperty('1')");
- CHECK(result->BooleanValue());
- free(pixel_data);
+THREADED_TEST(FixedUint32Array) {
+ FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
+ i::kExternalUint32Array, 0x0, UINT_MAX);
}
-static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
- switch (array_type) {
- case v8::kExternalInt8Array:
- case v8::kExternalUint8Array:
- case v8::kExternalUint8ClampedArray:
- return 1;
- break;
- case v8::kExternalInt16Array:
- case v8::kExternalUint16Array:
- return 2;
- break;
- case v8::kExternalInt32Array:
- case v8::kExternalUint32Array:
- case v8::kExternalFloat32Array:
- return 4;
- break;
- case v8::kExternalFloat64Array:
- return 8;
- break;
- default:
- UNREACHABLE();
- return -1;
- }
- UNREACHABLE();
- return -1;
+THREADED_TEST(FixedInt32Array) {
+ FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
+ i::kExternalInt32Array, INT_MIN, INT_MAX);
}
-template <class ExternalArrayClass, class ElementType>
-static void ObjectWithExternalArrayTestHelper(
- Handle<Context> context,
- v8::Handle<Object> obj,
- int element_count,
- v8::ExternalArrayType array_type,
- int64_t low, int64_t high) {
- i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
- i::Isolate* isolate = jsobj->GetIsolate();
- obj->Set(v8_str("field"),
- v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
- context->Global()->Set(v8_str("ext_array"), obj);
- v8::Handle<v8::Value> result = CompileRun("ext_array.field");
- CHECK_EQ(1503, result->Int32Value());
- result = CompileRun("ext_array[1]");
- CHECK_EQ(1, result->Int32Value());
+THREADED_TEST(FixedFloat32Array) {
+ FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
+ i::kExternalFloat32Array, -500, 500);
+}
- // Check assigned smis
- result = CompileRun("for (var i = 0; i < 8; i++) {"
- " ext_array[i] = i;"
- "}"
- "var sum = 0;"
- "for (var i = 0; i < 8; i++) {"
- " sum += ext_array[i];"
- "}"
- "sum;");
- CHECK_EQ(28, result->Int32Value());
- // Check pass through of assigned smis
- result = CompileRun("var sum = 0;"
- "for (var i = 0; i < 8; i++) {"
- " sum += ext_array[i] = ext_array[i] = -i;"
- "}"
- "sum;");
- CHECK_EQ(-28, result->Int32Value());
+THREADED_TEST(FixedFloat64Array) {
+ FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
+ i::kExternalFloat64Array, -500, 500);
+}
- // Check assigned smis in reverse order
- result = CompileRun("for (var i = 8; --i >= 0; ) {"
- " ext_array[i] = i;"
- "}"
- "var sum = 0;"
- "for (var i = 0; i < 8; i++) {"
- " sum += ext_array[i];"
- "}"
- "sum;");
- CHECK_EQ(28, result->Int32Value());
+template <typename ElementType, typename TypedArray, class ExternalArrayClass,
+ class ArrayBufferType>
+void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low,
+ int64_t high) {
+ const int kElementCount = 50;
- // Check pass through of assigned HeapNumbers
- result = CompileRun("var sum = 0;"
- "for (var i = 0; i < 16; i+=2) {"
- " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
- "}"
- "sum;");
- CHECK_EQ(-28, result->Int32Value());
+ i::ScopedVector<ElementType> backing_store(kElementCount+2);
- // Check assigned HeapNumbers
- result = CompileRun("for (var i = 0; i < 16; i+=2) {"
- " ext_array[i] = (i * 0.5);"
- "}"
- "var sum = 0;"
- "for (var i = 0; i < 16; i+=2) {"
- " sum += ext_array[i];"
- "}"
- "sum;");
- CHECK_EQ(28, result->Int32Value());
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
- // Check assigned HeapNumbers in reverse order
- result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
- " ext_array[i] = (i * 0.5);"
- "}"
- "var sum = 0;"
- "for (var i = 0; i < 16; i+=2) {"
- " sum += ext_array[i];"
- "}"
- "sum;");
- CHECK_EQ(28, result->Int32Value());
-
- i::ScopedVector<char> test_buf(1024);
+ Local<ArrayBufferType> ab =
+ ArrayBufferType::New(isolate, backing_store.start(),
+ (kElementCount + 2) * sizeof(ElementType));
+ Local<TypedArray> ta =
+ TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
+ CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
+ CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
+ CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
+ CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
+ CHECK(ab->Equals(ta->Buffer()));
- // Check legal boundary conditions.
- // The repeated loads and stores ensure the ICs are exercised.
- const char* boundary_program =
- "var res = 0;"
- "for (var i = 0; i < 16; i++) {"
- " ext_array[i] = %lld;"
- " if (i > 8) {"
- " res = ext_array[i];"
- " }"
- "}"
- "res;";
- i::SNPrintF(test_buf,
- boundary_program,
- low);
- result = CompileRun(test_buf.start());
- CHECK_EQ(low, result->IntegerValue());
+ ElementType* data = backing_store.start() + 2;
+ for (int i = 0; i < kElementCount; i++) {
+ data[i] = static_cast<ElementType>(i);
+ }
- i::SNPrintF(test_buf,
- boundary_program,
- high);
- result = CompileRun(test_buf.start());
- CHECK_EQ(high, result->IntegerValue());
+ ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
+ env.local(), ta, kElementCount, array_type, low, high);
+}
- // Check misprediction of type in IC.
- result = CompileRun("var tmp_array = ext_array;"
- "var sum = 0;"
- "for (var i = 0; i < 8; i++) {"
- " tmp_array[i] = i;"
- " sum += tmp_array[i];"
- " if (i == 4) {"
- " tmp_array = {};"
- " }"
- "}"
- "sum;");
- // Force GC to trigger verification.
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- CHECK_EQ(28, result->Int32Value());
- // Make sure out-of-range loads do not throw.
- i::SNPrintF(test_buf,
- "var caught_exception = false;"
- "try {"
- " ext_array[%d];"
- "} catch (e) {"
- " caught_exception = true;"
- "}"
- "caught_exception;",
- element_count);
- result = CompileRun(test_buf.start());
- CHECK_EQ(false, result->BooleanValue());
+THREADED_TEST(Uint8Array) {
+ TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array,
+ v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
+}
- // Make sure out-of-range stores do not throw.
- i::SNPrintF(test_buf,
- "var caught_exception = false;"
- "try {"
- " ext_array[%d] = 1;"
- "} catch (e) {"
- " caught_exception = true;"
- "}"
- "caught_exception;",
- element_count);
- result = CompileRun(test_buf.start());
- CHECK_EQ(false, result->BooleanValue());
- // Check other boundary conditions, values and operations.
- result = CompileRun("for (var i = 0; i < 8; i++) {"
- " ext_array[7] = undefined;"
- "}"
- "ext_array[7];");
- CHECK_EQ(0, result->Int32Value());
- if (array_type == v8::kExternalFloat64Array ||
- array_type == v8::kExternalFloat32Array) {
- CHECK(std::isnan(
- i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
- } else {
- CheckElementValue(isolate, 0, jsobj, 7);
- }
+THREADED_TEST(Int8Array) {
+ TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array,
+ v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F);
+}
- result = CompileRun("for (var i = 0; i < 8; i++) {"
- " ext_array[6] = '2.3';"
- "}"
- "ext_array[6];");
- CHECK_EQ(2, result->Int32Value());
- CHECK_EQ(2,
- static_cast<int>(
- i::Object::GetElement(
- isolate, jsobj, 6).ToHandleChecked()->Number()));
- if (array_type != v8::kExternalFloat32Array &&
- array_type != v8::kExternalFloat64Array) {
- // Though the specification doesn't state it, be explicit about
- // converting NaNs and +/-Infinity to zero.
- result = CompileRun("for (var i = 0; i < 8; i++) {"
- " ext_array[i] = 5;"
- "}"
- "for (var i = 0; i < 8; i++) {"
- " ext_array[i] = NaN;"
- "}"
- "ext_array[5];");
- CHECK_EQ(0, result->Int32Value());
- CheckElementValue(isolate, 0, jsobj, 5);
+THREADED_TEST(Uint16Array) {
+ TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array,
+ v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF);
+}
- result = CompileRun("for (var i = 0; i < 8; i++) {"
- " ext_array[i] = 5;"
- "}"
- "for (var i = 0; i < 8; i++) {"
- " ext_array[i] = Infinity;"
- "}"
- "ext_array[5];");
- int expected_value =
- (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
- CHECK_EQ(expected_value, result->Int32Value());
- CheckElementValue(isolate, expected_value, jsobj, 5);
- result = CompileRun("for (var i = 0; i < 8; i++) {"
- " ext_array[i] = 5;"
- "}"
- "for (var i = 0; i < 8; i++) {"
- " ext_array[i] = -Infinity;"
- "}"
- "ext_array[5];");
- CHECK_EQ(0, result->Int32Value());
- CheckElementValue(isolate, 0, jsobj, 5);
+THREADED_TEST(Int16Array) {
+ TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array,
+ v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000,
+ 0x7FFF);
+}
- // Check truncation behavior of integral arrays.
- const char* unsigned_data =
- "var source_data = [0.6, 10.6];"
- "var expected_results = [0, 10];";
- const char* signed_data =
- "var source_data = [0.6, 10.6, -0.6, -10.6];"
- "var expected_results = [0, 10, 0, -10];";
- const char* pixel_data =
- "var source_data = [0.6, 10.6];"
- "var expected_results = [1, 11];";
- bool is_unsigned =
- (array_type == v8::kExternalUint8Array ||
- array_type == v8::kExternalUint16Array ||
- array_type == v8::kExternalUint32Array);
- bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
- i::SNPrintF(test_buf,
- "%s"
- "var all_passed = true;"
- "for (var i = 0; i < source_data.length; i++) {"
- " for (var j = 0; j < 8; j++) {"
- " ext_array[j] = source_data[i];"
- " }"
- " all_passed = all_passed &&"
- " (ext_array[5] == expected_results[i]);"
- "}"
- "all_passed;",
- (is_unsigned ?
- unsigned_data :
- (is_pixel_data ? pixel_data : signed_data)));
- result = CompileRun(test_buf.start());
- CHECK_EQ(true, result->BooleanValue());
- }
+THREADED_TEST(Uint32Array) {
+ TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array,
+ v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX);
+}
- i::Handle<ExternalArrayClass> array(
- ExternalArrayClass::cast(jsobj->elements()));
- for (int i = 0; i < element_count; i++) {
- array->set(i, static_cast<ElementType>(i));
- }
- // Test complex assignments
- result = CompileRun("function ee_op_test_complex_func(sum) {"
- " for (var i = 0; i < 40; ++i) {"
- " sum += (ext_array[i] += 1);"
- " sum += (ext_array[i] -= 1);"
- " } "
- " return sum;"
- "}"
- "sum=0;"
- "for (var i=0;i<10000;++i) {"
- " sum=ee_op_test_complex_func(sum);"
- "}"
- "sum;");
- CHECK_EQ(16000000, result->Int32Value());
+THREADED_TEST(Int32Array) {
+ TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array,
+ v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN,
+ INT_MAX);
+}
- // Test count operations
- result = CompileRun("function ee_op_test_count_func(sum) {"
- " for (var i = 0; i < 40; ++i) {"
- " sum += (++ext_array[i]);"
- " sum += (--ext_array[i]);"
- " } "
- " return sum;"
- "}"
- "sum=0;"
- "for (var i=0;i<10000;++i) {"
- " sum=ee_op_test_count_func(sum);"
- "}"
- "sum;");
- CHECK_EQ(16000000, result->Int32Value());
- result = CompileRun("ext_array[3] = 33;"
- "delete ext_array[3];"
- "ext_array[3];");
- CHECK_EQ(33, result->Int32Value());
+THREADED_TEST(Float32Array) {
+ TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array,
+ v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500);
+}
- result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
- "ext_array[2] = 12; ext_array[3] = 13;"
- "ext_array.__defineGetter__('2',"
- "function() { return 120; });"
- "ext_array[2];");
- CHECK_EQ(12, result->Int32Value());
- result = CompileRun("var js_array = new Array(40);"
- "js_array[0] = 77;"
- "js_array;");
- CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
+THREADED_TEST(Float64Array) {
+ TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array,
+ v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500);
+}
- result = CompileRun("ext_array[1] = 23;"
- "ext_array.__proto__ = [];"
- "js_array.__proto__ = ext_array;"
- "js_array.concat(ext_array);");
- CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
- CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
- result = CompileRun("ext_array[1] = 23;");
- CHECK_EQ(23, result->Int32Value());
+THREADED_TEST(Uint8ClampedArray) {
+ TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
+ i::ExternalUint8ClampedArray, v8::ArrayBuffer>(
+ i::kExternalUint8ClampedArray, 0, 0xFF);
}
-template <class FixedTypedArrayClass,
- i::ElementsKind elements_kind,
- class ElementType>
-static void FixedTypedArrayTestHelper(
- v8::ExternalArrayType array_type,
- ElementType low,
- ElementType high) {
- i::FLAG_allow_natives_syntax = true;
- LocalContext context;
- i::Isolate* isolate = CcTest::i_isolate();
- i::Factory* factory = isolate->factory();
- v8::HandleScope scope(context->GetIsolate());
- const int kElementCount = 260;
- i::Handle<FixedTypedArrayClass> fixed_array =
- i::Handle<FixedTypedArrayClass>::cast(
- factory->NewFixedTypedArray(kElementCount, array_type));
- CHECK_EQ(FixedTypedArrayClass::kInstanceType,
- fixed_array->map()->instance_type());
- CHECK_EQ(kElementCount, fixed_array->length());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- for (int i = 0; i < kElementCount; i++) {
- fixed_array->set(i, static_cast<ElementType>(i));
- }
- // Force GC to trigger verification.
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- for (int i = 0; i < kElementCount; i++) {
- CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
- static_cast<int64_t>(fixed_array->get_scalar(i)));
- }
- v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
- i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
- i::Handle<i::Map> fixed_array_map =
- i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
- jsobj->set_map(*fixed_array_map);
- jsobj->set_elements(*fixed_array);
+THREADED_TEST(DataView) {
+ const int kSize = 50;
- ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
- context.local(), obj, kElementCount, array_type,
- static_cast<int64_t>(low),
- static_cast<int64_t>(high));
-}
-
-
-THREADED_TEST(FixedUint8Array) {
- FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
- v8::kExternalUint8Array,
- 0x0, 0xFF);
-}
-
-
-THREADED_TEST(FixedUint8ClampedArray) {
- FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
- i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
- v8::kExternalUint8ClampedArray,
- 0x0, 0xFF);
-}
-
-
-THREADED_TEST(FixedInt8Array) {
- FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
- v8::kExternalInt8Array,
- -0x80, 0x7F);
-}
-
-
-THREADED_TEST(FixedUint16Array) {
- FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
- v8::kExternalUint16Array,
- 0x0, 0xFFFF);
-}
-
-
-THREADED_TEST(FixedInt16Array) {
- FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
- v8::kExternalInt16Array,
- -0x8000, 0x7FFF);
-}
-
-
-THREADED_TEST(FixedUint32Array) {
- FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
- v8::kExternalUint32Array,
- 0x0, UINT_MAX);
-}
-
-
-THREADED_TEST(FixedInt32Array) {
- FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
- v8::kExternalInt32Array,
- INT_MIN, INT_MAX);
-}
-
-
-THREADED_TEST(FixedFloat32Array) {
- FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
- v8::kExternalFloat32Array,
- -500, 500);
-}
-
-
-THREADED_TEST(FixedFloat64Array) {
- FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
- v8::kExternalFloat64Array,
- -500, 500);
-}
-
-
-template <class ExternalArrayClass, class ElementType>
-static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
- int64_t low,
- int64_t high) {
- LocalContext context;
- i::Isolate* isolate = CcTest::i_isolate();
- i::Factory* factory = isolate->factory();
- v8::HandleScope scope(context->GetIsolate());
- const int kElementCount = 40;
- int element_size = ExternalArrayElementSize(array_type);
- ElementType* array_data =
- static_cast<ElementType*>(malloc(kElementCount * element_size));
- i::Handle<ExternalArrayClass> array =
- i::Handle<ExternalArrayClass>::cast(
- factory->NewExternalArray(kElementCount, array_type, array_data));
- // Force GC to trigger verification.
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- for (int i = 0; i < kElementCount; i++) {
- array->set(i, static_cast<ElementType>(i));
- }
- // Force GC to trigger verification.
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- for (int i = 0; i < kElementCount; i++) {
- CHECK_EQ(static_cast<int64_t>(i),
- static_cast<int64_t>(array->get_scalar(i)));
- CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
- }
-
- v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
- i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
- // Set the elements to be the external array.
- obj->SetIndexedPropertiesToExternalArrayData(array_data,
- array_type,
- kElementCount);
- CHECK_EQ(1,
- static_cast<int>(
- i::Object::GetElement(
- isolate, jsobj, 1).ToHandleChecked()->Number()));
-
- ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
- context.local(), obj, kElementCount, array_type, low, high);
-
- v8::Handle<v8::Value> result;
-
- // Test more complex manipulations which cause eax to contain values
- // that won't be completely overwritten by loads from the arrays.
- // This catches bugs in the instructions used for the KeyedLoadIC
- // for byte and word types.
- {
- const int kXSize = 300;
- const int kYSize = 300;
- const int kLargeElementCount = kXSize * kYSize * 4;
- ElementType* large_array_data =
- static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
- v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
- // Set the elements to be the external array.
- large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
- array_type,
- kLargeElementCount);
- context->Global()->Set(v8_str("large_array"), large_obj);
- // Initialize contents of a few rows.
- for (int x = 0; x < 300; x++) {
- int row = 0;
- int offset = row * 300 * 4;
- large_array_data[offset + 4 * x + 0] = (ElementType) 127;
- large_array_data[offset + 4 * x + 1] = (ElementType) 0;
- large_array_data[offset + 4 * x + 2] = (ElementType) 0;
- large_array_data[offset + 4 * x + 3] = (ElementType) 127;
- row = 150;
- offset = row * 300 * 4;
- large_array_data[offset + 4 * x + 0] = (ElementType) 127;
- large_array_data[offset + 4 * x + 1] = (ElementType) 0;
- large_array_data[offset + 4 * x + 2] = (ElementType) 0;
- large_array_data[offset + 4 * x + 3] = (ElementType) 127;
- row = 298;
- offset = row * 300 * 4;
- large_array_data[offset + 4 * x + 0] = (ElementType) 127;
- large_array_data[offset + 4 * x + 1] = (ElementType) 0;
- large_array_data[offset + 4 * x + 2] = (ElementType) 0;
- large_array_data[offset + 4 * x + 3] = (ElementType) 127;
- }
- // The goal of the code below is to make "offset" large enough
- // that the computation of the index (which goes into eax) has
- // high bits set which will not be overwritten by a byte or short
- // load.
- result = CompileRun("var failed = false;"
- "var offset = 0;"
- "for (var i = 0; i < 300; i++) {"
- " if (large_array[4 * i] != 127 ||"
- " large_array[4 * i + 1] != 0 ||"
- " large_array[4 * i + 2] != 0 ||"
- " large_array[4 * i + 3] != 127) {"
- " failed = true;"
- " }"
- "}"
- "offset = 150 * 300 * 4;"
- "for (var i = 0; i < 300; i++) {"
- " if (large_array[offset + 4 * i] != 127 ||"
- " large_array[offset + 4 * i + 1] != 0 ||"
- " large_array[offset + 4 * i + 2] != 0 ||"
- " large_array[offset + 4 * i + 3] != 127) {"
- " failed = true;"
- " }"
- "}"
- "offset = 298 * 300 * 4;"
- "for (var i = 0; i < 300; i++) {"
- " if (large_array[offset + 4 * i] != 127 ||"
- " large_array[offset + 4 * i + 1] != 0 ||"
- " large_array[offset + 4 * i + 2] != 0 ||"
- " large_array[offset + 4 * i + 3] != 127) {"
- " failed = true;"
- " }"
- "}"
- "!failed;");
- CHECK_EQ(true, result->BooleanValue());
- free(large_array_data);
- }
-
- // The "" property descriptor is overloaded to store information about
- // the external array. Ensure that setting and accessing the "" property
- // works (it should overwrite the information cached about the external
- // array in the DescriptorArray) in various situations.
- result = CompileRun("ext_array[''] = 23; ext_array['']");
- CHECK_EQ(23, result->Int32Value());
-
- // Property "" set after the external array is associated with the object.
- {
- v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
- obj2->Set(v8_str("ee_test_field"),
- v8::Int32::New(context->GetIsolate(), 256));
- obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
- // Set the elements to be the external array.
- obj2->SetIndexedPropertiesToExternalArrayData(array_data,
- array_type,
- kElementCount);
- context->Global()->Set(v8_str("ext_array"), obj2);
- result = CompileRun("ext_array['']");
- CHECK_EQ(1503, result->Int32Value());
- }
-
- // Property "" set after the external array is associated with the object.
- {
- v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
- obj2->Set(v8_str("ee_test_field_2"),
- v8::Int32::New(context->GetIsolate(), 256));
- // Set the elements to be the external array.
- obj2->SetIndexedPropertiesToExternalArrayData(array_data,
- array_type,
- kElementCount);
- obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
- context->Global()->Set(v8_str("ext_array"), obj2);
- result = CompileRun("ext_array['']");
- CHECK_EQ(1503, result->Int32Value());
- }
-
- // Should reuse the map from previous test.
- {
- v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
- obj2->Set(v8_str("ee_test_field_2"),
- v8::Int32::New(context->GetIsolate(), 256));
- // Set the elements to be the external array. Should re-use the map
- // from previous test.
- obj2->SetIndexedPropertiesToExternalArrayData(array_data,
- array_type,
- kElementCount);
- context->Global()->Set(v8_str("ext_array"), obj2);
- result = CompileRun("ext_array['']");
- }
-
- // Property "" is a constant function that shouldn't not be interfered with
- // when an external array is set.
- {
- v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
- // Start
- obj2->Set(v8_str("ee_test_field3"),
- v8::Int32::New(context->GetIsolate(), 256));
-
- // Add a constant function to an object.
- context->Global()->Set(v8_str("ext_array"), obj2);
- result = CompileRun("ext_array[''] = function() {return 1503;};"
- "ext_array['']();");
-
- // Add an external array transition to the same map that
- // has the constant transition.
- v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
- obj3->Set(v8_str("ee_test_field3"),
- v8::Int32::New(context->GetIsolate(), 256));
- obj3->SetIndexedPropertiesToExternalArrayData(array_data,
- array_type,
- kElementCount);
- context->Global()->Set(v8_str("ext_array"), obj3);
- }
-
- // If a external array transition is in the map, it should get clobbered
- // by a constant function.
- {
- // Add an external array transition.
- v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
- obj3->Set(v8_str("ee_test_field4"),
- v8::Int32::New(context->GetIsolate(), 256));
- obj3->SetIndexedPropertiesToExternalArrayData(array_data,
- array_type,
- kElementCount);
-
- // Add a constant function to the same map that just got an external array
- // transition.
- v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
- obj2->Set(v8_str("ee_test_field4"),
- v8::Int32::New(context->GetIsolate(), 256));
- context->Global()->Set(v8_str("ext_array"), obj2);
- result = CompileRun("ext_array[''] = function() {return 1503;};"
- "ext_array['']();");
- }
-
- free(array_data);
-}
-
-
-THREADED_TEST(ExternalInt8Array) {
- ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
- v8::kExternalInt8Array,
- -128,
- 127);
-}
-
-
-THREADED_TEST(ExternalUint8Array) {
- ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
- v8::kExternalUint8Array,
- 0,
- 255);
-}
-
-
-THREADED_TEST(ExternalUint8ClampedArray) {
- ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
- v8::kExternalUint8ClampedArray,
- 0,
- 255);
-}
-
-
-THREADED_TEST(ExternalInt16Array) {
- ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
- v8::kExternalInt16Array,
- -32768,
- 32767);
-}
-
-
-THREADED_TEST(ExternalUint16Array) {
- ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
- v8::kExternalUint16Array,
- 0,
- 65535);
-}
-
-
-THREADED_TEST(ExternalInt32Array) {
- ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
- v8::kExternalInt32Array,
- INT_MIN, // -2147483648
- INT_MAX); // 2147483647
-}
-
-
-THREADED_TEST(ExternalUint32Array) {
- ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
- v8::kExternalUint32Array,
- 0,
- UINT_MAX); // 4294967295
-}
-
-
-THREADED_TEST(ExternalFloat32Array) {
- ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
- v8::kExternalFloat32Array,
- -500,
- 500);
-}
-
-
-THREADED_TEST(ExternalFloat64Array) {
- ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
- v8::kExternalFloat64Array,
- -500,
- 500);
-}
-
-
-THREADED_TEST(ExternalArrays) {
- TestExternalInt8Array();
- TestExternalUint8Array();
- TestExternalInt16Array();
- TestExternalUint16Array();
- TestExternalInt32Array();
- TestExternalUint32Array();
- TestExternalFloat32Array();
-}
-
-
-void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
- LocalContext context;
- v8::HandleScope scope(context->GetIsolate());
- for (int size = 0; size < 100; size += 10) {
- int element_size = ExternalArrayElementSize(array_type);
- void* external_data = malloc(size * element_size);
- v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
- obj->SetIndexedPropertiesToExternalArrayData(
- external_data, array_type, size);
- CHECK(obj->HasIndexedPropertiesInExternalArrayData());
- CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
- CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
- CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
- free(external_data);
- }
-}
-
-
-THREADED_TEST(ExternalArrayInfo) {
- ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
- ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
- ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
- ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
- ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
- ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
- ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
- ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
- ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
-}
+ i::ScopedVector<uint8_t> backing_store(kSize+2);
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
-void ExtArrayLimitsHelper(v8::Isolate* isolate,
- v8::ExternalArrayType array_type,
- int size) {
- v8::Handle<v8::Object> obj = v8::Object::New(isolate);
- v8::V8::SetFatalErrorHandler(StoringErrorCallback);
- last_location = last_message = NULL;
- obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
- CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
- CHECK(last_location);
- CHECK(last_message);
+ Local<v8::ArrayBuffer> ab =
+ v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
+ Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize);
+ CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
+ CHECK_EQ(2u, dv->ByteOffset());
+ CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
+ CHECK(ab->Equals(dv->Buffer()));
}
-TEST(ExternalArrayLimits) {
- LocalContext context;
- v8::Isolate* isolate = context->GetIsolate();
- v8::HandleScope scope(isolate);
- ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
- ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
- ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
- ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
- ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
- ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
- ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
- ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
- ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
- ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
- ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
- ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
- ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
- ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
- ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
- ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
- ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
- ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
-}
-
-
-template <typename ElementType, typename TypedArray,
- class ExternalArrayClass>
-void TypedArrayTestHelper(v8::ExternalArrayType array_type,
- int64_t low, int64_t high) {
- const int kElementCount = 50;
-
- i::ScopedVector<ElementType> backing_store(kElementCount+2);
-
+THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope handle_scope(isolate);
- Local<v8::ArrayBuffer> ab =
- v8::ArrayBuffer::New(isolate, backing_store.start(),
- (kElementCount + 2) * sizeof(ElementType));
- Local<TypedArray> ta =
- TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
- CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
- CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
- CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
- CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
- CHECK(ab->Equals(ta->Buffer()));
+ // Make sure the pointer looks like a heap object
+ uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
- ElementType* data = backing_store.start() + 2;
- for (int i = 0; i < kElementCount; i++) {
- data[i] = static_cast<ElementType>(i);
- }
+ // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
+ Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
- ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
- env.local(), ta, kElementCount, array_type, low, high);
+ // Should not crash
+ CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
+ CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
+ CcTest::heap()->CollectAllGarbage();
+ CcTest::heap()->CollectAllGarbage();
+
+ // Should not move the pointer
+ CHECK_EQ(ab->GetContents().Data(), store_ptr);
}
-THREADED_TEST(Uint8Array) {
- TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
- v8::kExternalUint8Array, 0, 0xFF);
+THREADED_TEST(SharedUint8Array) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array,
+ v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
}
-THREADED_TEST(Int8Array) {
- TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
- v8::kExternalInt8Array, -0x80, 0x7F);
+THREADED_TEST(SharedInt8Array) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array,
+ v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80,
+ 0x7F);
}
-THREADED_TEST(Uint16Array) {
- TypedArrayTestHelper<uint16_t,
- v8::Uint16Array,
- i::ExternalUint16Array>(
- v8::kExternalUint16Array, 0, 0xFFFF);
+THREADED_TEST(SharedUint16Array) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array,
+ v8::SharedArrayBuffer>(i::kExternalUint16Array, 0,
+ 0xFFFF);
}
-THREADED_TEST(Int16Array) {
- TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
- v8::kExternalInt16Array, -0x8000, 0x7FFF);
+THREADED_TEST(SharedInt16Array) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array,
+ v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000,
+ 0x7FFF);
}
-THREADED_TEST(Uint32Array) {
- TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
- v8::kExternalUint32Array, 0, UINT_MAX);
+THREADED_TEST(SharedUint32Array) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array,
+ v8::SharedArrayBuffer>(i::kExternalUint32Array, 0,
+ UINT_MAX);
}
-THREADED_TEST(Int32Array) {
- TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
- v8::kExternalInt32Array, INT_MIN, INT_MAX);
+THREADED_TEST(SharedInt32Array) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array,
+ v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN,
+ INT_MAX);
}
-THREADED_TEST(Float32Array) {
- TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
- v8::kExternalFloat32Array, -500, 500);
+THREADED_TEST(SharedFloat32Array) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array,
+ v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500,
+ 500);
}
-THREADED_TEST(Float64Array) {
- TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
- v8::kExternalFloat64Array, -500, 500);
+THREADED_TEST(SharedFloat64Array) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array,
+ v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500,
+ 500);
}
-THREADED_TEST(Uint8ClampedArray) {
- TypedArrayTestHelper<uint8_t,
- v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
- v8::kExternalUint8ClampedArray, 0, 0xFF);
+THREADED_TEST(SharedUint8ClampedArray) {
+ i::FLAG_harmony_sharedarraybuffer = true;
+ TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
+ i::ExternalUint8ClampedArray, v8::SharedArrayBuffer>(
+ i::kExternalUint8ClampedArray, 0, 0xFF);
}
-THREADED_TEST(DataView) {
+THREADED_TEST(SharedDataView) {
+ i::FLAG_harmony_sharedarraybuffer = true;
const int kSize = 50;
- i::ScopedVector<uint8_t> backing_store(kSize+2);
+ i::ScopedVector<uint8_t> backing_store(kSize + 2);
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope handle_scope(isolate);
- Local<v8::ArrayBuffer> ab =
- v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
+ Local<v8::SharedArrayBuffer> ab =
+ v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
Local<v8::DataView> dv =
v8::DataView::New(ab, 2, kSize);
CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
THREADED_TEST(StackTrace) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
const char *source = "function foo() { FAIL.FAIL; }; foo();";
v8::Handle<v8::String> src =
v8::String::NewFromUtf8(context->GetIsolate(), source);
checkStackFrame(origin, "foo", 6, 3, false, false,
stackTrace->GetFrame(1));
// This is the source string inside the eval which has the call to foo.
- checkStackFrame(NULL, "", 1, 5, false, false,
- stackTrace->GetFrame(2));
+ checkStackFrame(NULL, "", 1, 1, false, false, stackTrace->GetFrame(2));
// The last frame is an anonymous function which has the initial eval call.
- checkStackFrame(origin, "", 8, 7, false, false,
- stackTrace->GetFrame(3));
+ checkStackFrame(origin, "", 8, 7, false, false, stackTrace->GetFrame(3));
CHECK(stackTrace->AsArray()->IsArray());
} else if (testGroup == kDetailedTest) {
stackTrace->GetFrame(1));
bool is_eval = true;
// This is the source string inside the eval which has the call to baz.
- checkStackFrame(NULL, "", 1, 5, is_eval, false,
- stackTrace->GetFrame(2));
+ checkStackFrame(NULL, "", 1, 1, is_eval, false, stackTrace->GetFrame(2));
// The last frame is an anonymous function which has the initial eval call.
- checkStackFrame(origin, "", 10, 1, false, false,
- stackTrace->GetFrame(3));
+ checkStackFrame(origin, "", 10, 1, false, false, stackTrace->GetFrame(3));
CHECK(stackTrace->AsArray()->IsArray());
}
}
+static void StackTraceFunctionNameListener(v8::Handle<v8::Message> message,
+ v8::Handle<Value>) {
+ v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
+ CHECK_EQ(5, stack_trace->GetFrameCount());
+ checkStackFrame("origin", "foo:0", 4, 7, false, false,
+ stack_trace->GetFrame(0));
+ checkStackFrame("origin", "foo:1", 5, 27, false, false,
+ stack_trace->GetFrame(1));
+ checkStackFrame("origin", "foo", 5, 27, false, false,
+ stack_trace->GetFrame(2));
+ checkStackFrame("origin", "foo", 5, 27, false, false,
+ stack_trace->GetFrame(3));
+ checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4));
+}
+
+
+TEST(GetStackTraceContainsFunctionsWithFunctionName) {
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+
+ CompileRunWithOrigin(
+ "function gen(name, counter) {\n"
+ " var f = function foo() {\n"
+ " if (counter === 0)\n"
+ " throw 1;\n"
+ " gen(name, counter - 1)();\n"
+ " };\n"
+ " if (counter == 3) {\n"
+ " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
+ " } else {\n"
+ " Object.defineProperty(f, 'name', {writable:true});\n"
+ " if (counter == 2)\n"
+ " f.name = 42;\n"
+ " else\n"
+ " f.name = name + ':' + counter;\n"
+ " }\n"
+ " return f;\n"
+ "};",
+ "origin");
+
+ v8::V8::AddMessageListener(StackTraceFunctionNameListener);
+ v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
+ CompileRunWithOrigin("gen('foo', 3)();", "origin");
+ v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
+ v8::V8::RemoveMessageListeners(StackTraceFunctionNameListener);
+}
+
+
static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
v8::Handle<v8::Value> data) {
// Use the frame where JavaScript is called from.
v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
args.GetIsolate(), 10, v8::StackTrace::kDetailed);
CHECK_EQ(4, stackTrace->GetFrameCount());
- v8::Handle<v8::String> url = v8_str("url");
+ v8::Handle<v8::String> url = v8_str("source_url");
for (int i = 0; i < 3; i++) {
v8::Handle<v8::String> name =
stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
i::ScopedVector<char> code(1024);
i::SNPrintF(code, source, "//# sourceURL=source_url");
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
CompileRunWithOrigin(code.start(), "", 0, 0);
CHECK(try_catch.HasCaught());
v8::String::Utf8Value stack(try_catch.StackTrace());
"outer();\n"
"//# sourceURL=outer_url";
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
CompileRun(source);
CHECK(try_catch.HasCaught());
"outer();\n"
"//# sourceURL=outer_url";
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
CompileRun(source);
CHECK(try_catch.HasCaught());
}
-// Test that idle notification can be handled and eventually returns true.
-TEST(IdleNotification) {
- const intptr_t MB = 1024 * 1024;
- const int IdlePauseInMs = 1000;
- LocalContext env;
- v8::HandleScope scope(env->GetIsolate());
- intptr_t initial_size = CcTest::heap()->SizeOfObjects();
- CreateGarbageInOldSpace();
- intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
- CHECK_GT(size_with_garbage, initial_size + MB);
- bool finished = false;
- for (int i = 0; i < 200 && !finished; i++) {
- finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
- }
- intptr_t final_size = CcTest::heap()->SizeOfObjects();
- CHECK(finished);
- CHECK_LT(final_size, initial_size + 1);
-}
-
-
-// Test that idle notification can be handled and eventually collects garbage.
-TEST(IdleNotificationWithSmallHint) {
- const intptr_t MB = 1024 * 1024;
- const int IdlePauseInMs = 900;
- LocalContext env;
- v8::HandleScope scope(env->GetIsolate());
- intptr_t initial_size = CcTest::heap()->SizeOfObjects();
- CreateGarbageInOldSpace();
- intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
- CHECK_GT(size_with_garbage, initial_size + MB);
- bool finished = false;
- for (int i = 0; i < 200 && !finished; i++) {
- finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
- }
- intptr_t final_size = CcTest::heap()->SizeOfObjects();
- CHECK(finished);
- CHECK_LT(final_size, initial_size + 1);
-}
-
-
// Test that idle notification can be handled and eventually collects garbage.
-TEST(IdleNotificationWithLargeHint) {
+TEST(TestIdleNotification) {
+ if (!i::FLAG_incremental_marking) return;
const intptr_t MB = 1024 * 1024;
- const int IdlePauseInMs = 900;
+ const double IdlePauseInSeconds = 1.0;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
intptr_t initial_size = CcTest::heap()->SizeOfObjects();
CHECK_GT(size_with_garbage, initial_size + MB);
bool finished = false;
for (int i = 0; i < 200 && !finished; i++) {
- finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
+ if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) {
+ CcTest::heap()->StartIdleIncrementalMarking();
+ }
+ finished = env->GetIsolate()->IdleNotificationDeadline(
+ (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
+ static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
+ IdlePauseInSeconds);
+ if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) {
+ CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted();
+ }
}
intptr_t final_size = CcTest::heap()->SizeOfObjects();
CHECK(finished);
CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
CcTest::heap()->CollectAllAvailableGarbage();
- CHECK(CcTest::heap()->old_pointer_space()->Contains(
- *v8::Utils::OpenHandle(*cons)));
+ CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
TestResource* resource = new TestResource(
AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
CcTest::heap()->CollectAllAvailableGarbage();
- CHECK(CcTest::heap()->old_pointer_space()->Contains(
- *v8::Utils::OpenHandle(*cons)));
+ CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
TestOneByteResource* resource =
new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
TEST(ExternalStringCollectedAtTearDown) {
int destroyed = 0;
- v8::Isolate* isolate = v8::Isolate::New();
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
{ v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
const char* s = "One string to test them all, one string to find them.";
TEST(ExternalInternalizedStringCollectedAtTearDown) {
int destroyed = 0;
- v8::Isolate* isolate = v8::Isolate::New();
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
{ v8::Isolate::Scope isolate_scope(isolate);
LocalContext env(isolate);
v8::HandleScope handle_scope(isolate);
TEST(ExternalInternalizedStringCollectedAtGC) {
- // TODO(mvstanton): vector ics need weak support.
- if (i::FLAG_vector_ics) return;
-
int destroyed = 0;
{ LocalContext env;
v8::HandleScope handle_scope(env->GetIsolate());
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope scope(isolate);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
// Special double values.
double snan = DoubleFromBits(0x7ff00000, 0x00000001);
static void SpaghettiIncident(
const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope scope(args.GetIsolate());
- v8::TryCatch tc;
+ v8::TryCatch tc(args.GetIsolate());
v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
USE(str);
if (tc.HasCaught())
context->Global()->Set(
v8::String::NewFromUtf8(isolate, "s"),
v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(
"var i = 0;"
"var o = {"
TEST(Regress528) {
v8::V8::Initialize();
v8::Isolate* isolate = CcTest::isolate();
+ i::FLAG_retain_maps_for_n_gc = 0;
v8::HandleScope scope(isolate);
v8::Local<Context> other_context;
int gc_count;
other_context->Enter();
CompileRun(source_simple);
other_context->Exit();
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
other_context->Enter();
CompileRun(source_eval);
other_context->Exit();
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
v8::Local<Context> context = Context::New(isolate);
context->Enter();
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(source_exception);
CHECK(try_catch.HasCaught());
v8::Handle<v8::Message> message = try_catch.Message();
other_context->Enter();
CompileRun(source_exception);
other_context->Exit();
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
v8::String::NewFromUtf8(env->GetIsolate(), "test"),
v8::Integer::New(env->GetIsolate(), 1),
v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
- v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()));
+ v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()),
+ v8::String::NewFromUtf8(env->GetIsolate(), "http://sourceMapUrl"),
+ v8::True(env->GetIsolate()));
v8::Handle<v8::String> script = v8::String::NewFromUtf8(
env->GetIsolate(), "function f() {}\n\nfunction g() {}");
v8::Script::Compile(script, &origin)->Run();
CHECK_EQ(0, strcmp("test",
*v8::String::Utf8Value(script_origin_f.ResourceName())));
CHECK_EQ(1, script_origin_f.ResourceLineOffset()->Int32Value());
- CHECK(script_origin_f.ResourceIsSharedCrossOrigin()->Value());
- CHECK(script_origin_f.ResourceIsEmbedderDebugScript()->Value());
+ CHECK(script_origin_f.Options().IsSharedCrossOrigin());
+ CHECK(script_origin_f.Options().IsEmbedderDebugScript());
+ CHECK(script_origin_f.Options().IsOpaque());
+ printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
+
+ CHECK_EQ(0, strcmp("http://sourceMapUrl",
+ *v8::String::Utf8Value(script_origin_f.SourceMapUrl())));
v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
CHECK_EQ(0, strcmp("test",
*v8::String::Utf8Value(script_origin_g.ResourceName())));
CHECK_EQ(1, script_origin_g.ResourceLineOffset()->Int32Value());
- CHECK(script_origin_g.ResourceIsSharedCrossOrigin()->Value());
- CHECK(script_origin_g.ResourceIsEmbedderDebugScript()->Value());
+ CHECK(script_origin_g.Options().IsSharedCrossOrigin());
+ CHECK(script_origin_g.Options().IsEmbedderDebugScript());
+ CHECK(script_origin_g.Options().IsOpaque());
+ CHECK_EQ(0, strcmp("http://sourceMapUrl",
+ *v8::String::Utf8Value(script_origin_g.SourceMapUrl())));
}
v8::V8::AddGCEpilogueCallback(EpilogueCallback);
CHECK_EQ(0, prologue_call_count);
CHECK_EQ(0, epilogue_call_count);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(1, prologue_call_count);
CHECK_EQ(1, epilogue_call_count);
v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(1, prologue_call_count_second);
CHECK_EQ(1, epilogue_call_count_second);
v8::V8::RemoveGCPrologueCallback(PrologueCallback);
v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(2, prologue_call_count_second);
CHECK_EQ(2, epilogue_call_count_second);
v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(2, prologue_call_count_second);
isolate->AddGCEpilogueCallback(EpilogueCallback);
CHECK_EQ(0, prologue_call_count);
CHECK_EQ(0, epilogue_call_count);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(1, prologue_call_count);
CHECK_EQ(1, epilogue_call_count);
isolate->AddGCPrologueCallback(PrologueCallbackSecond);
isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(1, prologue_call_count_second);
CHECK_EQ(1, epilogue_call_count_second);
isolate->RemoveGCPrologueCallback(PrologueCallback);
isolate->RemoveGCEpilogueCallback(EpilogueCallback);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(2, prologue_call_count_second);
CHECK_EQ(2, epilogue_call_count_second);
isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(2, prologue_call_count_second);
void FailedAccessCheckCallbackGC(Local<v8::Object> target,
v8::AccessType type,
Local<v8::Value> data) {
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
+ CcTest::isolate()->ThrowException(
+ v8::Exception::Error(v8_str("cross context")));
}
// check callbacks that will block access.
v8::Handle<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate);
- global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
- IndexedGetAccessBlocker,
- v8::Handle<v8::Value>(),
- false);
+ global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL,
+ v8::Handle<v8::Value>());
// Create a context and set an x property on it's global object.
LocalContext context0(NULL, global_template);
LocalContext context1(NULL, global_template);
context1->Global()->Set(v8_str("other"), global0);
+ v8::TryCatch try_catch(isolate);
+
// Get property with failed access check.
- ExpectUndefined("other.x");
+ CHECK(CompileRun("other.x").IsEmpty());
+ CHECK(try_catch.HasCaught());
+ try_catch.Reset();
// Get element with failed access check.
- ExpectUndefined("other[0]");
+ CHECK(CompileRun("other[0]").IsEmpty());
+ CHECK(try_catch.HasCaught());
+ try_catch.Reset();
// Set property with failed access check.
- v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
- CHECK(result->IsObject());
+ CHECK(CompileRun("other.x = new Object()").IsEmpty());
+ CHECK(try_catch.HasCaught());
+ try_catch.Reset();
// Set element with failed access check.
- result = CompileRun("other[0] = new Object()");
- CHECK(result->IsObject());
+ CHECK(CompileRun("other[0] = new Object()").IsEmpty());
+ CHECK(try_catch.HasCaught());
+ try_catch.Reset();
// Get property attribute with failed access check.
- ExpectFalse("\'x\' in other");
+ CHECK(CompileRun("\'x\' in other").IsEmpty());
+ CHECK(try_catch.HasCaught());
+ try_catch.Reset();
// Get property attribute for element with failed access check.
- ExpectFalse("0 in other");
+ CHECK(CompileRun("0 in other").IsEmpty());
+ CHECK(try_catch.HasCaught());
+ try_catch.Reset();
// Delete property.
- ExpectFalse("delete other.x");
+ CHECK(CompileRun("delete other.x").IsEmpty());
+ CHECK(try_catch.HasCaught());
+ try_catch.Reset();
// Delete element.
CHECK_EQ(false, global0->Delete(0));
global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
// Define JavaScript accessor.
- ExpectUndefined("Object.prototype.__defineGetter__.call("
- " other, \'x\', function() { return 42; })");
+ CHECK(CompileRun(
+ "Object.prototype.__defineGetter__.call("
+ " other, \'x\', function() { return 42; })").IsEmpty());
+ CHECK(try_catch.HasCaught());
+ try_catch.Reset();
// LookupAccessor.
- ExpectUndefined("Object.prototype.__lookupGetter__.call("
- " other, \'x\')");
+ CHECK(CompileRun(
+ "Object.prototype.__lookupGetter__.call("
+ " other, \'x\')").IsEmpty());
+ CHECK(try_catch.HasCaught());
+ try_catch.Reset();
// HasOwnElement.
- ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
+ CHECK(CompileRun(
+ "Object.prototype.hasOwnProperty.call("
+ "other, \'0\')").IsEmpty());
+ CHECK(try_catch.HasCaught());
+ try_catch.Reset();
CHECK_EQ(false, global0->HasRealIndexedProperty(0));
CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
TEST(IsolateNewDispose) {
v8::Isolate* current_isolate = CcTest::isolate();
- v8::Isolate* isolate = v8::Isolate::New();
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
CHECK(isolate != NULL);
CHECK(current_isolate != isolate);
CHECK(current_isolate == CcTest::isolate());
UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
- v8::Isolate* isolate = v8::Isolate::New();
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope i_scope(isolate);
v8::HandleScope scope(isolate);
}
+static void BreakArrayGuarantees(const char* script) {
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate1 = v8::Isolate::New(create_params);
+ isolate1->Enter();
+ v8::Persistent<v8::Context> context1;
+ {
+ v8::HandleScope scope(isolate1);
+ context1.Reset(isolate1, Context::New(isolate1));
+ }
+
+ {
+ v8::HandleScope scope(isolate1);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate1, context1);
+ v8::Context::Scope context_scope(context);
+ v8::internal::Isolate* i_isolate =
+ reinterpret_cast<v8::internal::Isolate*>(isolate1);
+ CHECK_EQ(true, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
+ // Run something in new isolate.
+ CompileRun(script);
+ CHECK_EQ(false, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
+ }
+ isolate1->Exit();
+ isolate1->Dispose();
+}
+
+
+TEST(VerifyArrayPrototypeGuarantees) {
+ // Break fast array hole handling by element changes.
+ BreakArrayGuarantees("[].__proto__[1] = 3;");
+ BreakArrayGuarantees("Object.prototype[3] = 'three';");
+ BreakArrayGuarantees("Array.prototype.push(1);");
+ BreakArrayGuarantees("Array.prototype.unshift(1);");
+ // Break fast array hole handling by changing length.
+ BreakArrayGuarantees("Array.prototype.length = 30;");
+ // Break fast array hole handling by prototype structure changes.
+ BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };");
+ // By sending elements to dictionary mode.
+ BreakArrayGuarantees("Object.freeze(Array.prototype);");
+ BreakArrayGuarantees("Object.freeze(Object.prototype);");
+ BreakArrayGuarantees(
+ "Object.defineProperty(Array.prototype, 0, {"
+ " get: function() { return 3; }});");
+ BreakArrayGuarantees(
+ "Object.defineProperty(Object.prototype, 0, {"
+ " get: function() { return 3; }});");
+}
+
+
TEST(RunTwoIsolatesOnSingleThread) {
// Run isolate 1.
- v8::Isolate* isolate1 = v8::Isolate::New();
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate1 = v8::Isolate::New(create_params);
isolate1->Enter();
v8::Persistent<v8::Context> context1;
{
}
// Run isolate 2.
- v8::Isolate* isolate2 = v8::Isolate::New();
+ v8::Isolate* isolate2 = v8::Isolate::New(create_params);
v8::Persistent<v8::Context> context2;
{
: Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
void Run() {
- v8::Isolate* isolate = v8::Isolate::New();
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
result_ = CalcFibonacci(isolate, fib_limit_);
isolate->Dispose();
}
TEST(IsolateDifferentContexts) {
- v8::Isolate* isolate = v8::Isolate::New();
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
Local<v8::Context> context;
{
v8::Isolate::Scope isolate_scope(isolate);
void Run() {
v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
switch (testCase_) {
case SetResourceConstraints: {
create_params.constraints.set_max_semi_space_size(1);
"})()",
"ReferenceError: cell is not defined");
CompileRun("cell = \"new_second\";");
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
ExpectString("readCell()", "new_second");
ExpectString("readCell()", "new_second");
}
object1.SetWrapperClassId(42);
CHECK_EQ(42, object1.WrapperClassId());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CcTest::heap()->CollectAllGarbage();
+ CcTest::heap()->CollectAllGarbage();
v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
CHECK_EQ(0, object2.WrapperClassId());
v8::Handle<v8::Value> value(CompileRun("re.property"));
CHECK_EQ(32, value->Int32Value());
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(context->GetIsolate());
re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
CHECK(re.IsEmpty());
CHECK(try_catch.HasCaught());
instance2 = func2->NewInstance();
}
- CHECK(object1->CreationContext() == context1);
- CheckContextId(object1, 1);
- CHECK(func1->CreationContext() == context1);
- CheckContextId(func1, 1);
- CHECK(instance1->CreationContext() == context1);
- CheckContextId(instance1, 1);
- CHECK(object2->CreationContext() == context2);
- CheckContextId(object2, 2);
- CHECK(func2->CreationContext() == context2);
- CheckContextId(func2, 2);
- CHECK(instance2->CreationContext() == context2);
- CheckContextId(instance2, 2);
+ {
+ Handle<Context> other_context = Context::New(isolate);
+ Context::Scope scope(other_context);
+ CHECK(object1->CreationContext() == context1);
+ CheckContextId(object1, 1);
+ CHECK(func1->CreationContext() == context1);
+ CheckContextId(func1, 1);
+ CHECK(instance1->CreationContext() == context1);
+ CheckContextId(instance1, 1);
+ CHECK(object2->CreationContext() == context2);
+ CheckContextId(object2, 2);
+ CHECK(func2->CreationContext() == context2);
+ CheckContextId(func2, 2);
+ CHECK(instance2->CreationContext() == context2);
+ CheckContextId(instance2, 2);
+ }
{
Context::Scope scope(context1);
function = CompileRun("function foo() {}; foo").As<Object>();
}
+ Handle<Context> other_context = Context::New(CcTest::isolate());
+ Context::Scope scope(other_context);
CHECK(function->CreationContext() == context);
CheckContextId(function, 1);
}
void CheckCodeGenerationDisallowed() {
- TryCatch try_catch;
+ TryCatch try_catch(CcTest::isolate());
Handle<Value> result = CompileRun("eval('42')");
CHECK(result.IsEmpty());
TEST(SetErrorMessageForCodeGenFromStrings) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
- TryCatch try_catch;
+ TryCatch try_catch(context->GetIsolate());
Handle<String> message = v8_str("Message") ;
Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
v8::FunctionTemplate::New(isolate, NonObjectThis);
Handle<Function> function = templ->GetFunction();
context->Global()->Set(v8_str("f"), function);
- TryCatch try_catch;
+ TryCatch try_catch(isolate);
CompileRun("f.call(2)");
}
int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
CHECK_LE(1, elements);
- CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+ CcTest::heap()->CollectAllGarbage();
CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
}
-static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
- Local<Value> name,
- v8::AccessType type,
- Local<Value> data) {
- // Only block read access to __proto__.
- if (type == v8::ACCESS_GET && name->IsString() &&
- name.As<v8::String>()->Length() == 9 &&
- name.As<v8::String>()->Utf8Length() == 9) {
- char buffer[10];
- CHECK_EQ(10, name.As<v8::String>()->WriteUtf8(buffer));
- return strncmp(buffer, "__proto__", 9) != 0;
- }
-
- return true;
-}
-
-
THREADED_TEST(Regress93759) {
v8::Isolate* isolate = CcTest::isolate();
HandleScope scope(isolate);
// Template for object with security check.
Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
- // We don't do indexing, so any callback can be used for that.
- no_proto_template->SetAccessCheckCallbacks(
- BlockProtoNamedSecurityTestCallback,
- IndexedSecurityTestCallback);
+ no_proto_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
// Templates for objects with hidden prototypes and possibly security check.
Local<FunctionTemplate> hidden_proto_template =
Local<FunctionTemplate> protected_hidden_proto_template =
v8::FunctionTemplate::New(isolate);
protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
- BlockProtoNamedSecurityTestCallback,
- IndexedSecurityTestCallback);
+ AccessAlwaysBlocked, NULL);
protected_hidden_proto_template->SetHiddenPrototype(true);
// Context for "foreign" objects used in test.
Local<Object> simple_object = Object::New(isolate);
// Object with explicit security check.
- Local<Object> protected_object =
- no_proto_template->NewInstance();
+ Local<Object> protected_object = no_proto_template->NewInstance();
// JSGlobalProxy object, always have security check.
- Local<Object> proxy_object =
- context->Global();
+ Local<Object> proxy_object = context->Global();
// Global object, the prototype of proxy_object. No security checks.
Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
}
-TEST(SealHandleScope) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope handle_scope(isolate);
- LocalContext env;
-
- v8::SealHandleScope seal(isolate);
-
- // Should fail
- v8::Local<v8::Object> obj = v8::Object::New(isolate);
-
- USE(obj);
-}
-
-
-TEST(SealHandleScopeNested) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope handle_scope(isolate);
- LocalContext env;
-
- v8::SealHandleScope seal(isolate);
-
- {
- v8::HandleScope handle_scope(isolate);
-
- // Should work
- v8::Local<v8::Object> obj = v8::Object::New(isolate);
-
- USE(obj);
- }
-}
-
-
TEST(CallCompletedCallbackOneException) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
Function::New(isolate, MicrotaskExceptionOne));
isolate->EnqueueMicrotask(
Function::New(isolate, MicrotaskExceptionTwo));
- TryCatch try_catch;
+ TryCatch try_catch(isolate);
CompileRun("1+1;");
CHECK(!try_catch.HasCaught());
CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
UNINITIALIZED_TEST(IsolateEmbedderData) {
CcTest::DisableAutomaticDispose();
- v8::Isolate* isolate = v8::Isolate::New();
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
isolate->Enter();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
instance_checked_getter_count = 0;
instance_checked_setter_count = 0;
- TryCatch try_catch;
+ TryCatch try_catch(CcTest::isolate());
// Test path through generic runtime code.
CompileRun("obj.foo");
// Test that the original error message is not lost if there is a
// recursive call into Javascript is done in the finally block, e.g. to
// initialize an IC. (crbug.com/129171)
- TryCatch try_catch;
+ TryCatch try_catch(context->GetIsolate());
const char* trigger_ic =
"try { \n"
" throw new Error('test'); \n"
{
// Test that the original exception message is indeed overwritten if
// a new error is thrown in the finally block.
- TryCatch try_catch;
+ TryCatch try_catch(context->GetIsolate());
const char* throw_again =
"try { \n"
" throw new Error('test'); \n"
}
-THREADED_TEST(Regress3337) {
- LocalContext context;
- v8::Isolate* isolate = context->GetIsolate();
- v8::HandleScope scope(isolate);
- Local<v8::Object> o1 = Object::New(isolate);
- Local<v8::Object> o2 = Object::New(isolate);
- i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
- i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
- CHECK(io1->map() == io2->map());
- o1->SetIndexedPropertiesToExternalArrayData(
- NULL, v8::kExternalUint32Array, 0);
- o2->SetIndexedPropertiesToExternalArrayData(
- NULL, v8::kExternalUint32Array, 0);
- CHECK(io1->map() == io2->map());
-}
-
-
THREADED_TEST(Regress137496) {
i::FLAG_expose_gc = true;
LocalContext context;
// Compile a try-finally clause where the finally block causes a GC
// while there still is a message pending for external reporting.
- TryCatch try_catch;
+ TryCatch try_catch(context->GetIsolate());
try_catch.SetVerbose(true);
CompileRun("try { throw new Error(); } finally { gc(); }");
CHECK(try_catch.HasCaught());
struct sigaction action;
// Ensure that we'll enter waiting condition
- v8::base::OS::Sleep(100);
+ v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
// Setup signal handler
memset(&action, 0, sizeof(action));
kill(getpid(), SIGCHLD);
// Ensure that if wait has returned because of error
- v8::base::OS::Sleep(100);
+ v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
// Set value and signal semaphore
test_->sem_value_ = 1;
#endif // V8_OS_POSIX
-static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
- Local<Value> name,
- v8::AccessType type,
- Local<Value> data) {
- i::PrintF("Named access blocked.\n");
- return false;
-}
-
-
-static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
- uint32_t key,
- v8::AccessType type,
- Local<Value> data) {
- i::PrintF("Indexed access blocked.\n");
- return false;
-}
-
-
void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
CHECK(false);
}
// check callbacks that will block access.
v8::Handle<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate);
- global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
- IndexAccessAlwaysBlocked);
+ global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
// Create a context and set an x property on it's global object.
LocalContext context0(NULL, global_template);
CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
-
- v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
- array->Set(0, v8_str("a"));
- array->Set(1, v8_str("b"));
- context1->Global()->Set(v8_str("array"), array);
- ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
- array->TurnOnAccessCheck();
- CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
- CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
- CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
}
}
TEST(AccessCheckThrows) {
i::FLAG_allow_natives_syntax = true;
+ i::FLAG_turbo_try_catch = true;
v8::V8::Initialize();
v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
v8::Isolate* isolate = CcTest::isolate();
// check callbacks that will block access.
v8::Handle<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate);
- global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
- IndexAccessAlwaysBlocked);
+ global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
// Create a context and set an x property on it's global object.
LocalContext context0(NULL, global_template);
context1->Global()->Set(v8_str("has_own_property"),
has_own_property_fun->GetFunction());
- { v8::TryCatch try_catch;
+ {
+ v8::TryCatch try_catch(isolate);
access_check_fail_thrown = false;
CompileRun("other.x;");
CHECK(access_check_fail_thrown);
TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
+static bool interrupt_was_called = false;
+
+
+void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) {
+ interrupt_was_called = true;
+}
+
+
+TEST(RequestInterruptSmallScripts) {
+ LocalContext env;
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+
+ interrupt_was_called = false;
+ isolate->RequestInterrupt(&SmallScriptsInterruptCallback, NULL);
+ CompileRun("(function(x){return x;})(1);");
+ CHECK(interrupt_was_called);
+}
+
+
static Local<Value> function_new_expected_env;
static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
CHECK(function_new_expected_env->Equals(info.Data()));
env->Global()->Set(v8_str("func"), func);
Local<Value> result = CompileRun("func();");
CHECK(v8::Integer::New(isolate, 17)->Equals(result));
- // Verify function not cached
- int serial_number =
- i::Smi::cast(v8::Utils::OpenHandle(*func)
- ->shared()->get_api_func_data()->serial_number())->value();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
- i::Handle<i::FixedArray> cache(i_isolate->native_context()->function_cache());
- if (serial_number < cache->length()) {
- CHECK(cache->get(serial_number)->IsUndefined());
- }
+ // Verify function not cached
+ auto serial_number = handle(i::Smi::cast(v8::Utils::OpenHandle(*func)
+ ->shared()
+ ->get_api_func_data()
+ ->serial_number()),
+ i_isolate);
+ auto cache = i_isolate->function_cache();
+ CHECK(cache->Lookup(serial_number)->IsTheHole());
// Verify that each Function::New creates a new function instance
Local<Object> data2 = v8::Object::New(isolate);
function_new_expected_env = data2;
"%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
"check(wrap_set());\n",
wrap_function.start(), key, key, key, key, key, key);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
CompileRun(source.start());
DCHECK(!try_catch.HasCaught());
CHECK_EQ(9, count);
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope scope(isolate);
- v8::TryCatch try_catch;
+ v8::TryCatch try_catch(isolate);
v8::Isolate::DisallowJavascriptExecutionScope throw_js(
isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
CompileRun("1+1");
v8::HandleScope scope(isolate);
v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
- templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
+ templ->SetAccessCheckCallbacks(AccessCounter, NULL);
current->Global()->Set(v8_str("friend"), templ->NewInstance());
// Test access using __proto__ from the prototype chain.
- named_access_count = 0;
+ access_count = 0;
CompileRun("friend.__proto__ = {};");
- CHECK_EQ(2, named_access_count);
+ CHECK_EQ(2, access_count);
CompileRun("friend.__proto__;");
- CHECK_EQ(4, named_access_count);
+ CHECK_EQ(4, access_count);
// Test access using __proto__ as a hijacked function (A).
- named_access_count = 0;
+ access_count = 0;
CompileRun("var p = Object.prototype;"
"var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
"f.call(friend, {});");
- CHECK_EQ(1, named_access_count);
+ CHECK_EQ(1, access_count);
CompileRun("var p = Object.prototype;"
"var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
"f.call(friend);");
- CHECK_EQ(2, named_access_count);
+ CHECK_EQ(2, access_count);
// Test access using __proto__ as a hijacked function (B).
- named_access_count = 0;
+ access_count = 0;
CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
"f.call(friend, {});");
- CHECK_EQ(1, named_access_count);
+ CHECK_EQ(1, access_count);
CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
"f.call(friend);");
- CHECK_EQ(2, named_access_count);
+ CHECK_EQ(2, access_count);
// Test access using Object.setPrototypeOf reflective method.
- named_access_count = 0;
+ access_count = 0;
CompileRun("Object.setPrototypeOf(friend, {});");
- CHECK_EQ(1, named_access_count);
+ CHECK_EQ(1, access_count);
CompileRun("Object.getPrototypeOf(friend);");
- CHECK_EQ(2, named_access_count);
+ CHECK_EQ(2, access_count);
+}
+
+
+TEST(CaptureStackTraceForStackOverflow) {
+ v8::internal::FLAG_stack_size = 150;
+ LocalContext current;
+ v8::Isolate* isolate = current->GetIsolate();
+ v8::HandleScope scope(isolate);
+ V8::SetCaptureStackTraceForUncaughtExceptions(
+ true, 10, v8::StackTrace::kDetailed);
+ v8::TryCatch try_catch(isolate);
+ CompileRun("(function f(x) { f(x+1); })(0)");
+ CHECK(try_catch.HasCaught());
+}
+
+
+TEST(ScriptNameAndLineNumber) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope scope(isolate);
+ const char* url = "http://www.foo.com/foo.js";
+ v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
+ v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
+ Local<Script> script = v8::ScriptCompiler::Compile(
+ isolate, &script_source);
+ Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
+ CHECK(!script_name.IsEmpty());
+ CHECK(script_name->IsString());
+ String::Utf8Value utf8_name(script_name);
+ CHECK_EQ(0, strcmp(url, *utf8_name));
+ int line_number = script->GetUnboundScript()->GetLineNumber(0);
+ CHECK_EQ(13, line_number);
+}
+
+void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
+ const char* expected_source_mapping_url) {
+ if (expected_source_url != NULL) {
+ v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
+ CHECK_EQ(0, strcmp(expected_source_url, *url));
+ } else {
+ CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
+ }
+ if (expected_source_mapping_url != NULL) {
+ v8::String::Utf8Value url(
+ script->GetUnboundScript()->GetSourceMappingURL());
+ CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
+ } else {
+ CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
+ }
+}
+
+void SourceURLHelper(const char* source, const char* expected_source_url,
+ const char* expected_source_mapping_url) {
+ Local<Script> script = v8_compile(source);
+ CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
+}
+
+
+TEST(ScriptSourceURLAndSourceMappingURL) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope scope(isolate);
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceURL=bar1.js\n", "bar1.js", NULL);
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
+
+ // Both sourceURL and sourceMappingURL.
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceURL=bar3.js\n"
+ "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
+
+ // Two source URLs; the first one is ignored.
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceURL=ignoreme.js\n"
+ "//# sourceURL=bar5.js\n", "bar5.js", NULL);
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceMappingURL=ignoreme.js\n"
+ "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
+
+ // SourceURL or sourceMappingURL in the middle of the script.
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceURL=bar7.js\n"
+ "function baz() {}\n", "bar7.js", NULL);
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceMappingURL=bar8.js\n"
+ "function baz() {}\n", NULL, "bar8.js");
+
+ // Too much whitespace.
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceURL=bar9.js\n"
+ "//# sourceMappingURL=bar10.js\n", NULL, NULL);
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceURL =bar11.js\n"
+ "//# sourceMappingURL =bar12.js\n", NULL, NULL);
+
+ // Disallowed characters in value.
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceURL=bar13 .js \n"
+ "//# sourceMappingURL=bar14 .js \n",
+ NULL, NULL);
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceURL=bar15\t.js \n"
+ "//# sourceMappingURL=bar16\t.js \n",
+ NULL, NULL);
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceURL=bar17'.js \n"
+ "//# sourceMappingURL=bar18'.js \n",
+ NULL, NULL);
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceURL=bar19\".js \n"
+ "//# sourceMappingURL=bar20\".js \n",
+ NULL, NULL);
+
+ // Not too much whitespace.
+ SourceURLHelper("function foo() {}\n"
+ "//# sourceURL= bar21.js \n"
+ "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
+}
+
+
+TEST(GetOwnPropertyDescriptor) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope scope(isolate);
+ CompileRun(
+ "var x = { value : 13};"
+ "Object.defineProperty(x, 'p0', {value : 12});"
+ "Object.defineProperty(x, 'p1', {"
+ " set : function(value) { this.value = value; },"
+ " get : function() { return this.value; },"
+ "});");
+ Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
+ Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
+ CHECK(desc->IsUndefined());
+ desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
+ CHECK(v8_num(12)->Equals(Local<Object>::Cast(desc)->Get(v8_str("value"))));
+ desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
+ Local<Function> set =
+ Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
+ Local<Function> get =
+ Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
+ CHECK(v8_num(13)->Equals(get->Call(x, 0, NULL)));
+ Handle<Value> args[] = { v8_num(14) };
+ set->Call(x, 1, args);
+ CHECK(v8_num(14)->Equals(get->Call(x, 0, NULL)));
+}
+
+
+TEST(Regress411877) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::ObjectTemplate> object_template =
+ v8::ObjectTemplate::New(isolate);
+ object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
+
+ v8::Handle<Context> context = Context::New(isolate);
+ v8::Context::Scope context_scope(context);
+
+ context->Global()->Set(v8_str("o"), object_template->NewInstance());
+ CompileRun("Object.getOwnPropertyNames(o)");
+}
+
+
+TEST(GetHiddenPropertyTableAfterAccessCheck) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::ObjectTemplate> object_template =
+ v8::ObjectTemplate::New(isolate);
+ object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
+
+ v8::Handle<Context> context = Context::New(isolate);
+ v8::Context::Scope context_scope(context);
+
+ v8::Handle<v8::Object> obj = object_template->NewInstance();
+ obj->Set(v8_str("key"), v8_str("value"));
+ obj->Delete(v8_str("key"));
+
+ obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
+}
+
+
+TEST(Regress411793) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::ObjectTemplate> object_template =
+ v8::ObjectTemplate::New(isolate);
+ object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
+
+ v8::Handle<Context> context = Context::New(isolate);
+ v8::Context::Scope context_scope(context);
+
+ context->Global()->Set(v8_str("o"), object_template->NewInstance());
+ CompileRun(
+ "Object.defineProperty(o, 'key', "
+ " { get: function() {}, set: function() {} });");
+}
+
+class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
+ public:
+ explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
+
+ virtual size_t GetMoreData(const uint8_t** src) {
+ // Unlike in real use cases, this function will never block.
+ if (chunks_[index_] == NULL) {
+ return 0;
+ }
+ // Copy the data, since the caller takes ownership of it.
+ size_t len = strlen(chunks_[index_]);
+ // We don't need to zero-terminate since we return the length.
+ uint8_t* copy = new uint8_t[len];
+ memcpy(copy, chunks_[index_], len);
+ *src = copy;
+ ++index_;
+ return len;
+ }
+
+ // Helper for constructing a string from chunks (the compilation needs it
+ // too).
+ static char* FullSourceString(const char** chunks) {
+ size_t total_len = 0;
+ for (size_t i = 0; chunks[i] != NULL; ++i) {
+ total_len += strlen(chunks[i]);
+ }
+ char* full_string = new char[total_len + 1];
+ size_t offset = 0;
+ for (size_t i = 0; chunks[i] != NULL; ++i) {
+ size_t len = strlen(chunks[i]);
+ memcpy(full_string + offset, chunks[i], len);
+ offset += len;
+ }
+ full_string[total_len] = 0;
+ return full_string;
+ }
+
+ private:
+ const char** chunks_;
+ unsigned index_;
+};
+
+
+// Helper function for running streaming tests.
+void RunStreamingTest(const char** chunks,
+ v8::ScriptCompiler::StreamedSource::Encoding encoding =
+ v8::ScriptCompiler::StreamedSource::ONE_BYTE,
+ bool expected_success = true,
+ const char* expected_source_url = NULL,
+ const char* expected_source_mapping_url = NULL) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope scope(isolate);
+ v8::TryCatch try_catch(isolate);
+
+ v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
+ encoding);
+ v8::ScriptCompiler::ScriptStreamingTask* task =
+ v8::ScriptCompiler::StartStreamingScript(isolate, &source);
+
+ // TestSourceStream::GetMoreData won't block, so it's OK to just run the
+ // task here in the main thread.
+ task->Run();
+ delete task;
+
+ // Possible errors are only produced while compiling.
+ CHECK_EQ(false, try_catch.HasCaught());
+
+ v8::ScriptOrigin origin(v8_str("http://foo.com"));
+ char* full_source = TestSourceStream::FullSourceString(chunks);
+ v8::Handle<Script> script = v8::ScriptCompiler::Compile(
+ isolate, &source, v8_str(full_source), origin);
+ if (expected_success) {
+ CHECK(!script.IsEmpty());
+ v8::Handle<Value> result(script->Run());
+ // All scripts are supposed to return the fixed value 13 when ran.
+ CHECK_EQ(13, result->Int32Value());
+ CheckMagicComments(script, expected_source_url,
+ expected_source_mapping_url);
+ } else {
+ CHECK(script.IsEmpty());
+ CHECK(try_catch.HasCaught());
+ }
+ delete[] full_source;
+}
+
+
+TEST(StreamingSimpleScript) {
+ // This script is unrealistically small, since no one chunk is enough to fill
+ // the backing buffer of Scanner, let alone overflow it.
+ const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
+ NULL};
+ RunStreamingTest(chunks);
+}
+
+
+TEST(StreamingBiggerScript) {
+ const char* chunk1 =
+ "function foo() {\n"
+ " // Make this chunk sufficiently long so that it will overflow the\n"
+ " // backing buffer of the Scanner.\n"
+ " var i = 0;\n"
+ " var result = 0;\n"
+ " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
+ " result = 0;\n"
+ " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
+ " result = 0;\n"
+ " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
+ " result = 0;\n"
+ " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
+ " return result;\n"
+ "}\n";
+ const char* chunks[] = {chunk1, "foo(); ", NULL};
+ RunStreamingTest(chunks);
+}
+
+
+TEST(StreamingScriptWithParseError) {
+ // Test that parse errors from streamed scripts are propagated correctly.
+ {
+ char chunk1[] =
+ " // This will result in a parse error.\n"
+ " var if else then foo";
+ char chunk2[] = " 13\n";
+ const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
+ false);
+ }
+ // Test that the next script succeeds normally.
+ {
+ char chunk1[] =
+ " // This will be parsed successfully.\n"
+ " function foo() { return ";
+ char chunk2[] = " 13; }\n";
+ const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+
+ RunStreamingTest(chunks);
+ }
+}
+
+
+TEST(StreamingUtf8Script) {
+ // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
+ // don't like it.
+ const char* chunk1 =
+ "function foo() {\n"
+ " // This function will contain an UTF-8 character which is not in\n"
+ " // ASCII.\n"
+ " var foob\xec\x92\x81r = 13;\n"
+ " return foob\xec\x92\x81r;\n"
+ "}\n";
+ const char* chunks[] = {chunk1, "foo(); ", NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+}
+
+
+TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
+ // A sanity check to prove that the approach of splitting UTF-8
+ // characters is correct. Here is an UTF-8 character which will take three
+ // bytes.
+ const char* reference = "\xec\x92\x81";
+ CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
+
+ char chunk1[] =
+ "function foo() {\n"
+ " // This function will contain an UTF-8 character which is not in\n"
+ " // ASCII.\n"
+ " var foob";
+ char chunk2[] =
+ "XXXr = 13;\n"
+ " return foob\xec\x92\x81r;\n"
+ "}\n";
+ for (int i = 0; i < 3; ++i) {
+ chunk2[i] = reference[i];
+ }
+ const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+}
+
+
+TEST(StreamingUtf8ScriptWithSplitCharacters) {
+ // Stream data where a multi-byte UTF-8 character is split between two data
+ // chunks.
+ const char* reference = "\xec\x92\x81";
+ char chunk1[] =
+ "function foo() {\n"
+ " // This function will contain an UTF-8 character which is not in\n"
+ " // ASCII.\n"
+ " var foobX";
+ char chunk2[] =
+ "XXr = 13;\n"
+ " return foob\xec\x92\x81r;\n"
+ "}\n";
+ chunk1[strlen(chunk1) - 1] = reference[0];
+ chunk2[0] = reference[1];
+ chunk2[1] = reference[2];
+ const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+}
+
+
+TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
+ // Tests edge cases which should still be decoded correctly.
+
+ // Case 1: a chunk contains only bytes for a split character (and no other
+ // data). This kind of a chunk would be exceptionally small, but we should
+ // still decode it correctly.
+ const char* reference = "\xec\x92\x81";
+ // The small chunk is at the beginning of the split character
+ {
+ char chunk1[] =
+ "function foo() {\n"
+ " // This function will contain an UTF-8 character which is not in\n"
+ " // ASCII.\n"
+ " var foob";
+ char chunk2[] = "XX";
+ char chunk3[] =
+ "Xr = 13;\n"
+ " return foob\xec\x92\x81r;\n"
+ "}\n";
+ chunk2[0] = reference[0];
+ chunk2[1] = reference[1];
+ chunk3[0] = reference[2];
+ const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+ }
+ // The small chunk is at the end of a character
+ {
+ char chunk1[] =
+ "function foo() {\n"
+ " // This function will contain an UTF-8 character which is not in\n"
+ " // ASCII.\n"
+ " var foobX";
+ char chunk2[] = "XX";
+ char chunk3[] =
+ "r = 13;\n"
+ " return foob\xec\x92\x81r;\n"
+ "}\n";
+ chunk1[strlen(chunk1) - 1] = reference[0];
+ chunk2[0] = reference[1];
+ chunk2[1] = reference[2];
+ const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+ }
+ // Case 2: the script ends with a multi-byte character. Make sure that it's
+ // decoded correctly and not just ignored.
+ {
+ char chunk1[] =
+ "var foob\xec\x92\x81 = 13;\n"
+ "foob\xec\x92\x81";
+ const char* chunks[] = {chunk1, NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+ }
}
-TEST(CaptureStackTraceForStackOverflow) {
- v8::internal::FLAG_stack_size = 150;
- LocalContext current;
- v8::Isolate* isolate = current->GetIsolate();
- v8::HandleScope scope(isolate);
- V8::SetCaptureStackTraceForUncaughtExceptions(
- true, 10, v8::StackTrace::kDetailed);
- v8::TryCatch try_catch;
- CompileRun("(function f(x) { f(x+1); })(0)");
- CHECK(try_catch.HasCaught());
+TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
+ // Test cases where a UTF-8 character is split over several chunks. Those
+ // cases are not supported (the embedder should give the data in big enough
+ // chunks), but we shouldn't crash, just produce a parse error.
+ const char* reference = "\xec\x92\x81";
+ char chunk1[] =
+ "function foo() {\n"
+ " // This function will contain an UTF-8 character which is not in\n"
+ " // ASCII.\n"
+ " var foobX";
+ char chunk2[] = "X";
+ char chunk3[] =
+ "Xr = 13;\n"
+ " return foob\xec\x92\x81r;\n"
+ "}\n";
+ chunk1[strlen(chunk1) - 1] = reference[0];
+ chunk2[0] = reference[1];
+ chunk3[0] = reference[2];
+ const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
+
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
}
-TEST(ScriptNameAndLineNumber) {
+TEST(StreamingProducesParserCache) {
+ i::FLAG_min_preparse_length = 0;
+ const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
+ NULL};
+
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
- const char* url = "http://www.foo.com/foo.js";
- v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
- v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
- Local<Script> script = v8::ScriptCompiler::Compile(
- isolate, &script_source);
- Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
- CHECK(!script_name.IsEmpty());
- CHECK(script_name->IsString());
- String::Utf8Value utf8_name(script_name);
- CHECK_EQ(0, strcmp(url, *utf8_name));
- int line_number = script->GetUnboundScript()->GetLineNumber(0);
- CHECK_EQ(13, line_number);
-}
-void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
- const char* expected_source_mapping_url) {
- if (expected_source_url != NULL) {
- v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
- CHECK_EQ(0, strcmp(expected_source_url, *url));
- } else {
- CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
- }
- if (expected_source_mapping_url != NULL) {
- v8::String::Utf8Value url(
- script->GetUnboundScript()->GetSourceMappingURL());
- CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
- } else {
- CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
- }
-}
+ v8::ScriptCompiler::StreamedSource source(
+ new TestSourceStream(chunks),
+ v8::ScriptCompiler::StreamedSource::ONE_BYTE);
+ v8::ScriptCompiler::ScriptStreamingTask* task =
+ v8::ScriptCompiler::StartStreamingScript(
+ isolate, &source, v8::ScriptCompiler::kProduceParserCache);
-void SourceURLHelper(const char* source, const char* expected_source_url,
- const char* expected_source_mapping_url) {
- Local<Script> script = v8_compile(source);
- CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
+ // TestSourceStream::GetMoreData won't block, so it's OK to just run the
+ // task here in the main thread.
+ task->Run();
+ delete task;
+
+ const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
+ CHECK(cached_data != NULL);
+ CHECK(cached_data->data != NULL);
+ CHECK(!cached_data->rejected);
+ CHECK_GT(cached_data->length, 0);
}
-TEST(ScriptSourceURLAndSourceMappingURL) {
+TEST(StreamingWithDebuggingDoesNotProduceParserCache) {
+ // If the debugger is active, we should just not produce parser cache at
+ // all. This is a regeression test: We used to produce a parser cache without
+ // any data in it (just headers).
+ i::FLAG_min_preparse_length = 0;
+ const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
+ NULL};
+
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
- SourceURLHelper("function foo() {}\n"
- "//# sourceURL=bar1.js\n", "bar1.js", NULL);
- SourceURLHelper("function foo() {}\n"
- "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
- // Both sourceURL and sourceMappingURL.
- SourceURLHelper("function foo() {}\n"
- "//# sourceURL=bar3.js\n"
- "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
+ // Make the debugger active by setting a breakpoint.
+ CompileRun("function break_here() { }");
+ i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(
+ v8::Utils::OpenHandle(*env->Global()->Get(v8_str("break_here"))));
+ EnableDebugger();
+ v8::internal::Debug* debug = CcTest::i_isolate()->debug();
+ int position = 0;
+ debug->SetBreakPoint(func, i::Handle<i::Object>(v8::internal::Smi::FromInt(1),
+ CcTest::i_isolate()),
+ &position);
- // Two source URLs; the first one is ignored.
- SourceURLHelper("function foo() {}\n"
- "//# sourceURL=ignoreme.js\n"
- "//# sourceURL=bar5.js\n", "bar5.js", NULL);
- SourceURLHelper("function foo() {}\n"
- "//# sourceMappingURL=ignoreme.js\n"
- "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
+ v8::ScriptCompiler::StreamedSource source(
+ new TestSourceStream(chunks),
+ v8::ScriptCompiler::StreamedSource::ONE_BYTE);
+ v8::ScriptCompiler::ScriptStreamingTask* task =
+ v8::ScriptCompiler::StartStreamingScript(
+ isolate, &source, v8::ScriptCompiler::kProduceParserCache);
- // SourceURL or sourceMappingURL in the middle of the script.
- SourceURLHelper("function foo() {}\n"
- "//# sourceURL=bar7.js\n"
- "function baz() {}\n", "bar7.js", NULL);
- SourceURLHelper("function foo() {}\n"
- "//# sourceMappingURL=bar8.js\n"
- "function baz() {}\n", NULL, "bar8.js");
+ // TestSourceStream::GetMoreData won't block, so it's OK to just run the
+ // task here in the main thread.
+ task->Run();
+ delete task;
- // Too much whitespace.
- SourceURLHelper("function foo() {}\n"
- "//# sourceURL=bar9.js\n"
- "//# sourceMappingURL=bar10.js\n", NULL, NULL);
- SourceURLHelper("function foo() {}\n"
- "//# sourceURL =bar11.js\n"
- "//# sourceMappingURL =bar12.js\n", NULL, NULL);
+ // Check that we got no cached data.
+ CHECK(source.GetCachedData() == NULL);
+ DisableDebugger();
+}
- // Disallowed characters in value.
- SourceURLHelper("function foo() {}\n"
- "//# sourceURL=bar13 .js \n"
- "//# sourceMappingURL=bar14 .js \n",
- NULL, NULL);
- SourceURLHelper("function foo() {}\n"
- "//# sourceURL=bar15\t.js \n"
- "//# sourceMappingURL=bar16\t.js \n",
- NULL, NULL);
- SourceURLHelper("function foo() {}\n"
- "//# sourceURL=bar17'.js \n"
- "//# sourceMappingURL=bar18'.js \n",
- NULL, NULL);
- SourceURLHelper("function foo() {}\n"
- "//# sourceURL=bar19\".js \n"
- "//# sourceMappingURL=bar20\".js \n",
- NULL, NULL);
- // Not too much whitespace.
- SourceURLHelper("function foo() {}\n"
- "//# sourceURL= bar21.js \n"
- "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
+TEST(StreamingScriptWithInvalidUtf8) {
+ // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
+ // chunk don't produce a crash.
+ const char* reference = "\xec\x92\x81\x80\x80";
+ char chunk1[] =
+ "function foo() {\n"
+ " // This function will contain an UTF-8 character which is not in\n"
+ " // ASCII.\n"
+ " var foobXXXXX"; // Too many bytes which look like incomplete chars!
+ char chunk2[] =
+ "r = 13;\n"
+ " return foob\xec\x92\x81\x80\x80r;\n"
+ "}\n";
+ for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
+
+ const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
}
-TEST(GetOwnPropertyDescriptor) {
+TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
+ // Regression test: Stream data where there are several multi-byte UTF-8
+ // characters in a sequence and one of them is split between two data chunks.
+ const char* reference = "\xec\x92\x81";
+ char chunk1[] =
+ "function foo() {\n"
+ " // This function will contain an UTF-8 character which is not in\n"
+ " // ASCII.\n"
+ " var foob\xec\x92\x81X";
+ char chunk2[] =
+ "XXr = 13;\n"
+ " return foob\xec\x92\x81\xec\x92\x81r;\n"
+ "}\n";
+ chunk1[strlen(chunk1) - 1] = reference[0];
+ chunk2[0] = reference[1];
+ chunk2[1] = reference[2];
+ const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+}
+
+
+TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
+ // Another regression test, similar to the previous one. The difference is
+ // that the split character is not the last one in the sequence.
+ const char* reference = "\xec\x92\x81";
+ char chunk1[] =
+ "function foo() {\n"
+ " // This function will contain an UTF-8 character which is not in\n"
+ " // ASCII.\n"
+ " var foobX";
+ char chunk2[] =
+ "XX\xec\x92\x81r = 13;\n"
+ " return foob\xec\x92\x81\xec\x92\x81r;\n"
+ "}\n";
+ chunk1[strlen(chunk1) - 1] = reference[0];
+ chunk2[0] = reference[1];
+ chunk2[1] = reference[2];
+ const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+}
+
+
+TEST(StreamingWithHarmonyScopes) {
+ // Don't use RunStreamingTest here so that both scripts get to use the same
+ // LocalContext and HandleScope.
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
- CompileRun(
- "var x = { value : 13};"
- "Object.defineProperty(x, 'p0', {value : 12});"
- "Object.defineProperty(x, 'p1', {"
- " set : function(value) { this.value = value; },"
- " get : function() { return this.value; },"
- "});");
- Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
- Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
- CHECK(desc->IsUndefined());
- desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
- CHECK(v8_num(12)->Equals(Local<Object>::Cast(desc)->Get(v8_str("value"))));
- desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
- Local<Function> set =
- Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
- Local<Function> get =
- Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
- CHECK(v8_num(13)->Equals(get->Call(x, 0, NULL)));
- Handle<Value> args[] = { v8_num(14) };
- set->Call(x, 1, args);
- CHECK(v8_num(14)->Equals(get->Call(x, 0, NULL)));
-}
+ // First, run a script with a let variable.
+ CompileRun("\"use strict\"; let x = 1;");
+
+ // Then stream a script which (erroneously) tries to introduce the same
+ // variable again.
+ const char* chunks[] = {"\"use strict\"; let x = 2;", NULL};
+
+ v8::TryCatch try_catch(isolate);
+ v8::ScriptCompiler::StreamedSource source(
+ new TestSourceStream(chunks),
+ v8::ScriptCompiler::StreamedSource::ONE_BYTE);
+ v8::ScriptCompiler::ScriptStreamingTask* task =
+ v8::ScriptCompiler::StartStreamingScript(isolate, &source);
+ task->Run();
+ delete task;
-TEST(Regress411877) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::ObjectTemplate> object_template =
- v8::ObjectTemplate::New(isolate);
- object_template->SetAccessCheckCallbacks(NamedAccessCounter,
- IndexedAccessCounter);
+ // Parsing should succeed (the script will be parsed and compiled in a context
+ // independent way, so the error is not detected).
+ CHECK_EQ(false, try_catch.HasCaught());
- v8::Handle<Context> context = Context::New(isolate);
- v8::Context::Scope context_scope(context);
+ v8::ScriptOrigin origin(v8_str("http://foo.com"));
+ char* full_source = TestSourceStream::FullSourceString(chunks);
+ v8::Handle<Script> script = v8::ScriptCompiler::Compile(
+ isolate, &source, v8_str(full_source), origin);
+ CHECK(!script.IsEmpty());
+ CHECK_EQ(false, try_catch.HasCaught());
- context->Global()->Set(v8_str("o"), object_template->NewInstance());
- CompileRun("Object.getOwnPropertyNames(o)");
+ // Running the script exposes the error.
+ v8::Handle<Value> result(script->Run());
+ CHECK(result.IsEmpty());
+ CHECK(try_catch.HasCaught());
+ delete[] full_source;
}
-TEST(GetHiddenPropertyTableAfterAccessCheck) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::ObjectTemplate> object_template =
- v8::ObjectTemplate::New(isolate);
- object_template->SetAccessCheckCallbacks(NamedAccessCounter,
- IndexedAccessCounter);
+TEST(CodeCache) {
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
- v8::Handle<Context> context = Context::New(isolate);
- v8::Context::Scope context_scope(context);
+ const char* source = "Math.sqrt(4)";
+ const char* origin = "code cache test";
+ v8::ScriptCompiler::CachedData* cache;
- v8::Handle<v8::Object> obj = object_template->NewInstance();
- obj->Set(v8_str("key"), v8_str("value"));
- obj->Delete(v8_str("key"));
+ v8::Isolate* isolate1 = v8::Isolate::New(create_params);
+ {
+ v8::Isolate::Scope iscope(isolate1);
+ v8::HandleScope scope(isolate1);
+ v8::Local<v8::Context> context = v8::Context::New(isolate1);
+ v8::Context::Scope cscope(context);
+ v8::Local<v8::String> source_string = v8_str(source);
+ v8::ScriptOrigin script_origin(v8_str(origin));
+ v8::ScriptCompiler::Source source(source_string, script_origin);
+ v8::ScriptCompiler::CompileOptions option =
+ v8::ScriptCompiler::kProduceCodeCache;
+ v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
+ int length = source.GetCachedData()->length;
+ uint8_t* cache_data = new uint8_t[length];
+ memcpy(cache_data, source.GetCachedData()->data, length);
+ cache = new v8::ScriptCompiler::CachedData(
+ cache_data, length, v8::ScriptCompiler::CachedData::BufferOwned);
+ }
+ isolate1->Dispose();
- obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
+ v8::Isolate* isolate2 = v8::Isolate::New(create_params);
+ {
+ v8::Isolate::Scope iscope(isolate2);
+ v8::HandleScope scope(isolate2);
+ v8::Local<v8::Context> context = v8::Context::New(isolate2);
+ v8::Context::Scope cscope(context);
+ v8::Local<v8::String> source_string = v8_str(source);
+ v8::ScriptOrigin script_origin(v8_str(origin));
+ v8::ScriptCompiler::Source source(source_string, script_origin, cache);
+ v8::ScriptCompiler::CompileOptions option =
+ v8::ScriptCompiler::kConsumeCodeCache;
+ v8::Local<v8::Script> script;
+ {
+ i::DisallowCompilation no_compile(
+ reinterpret_cast<i::Isolate*>(isolate2));
+ script = v8::ScriptCompiler::Compile(context, &source, option)
+ .ToLocalChecked();
+ }
+ CHECK_EQ(2, script->Run()->ToInt32(isolate2)->Int32Value());
+ }
+ isolate2->Dispose();
}
-TEST(Regress411793) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::ObjectTemplate> object_template =
- v8::ObjectTemplate::New(isolate);
- object_template->SetAccessCheckCallbacks(NamedAccessCounter,
- IndexedAccessCounter);
+void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
+ const char* garbage = "garbage garbage garbage garbage garbage garbage";
+ const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
+ int length = 16;
+ v8::ScriptCompiler::CachedData* cached_data =
+ new v8::ScriptCompiler::CachedData(data, length);
+ DCHECK(!cached_data->rejected);
+ v8::ScriptOrigin origin(v8_str("origin"));
+ v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
+ v8::Handle<v8::Script> script =
+ v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
+ CHECK(cached_data->rejected);
+ CHECK_EQ(42, script->Run()->Int32Value());
+}
- v8::Handle<Context> context = Context::New(isolate);
- v8::Context::Scope context_scope(context);
- context->Global()->Set(v8_str("o"), object_template->NewInstance());
- CompileRun(
- "Object.defineProperty(o, 'key', "
- " { get: function() {}, set: function() {} });");
+TEST(InvalidCacheData) {
+ v8::V8::Initialize();
+ v8::HandleScope scope(CcTest::isolate());
+ LocalContext context;
+ TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
+ TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
}
-class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
- public:
- explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
- virtual size_t GetMoreData(const uint8_t** src) {
- // Unlike in real use cases, this function will never block.
- if (chunks_[index_] == NULL) {
- return 0;
- }
- // Copy the data, since the caller takes ownership of it.
- size_t len = strlen(chunks_[index_]);
- // We don't need to zero-terminate since we return the length.
- uint8_t* copy = new uint8_t[len];
- memcpy(copy, chunks_[index_], len);
- *src = copy;
- ++index_;
- return len;
+TEST(ParserCacheRejectedGracefully) {
+ i::FLAG_min_preparse_length = 0;
+ v8::V8::Initialize();
+ v8::HandleScope scope(CcTest::isolate());
+ LocalContext context;
+ // Produce valid cached data.
+ v8::ScriptOrigin origin(v8_str("origin"));
+ v8::Local<v8::String> source_str = v8_str("function foo() {}");
+ v8::ScriptCompiler::Source source(source_str, origin);
+ v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
+ CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
+ CHECK(!script.IsEmpty());
+ const v8::ScriptCompiler::CachedData* original_cached_data =
+ source.GetCachedData();
+ CHECK(original_cached_data != NULL);
+ CHECK(original_cached_data->data != NULL);
+ CHECK(!original_cached_data->rejected);
+ CHECK_GT(original_cached_data->length, 0);
+ // Recompiling the same script with it won't reject the data.
+ {
+ v8::ScriptCompiler::Source source_with_cached_data(
+ source_str, origin,
+ new v8::ScriptCompiler::CachedData(original_cached_data->data,
+ original_cached_data->length));
+ v8::Handle<v8::Script> script =
+ v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
+ v8::ScriptCompiler::kConsumeParserCache);
+ CHECK(!script.IsEmpty());
+ const v8::ScriptCompiler::CachedData* new_cached_data =
+ source_with_cached_data.GetCachedData();
+ CHECK(new_cached_data != NULL);
+ CHECK(!new_cached_data->rejected);
}
-
- // Helper for constructing a string from chunks (the compilation needs it
- // too).
- static char* FullSourceString(const char** chunks) {
- size_t total_len = 0;
- for (size_t i = 0; chunks[i] != NULL; ++i) {
- total_len += strlen(chunks[i]);
- }
- char* full_string = new char[total_len + 1];
- size_t offset = 0;
- for (size_t i = 0; chunks[i] != NULL; ++i) {
- size_t len = strlen(chunks[i]);
- memcpy(full_string + offset, chunks[i], len);
- offset += len;
- }
- full_string[total_len] = 0;
- return full_string;
+ // Compile an incompatible script with the cached data. The new script doesn't
+ // have the same starting position for the function as the old one, so the old
+ // cached data will be incompatible with it and will be rejected.
+ {
+ v8::Local<v8::String> incompatible_source_str =
+ v8_str(" function foo() {}");
+ v8::ScriptCompiler::Source source_with_cached_data(
+ incompatible_source_str, origin,
+ new v8::ScriptCompiler::CachedData(original_cached_data->data,
+ original_cached_data->length));
+ v8::Handle<v8::Script> script =
+ v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
+ v8::ScriptCompiler::kConsumeParserCache);
+ CHECK(!script.IsEmpty());
+ const v8::ScriptCompiler::CachedData* new_cached_data =
+ source_with_cached_data.GetCachedData();
+ CHECK(new_cached_data != NULL);
+ CHECK(new_cached_data->rejected);
}
+}
- private:
- const char** chunks_;
- unsigned index_;
-};
+TEST(StringConcatOverflow) {
+ v8::V8::Initialize();
+ v8::HandleScope scope(CcTest::isolate());
+ RandomLengthOneByteResource* r =
+ new RandomLengthOneByteResource(i::String::kMaxLength);
+ v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
+ CHECK(!str.IsEmpty());
+ v8::TryCatch try_catch(CcTest::isolate());
+ v8::Local<v8::String> result = v8::String::Concat(str, str);
+ CHECK(result.IsEmpty());
+ CHECK(!try_catch.HasCaught());
+}
-// Helper function for running streaming tests.
-void RunStreamingTest(const char** chunks,
- v8::ScriptCompiler::StreamedSource::Encoding encoding =
- v8::ScriptCompiler::StreamedSource::ONE_BYTE,
- bool expected_success = true,
- const char* expected_source_url = NULL,
- const char* expected_source_mapping_url = NULL) {
- LocalContext env;
- v8::Isolate* isolate = env->GetIsolate();
- v8::HandleScope scope(isolate);
- v8::TryCatch try_catch;
- v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
- encoding);
- v8::ScriptCompiler::ScriptStreamingTask* task =
- v8::ScriptCompiler::StartStreamingScript(isolate, &source);
+TEST(TurboAsmDisablesNeuter) {
+ v8::V8::Initialize();
+ v8::HandleScope scope(CcTest::isolate());
+ LocalContext context;
+#if V8_TURBOFAN_TARGET
+ bool should_be_neuterable = !i::FLAG_turbo_asm;
+#else
+ bool should_be_neuterable = true;
+#endif
+ const char* load =
+ "function Module(stdlib, foreign, heap) {"
+ " 'use asm';"
+ " var MEM32 = new stdlib.Int32Array(heap);"
+ " function load() { return MEM32[0]; }"
+ " return { load: load };"
+ "}"
+ "var buffer = new ArrayBuffer(4);"
+ "Module(this, {}, buffer).load();"
+ "buffer";
- // TestSourceStream::GetMoreData won't block, so it's OK to just run the
- // task here in the main thread.
- task->Run();
- delete task;
+ i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF.
+ v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
+ CHECK_EQ(should_be_neuterable, result->IsNeuterable());
- // Possible errors are only produced while compiling.
- CHECK_EQ(false, try_catch.HasCaught());
+ const char* store =
+ "function Module(stdlib, foreign, heap) {"
+ " 'use asm';"
+ " var MEM32 = new stdlib.Int32Array(heap);"
+ " function store() { MEM32[0] = 0; }"
+ " return { store: store };"
+ "}"
+ "var buffer = new ArrayBuffer(4);"
+ "Module(this, {}, buffer).store();"
+ "buffer";
- v8::ScriptOrigin origin(v8_str("http://foo.com"));
- char* full_source = TestSourceStream::FullSourceString(chunks);
- v8::Handle<Script> script = v8::ScriptCompiler::Compile(
- isolate, &source, v8_str(full_source), origin);
- if (expected_success) {
- CHECK(!script.IsEmpty());
- v8::Handle<Value> result(script->Run());
- // All scripts are supposed to return the fixed value 13 when ran.
- CHECK_EQ(13, result->Int32Value());
- CheckMagicComments(script, expected_source_url,
- expected_source_mapping_url);
- } else {
- CHECK(script.IsEmpty());
+ i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF.
+ result = CompileRun(store).As<v8::ArrayBuffer>();
+ CHECK_EQ(should_be_neuterable, result->IsNeuterable());
+}
+
+
+TEST(GetPrototypeAccessControl) {
+ i::FLAG_allow_natives_syntax = true;
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
+ LocalContext env;
+
+ v8::Handle<v8::ObjectTemplate> obj_template =
+ v8::ObjectTemplate::New(isolate);
+ obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
+
+ env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
+
+ {
+ v8::TryCatch try_catch(isolate);
+ CompileRun(
+ "function f() { %_GetPrototype(prohibited); }"
+ "%OptimizeFunctionOnNextCall(f);"
+ "f();");
CHECK(try_catch.HasCaught());
}
- delete[] full_source;
}
-TEST(StreamingSimpleScript) {
- // This script is unrealistically small, since no one chunk is enough to fill
- // the backing buffer of Scanner, let alone overflow it.
- const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
- NULL};
- RunStreamingTest(chunks);
-}
+TEST(GetPrototypeHidden) {
+ i::FLAG_allow_natives_syntax = true;
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
+ LocalContext env;
+ Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
+ t->SetHiddenPrototype(true);
+ Handle<Object> proto = t->GetFunction()->NewInstance();
+ Handle<Object> object = Object::New(isolate);
+ Handle<Object> proto2 = Object::New(isolate);
+ object->SetPrototype(proto);
+ proto->SetPrototype(proto2);
-TEST(StreamingBiggerScript) {
- const char* chunk1 =
- "function foo() {\n"
- " // Make this chunk sufficiently long so that it will overflow the\n"
- " // backing buffer of the Scanner.\n"
- " var i = 0;\n"
- " var result = 0;\n"
- " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
- " result = 0;\n"
- " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
- " result = 0;\n"
- " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
- " result = 0;\n"
- " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
- " return result;\n"
- "}\n";
- const char* chunks[] = {chunk1, "foo(); ", NULL};
- RunStreamingTest(chunks);
-}
+ env->Global()->Set(v8_str("object"), object);
+ env->Global()->Set(v8_str("proto"), proto);
+ env->Global()->Set(v8_str("proto2"), proto2);
+ v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
+ CHECK(result->Equals(proto2));
-TEST(StreamingScriptWithParseError) {
- // Test that parse errors from streamed scripts are propagated correctly.
- {
- char chunk1[] =
- " // This will result in a parse error.\n"
- " var if else then foo";
- char chunk2[] = " 13\n";
- const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+ result = CompileRun(
+ "function f() { return %_GetPrototype(object); }"
+ "%OptimizeFunctionOnNextCall(f);"
+ "f()");
+ CHECK(result->Equals(proto2));
+}
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
- false);
- }
- // Test that the next script succeeds normally.
- {
- char chunk1[] =
- " // This will be parsed successfully.\n"
- " function foo() { return ";
- char chunk2[] = " 13; }\n";
- const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
- RunStreamingTest(chunks);
- }
+TEST(ClassPrototypeCreationContext) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
+ LocalContext env;
+
+ Handle<Object> result = Handle<Object>::Cast(
+ CompileRun("'use strict'; class Example { }; Example.prototype"));
+ CHECK(env.local() == result->CreationContext());
}
-TEST(StreamingUtf8Script) {
- // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
- // don't like it.
- const char* chunk1 =
- "function foo() {\n"
- " // This function will contain an UTF-8 character which is not in\n"
- " // ASCII.\n"
- " var foob\xec\x92\x81r = 13;\n"
- " return foob\xec\x92\x81r;\n"
- "}\n";
- const char* chunks[] = {chunk1, "foo(); ", NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+TEST(SimpleStreamingScriptWithSourceURL) {
+ const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
+ "//# sourceURL=bar2.js\n", NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
+ "bar2.js");
}
-TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
- // A sanity check to prove that the approach of splitting UTF-8
- // characters is correct. Here is an UTF-8 character which will take three
- // bytes.
- const char* reference = "\xec\x92\x81";
- CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
-
- char chunk1[] =
- "function foo() {\n"
- " // This function will contain an UTF-8 character which is not in\n"
- " // ASCII.\n"
- " var foob";
- char chunk2[] =
- "XXXr = 13;\n"
- " return foob\xec\x92\x81r;\n"
- "}\n";
- for (int i = 0; i < 3; ++i) {
- chunk2[i] = reference[i];
- }
- const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+TEST(StreamingScriptWithSplitSourceURL) {
+ const char* chunks[] = {"function foo() { ret", "urn 13; } f",
+ "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
+ "bar2.js");
}
-TEST(StreamingUtf8ScriptWithSplitCharacters) {
- // Stream data where a multi-byte UTF-8 character is split between two data
- // chunks.
- const char* reference = "\xec\x92\x81";
- char chunk1[] =
- "function foo() {\n"
- " // This function will contain an UTF-8 character which is not in\n"
- " // ASCII.\n"
- " var foobX";
- char chunk2[] =
- "XXr = 13;\n"
- " return foob\xec\x92\x81r;\n"
- "}\n";
- chunk1[strlen(chunk1) - 1] = reference[0];
- chunk2[0] = reference[1];
- chunk2[1] = reference[2];
- const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
+ const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
+ " sourceMappingURL=bar2.js\n", "foo();", NULL};
+ RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
+ "bar2.js");
}
-TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
- // Tests edge cases which should still be decoded correctly.
-
- // Case 1: a chunk contains only bytes for a split character (and no other
- // data). This kind of a chunk would be exceptionally small, but we should
- // still decode it correctly.
- const char* reference = "\xec\x92\x81";
- // The small chunk is at the beginning of the split character
+TEST(NewStringRangeError) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
+ const int length = i::String::kMaxLength + 1;
+ const int buffer_size = length * sizeof(uint16_t);
+ void* buffer = malloc(buffer_size);
+ if (buffer == NULL) return;
+ memset(buffer, 'A', buffer_size);
{
- char chunk1[] =
- "function foo() {\n"
- " // This function will contain an UTF-8 character which is not in\n"
- " // ASCII.\n"
- " var foob";
- char chunk2[] = "XX";
- char chunk3[] =
- "Xr = 13;\n"
- " return foob\xec\x92\x81r;\n"
- "}\n";
- chunk2[0] = reference[0];
- chunk2[1] = reference[1];
- chunk3[0] = reference[2];
- const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+ v8::TryCatch try_catch(isolate);
+ char* data = reinterpret_cast<char*>(buffer);
+ CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString,
+ length).IsEmpty());
+ CHECK(!try_catch.HasCaught());
}
- // The small chunk is at the end of a character
{
- char chunk1[] =
- "function foo() {\n"
- " // This function will contain an UTF-8 character which is not in\n"
- " // ASCII.\n"
- " var foobX";
- char chunk2[] = "XX";
- char chunk3[] =
- "r = 13;\n"
- " return foob\xec\x92\x81r;\n"
- "}\n";
- chunk1[strlen(chunk1) - 1] = reference[0];
- chunk2[0] = reference[1];
- chunk2[1] = reference[2];
- const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+ v8::TryCatch try_catch(isolate);
+ uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
+ CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString,
+ length).IsEmpty());
+ CHECK(!try_catch.HasCaught());
}
- // Case 2: the script ends with a multi-byte character. Make sure that it's
- // decoded correctly and not just ignored.
{
- char chunk1[] =
- "var foob\xec\x92\x81 = 13;\n"
- "foob\xec\x92\x81";
- const char* chunks[] = {chunk1, NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+ v8::TryCatch try_catch(isolate);
+ uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
+ CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString,
+ length).IsEmpty());
+ CHECK(!try_catch.HasCaught());
}
-}
-
-
-TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
- // Test cases where a UTF-8 character is split over several chunks. Those
- // cases are not supported (the embedder should give the data in big enough
- // chunks), but we shouldn't crash, just produce a parse error.
- const char* reference = "\xec\x92\x81";
- char chunk1[] =
- "function foo() {\n"
- " // This function will contain an UTF-8 character which is not in\n"
- " // ASCII.\n"
- " var foobX";
- char chunk2[] = "X";
- char chunk3[] =
- "Xr = 13;\n"
- " return foob\xec\x92\x81r;\n"
- "}\n";
- chunk1[strlen(chunk1) - 1] = reference[0];
- chunk2[0] = reference[1];
- chunk3[0] = reference[2];
- const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
-
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
-}
-
-
-TEST(StreamingProducesParserCache) {
- i::FLAG_min_preparse_length = 0;
- const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
- NULL};
+ free(buffer);
+}
+
+TEST(SealHandleScope) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
LocalContext env;
- v8::Isolate* isolate = env->GetIsolate();
- v8::HandleScope scope(isolate);
- v8::ScriptCompiler::StreamedSource source(
- new TestSourceStream(chunks),
- v8::ScriptCompiler::StreamedSource::ONE_BYTE);
- v8::ScriptCompiler::ScriptStreamingTask* task =
- v8::ScriptCompiler::StartStreamingScript(
- isolate, &source, v8::ScriptCompiler::kProduceParserCache);
+ v8::SealHandleScope seal(isolate);
- // TestSourceStream::GetMoreData won't block, so it's OK to just run the
- // task here in the main thread.
- task->Run();
- delete task;
+ // Should fail
+ v8::Local<v8::Object> obj = v8::Object::New(isolate);
- const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
- CHECK(cached_data != NULL);
- CHECK(cached_data->data != NULL);
- CHECK(!cached_data->rejected);
- CHECK_GT(cached_data->length, 0);
+ USE(obj);
}
-TEST(StreamingWithDebuggingDoesNotProduceParserCache) {
- // If the debugger is active, we should just not produce parser cache at
- // all. This is a regeression test: We used to produce a parser cache without
- // any data in it (just headers).
- i::FLAG_min_preparse_length = 0;
- const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
- NULL};
-
+TEST(SealHandleScopeNested) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
LocalContext env;
- v8::Isolate* isolate = env->GetIsolate();
- v8::HandleScope scope(isolate);
- // Make the debugger active by setting a breakpoint.
- CompileRun("function break_here() { }");
- i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(
- v8::Utils::OpenHandle(*env->Global()->Get(v8_str("break_here"))));
- v8::internal::Debug* debug = CcTest::i_isolate()->debug();
- int position = 0;
- debug->SetBreakPoint(func, i::Handle<i::Object>(v8::internal::Smi::FromInt(1),
- CcTest::i_isolate()),
- &position);
+ v8::SealHandleScope seal(isolate);
- v8::ScriptCompiler::StreamedSource source(
- new TestSourceStream(chunks),
- v8::ScriptCompiler::StreamedSource::ONE_BYTE);
- v8::ScriptCompiler::ScriptStreamingTask* task =
- v8::ScriptCompiler::StartStreamingScript(
- isolate, &source, v8::ScriptCompiler::kProduceParserCache);
+ {
+ v8::HandleScope handle_scope(isolate);
- // TestSourceStream::GetMoreData won't block, so it's OK to just run the
- // task here in the main thread.
- task->Run();
- delete task;
+ // Should work
+ v8::Local<v8::Object> obj = v8::Object::New(isolate);
- // Check that we got no cached data.
- CHECK(source.GetCachedData() == NULL);
+ USE(obj);
+ }
}
-TEST(StreamingScriptWithInvalidUtf8) {
- // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
- // chunk don't produce a crash.
- const char* reference = "\xec\x92\x81\x80\x80";
- char chunk1[] =
- "function foo() {\n"
- " // This function will contain an UTF-8 character which is not in\n"
- " // ASCII.\n"
- " var foobXXXXX"; // Too many bytes which look like incomplete chars!
- char chunk2[] =
- "r = 13;\n"
- " return foob\xec\x92\x81\x80\x80r;\n"
- "}\n";
- for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
+static bool access_was_called = false;
- const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
+
+static bool AccessAlwaysAllowedWithFlag(Local<v8::Object> global,
+ Local<Value> name, v8::AccessType type,
+ Local<Value> data) {
+ access_was_called = true;
+ return true;
}
-TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
- // Regression test: Stream data where there are several multi-byte UTF-8
- // characters in a sequence and one of them is split between two data chunks.
- const char* reference = "\xec\x92\x81";
- char chunk1[] =
- "function foo() {\n"
- " // This function will contain an UTF-8 character which is not in\n"
- " // ASCII.\n"
- " var foob\xec\x92\x81X";
- char chunk2[] =
- "XXr = 13;\n"
- " return foob\xec\x92\x81\xec\x92\x81r;\n"
- "}\n";
- chunk1[strlen(chunk1) - 1] = reference[0];
- chunk2[0] = reference[1];
- chunk2[1] = reference[2];
- const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+static bool AccessAlwaysBlockedWithFlag(Local<v8::Object> global,
+ Local<Value> name, v8::AccessType type,
+ Local<Value> data) {
+ access_was_called = true;
+ return false;
}
-TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
- // Another regression test, similar to the previous one. The difference is
- // that the split character is not the last one in the sequence.
- const char* reference = "\xec\x92\x81";
- char chunk1[] =
- "function foo() {\n"
- " // This function will contain an UTF-8 character which is not in\n"
- " // ASCII.\n"
- " var foobX";
- char chunk2[] =
- "XX\xec\x92\x81r = 13;\n"
- " return foob\xec\x92\x81\xec\x92\x81r;\n"
- "}\n";
- chunk1[strlen(chunk1) - 1] = reference[0];
- chunk2[0] = reference[1];
- chunk2[1] = reference[2];
- const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
-}
+TEST(StrongModeAccessCheckAllowed) {
+ i::FLAG_strong_mode = true;
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<Value> value;
+ access_was_called = false;
+ v8::Handle<v8::ObjectTemplate> obj_template =
+ v8::ObjectTemplate::New(isolate);
-TEST(StreamingWithHarmonyScopes) {
- // Don't use RunStreamingTest here so that both scripts get to use the same
- // LocalContext and HandleScope.
- LocalContext env;
- v8::Isolate* isolate = env->GetIsolate();
- v8::HandleScope scope(isolate);
+ obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
+ obj_template->SetAccessCheckCallbacks(AccessAlwaysAllowedWithFlag, NULL);
- // First, run a script with a let variable.
- CompileRun("\"use strict\"; let x = 1;");
+ // Create an environment
+ v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
+ context0->Enter();
+ v8::Handle<v8::Object> global0 = context0->Global();
+ global0->Set(v8_str("object"), obj_template->NewInstance());
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object.x");
+ CHECK(!try_catch.HasCaught());
+ CHECK(!access_was_called);
+ CHECK_EQ(42, value->Int32Value());
+ }
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object.foo");
+ CHECK(try_catch.HasCaught());
+ CHECK(!access_was_called);
+ }
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object[10]");
+ CHECK(try_catch.HasCaught());
+ CHECK(!access_was_called);
+ }
- // Then stream a script which (erroneously) tries to introduce the same
- // variable again.
- const char* chunks[] = {"\"use strict\"; let x = 2;", NULL};
+ // Create an environment
+ v8::Local<Context> context1 = Context::New(isolate);
+ context1->Enter();
+ v8::Handle<v8::Object> global1 = context1->Global();
+ global1->Set(v8_str("object"), obj_template->NewInstance());
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object.x");
+ CHECK(!try_catch.HasCaught());
+ CHECK(access_was_called);
+ CHECK_EQ(42, value->Int32Value());
+ }
+ access_was_called = false;
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object.foo");
+ CHECK(try_catch.HasCaught());
+ CHECK(access_was_called);
+ }
+ access_was_called = false;
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object[10]");
+ CHECK(try_catch.HasCaught());
+ CHECK(access_was_called);
+ }
- v8::TryCatch try_catch;
- v8::ScriptCompiler::StreamedSource source(
- new TestSourceStream(chunks),
- v8::ScriptCompiler::StreamedSource::ONE_BYTE);
- v8::ScriptCompiler::ScriptStreamingTask* task =
- v8::ScriptCompiler::StartStreamingScript(isolate, &source);
- task->Run();
- delete task;
+ context1->Exit();
+ context0->Exit();
+}
- // Parsing should succeed (the script will be parsed and compiled in a context
- // independent way, so the error is not detected).
- CHECK_EQ(false, try_catch.HasCaught());
- v8::ScriptOrigin origin(v8_str("http://foo.com"));
- char* full_source = TestSourceStream::FullSourceString(chunks);
- v8::Handle<Script> script = v8::ScriptCompiler::Compile(
- isolate, &source, v8_str(full_source), origin);
- CHECK(!script.IsEmpty());
- CHECK_EQ(false, try_catch.HasCaught());
+TEST(StrongModeAccessCheckBlocked) {
+ i::FLAG_strong_mode = true;
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<Value> value;
+ access_was_called = false;
- // Running the script exposes the error.
- v8::Handle<Value> result(script->Run());
- CHECK(result.IsEmpty());
- CHECK(try_catch.HasCaught());
- delete[] full_source;
-}
+ v8::Handle<v8::ObjectTemplate> obj_template =
+ v8::ObjectTemplate::New(isolate);
+ obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
+ obj_template->SetAccessCheckCallbacks(AccessAlwaysBlockedWithFlag, NULL);
-void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
- const char* garbage = "garbage garbage garbage garbage garbage garbage";
- const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
- int length = 16;
- v8::ScriptCompiler::CachedData* cached_data =
- new v8::ScriptCompiler::CachedData(data, length);
- DCHECK(!cached_data->rejected);
- v8::ScriptOrigin origin(v8_str("origin"));
- v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
- v8::Handle<v8::Script> script =
- v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
- CHECK(cached_data->rejected);
- CHECK_EQ(42, script->Run()->Int32Value());
+ // Create an environment
+ v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
+ context0->Enter();
+ v8::Handle<v8::Object> global0 = context0->Global();
+ global0->Set(v8_str("object"), obj_template->NewInstance());
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object.x");
+ CHECK(!try_catch.HasCaught());
+ CHECK(!access_was_called);
+ CHECK_EQ(42, value->Int32Value());
+ }
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object.foo");
+ CHECK(try_catch.HasCaught());
+ CHECK(!access_was_called);
+ }
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object[10]");
+ CHECK(try_catch.HasCaught());
+ CHECK(!access_was_called);
+ }
+
+ // Create an environment
+ v8::Local<Context> context1 = Context::New(isolate);
+ context1->Enter();
+ v8::Handle<v8::Object> global1 = context1->Global();
+ global1->Set(v8_str("object"), obj_template->NewInstance());
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object.x");
+ CHECK(try_catch.HasCaught());
+ CHECK(access_was_called);
+ }
+ access_was_called = false;
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object.foo");
+ CHECK(try_catch.HasCaught());
+ CHECK(access_was_called);
+ }
+ access_was_called = false;
+ {
+ v8::TryCatch try_catch(isolate);
+ value = CompileRun("'use strong'; object[10]");
+ CHECK(try_catch.HasCaught());
+ CHECK(access_was_called);
+ }
+
+ context1->Exit();
+ context0->Exit();
}
-TEST(InvalidCacheData) {
- v8::V8::Initialize();
- v8::HandleScope scope(CcTest::isolate());
- LocalContext context;
- TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
- TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
+TEST(StrongModeArityCallFromApi) {
+ i::FLAG_strong_mode = true;
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope scope(isolate);
+ Local<Function> fun;
+ {
+ v8::TryCatch try_catch(isolate);
+ fun = Local<Function>::Cast(CompileRun(
+ "function f(x) { 'use strong'; }"
+ "f"));
+
+ CHECK(!try_catch.HasCaught());
+ }
+
+ {
+ v8::TryCatch try_catch(isolate);
+ fun->Call(v8::Undefined(isolate), 0, nullptr);
+ CHECK(try_catch.HasCaught());
+ }
+
+ {
+ v8::TryCatch try_catch(isolate);
+ v8::Handle<Value> args[] = {v8_num(42)};
+ fun->Call(v8::Undefined(isolate), arraysize(args), args);
+ CHECK(!try_catch.HasCaught());
+ }
+
+ {
+ v8::TryCatch try_catch(isolate);
+ v8::Handle<Value> args[] = {v8_num(42), v8_num(555)};
+ fun->Call(v8::Undefined(isolate), arraysize(args), args);
+ CHECK(!try_catch.HasCaught());
+ }
}
-TEST(ParserCacheRejectedGracefully) {
- i::FLAG_min_preparse_length = 0;
- v8::V8::Initialize();
- v8::HandleScope scope(CcTest::isolate());
- LocalContext context;
- // Produce valid cached data.
- v8::ScriptOrigin origin(v8_str("origin"));
- v8::Local<v8::String> source_str = v8_str("function foo() {}");
- v8::ScriptCompiler::Source source(source_str, origin);
- v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
- CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
- CHECK(!script.IsEmpty());
- const v8::ScriptCompiler::CachedData* original_cached_data =
- source.GetCachedData();
- CHECK(original_cached_data != NULL);
- CHECK(original_cached_data->data != NULL);
- CHECK(!original_cached_data->rejected);
- CHECK_GT(original_cached_data->length, 0);
- // Recompiling the same script with it won't reject the data.
+TEST(StrongModeArityCallFromApi2) {
+ i::FLAG_strong_mode = true;
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope scope(isolate);
+ Local<Function> fun;
{
- v8::ScriptCompiler::Source source_with_cached_data(
- source_str, origin,
- new v8::ScriptCompiler::CachedData(original_cached_data->data,
- original_cached_data->length));
- v8::Handle<v8::Script> script =
- v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
- v8::ScriptCompiler::kConsumeParserCache);
- CHECK(!script.IsEmpty());
- const v8::ScriptCompiler::CachedData* new_cached_data =
- source_with_cached_data.GetCachedData();
- CHECK(new_cached_data != NULL);
- CHECK(!new_cached_data->rejected);
+ v8::TryCatch try_catch(isolate);
+ fun = Local<Function>::Cast(CompileRun(
+ "'use strong';"
+ "function f(x) {}"
+ "f"));
+
+ CHECK(!try_catch.HasCaught());
}
- // Compile an incompatible script with the cached data. The new script doesn't
- // have the same starting position for the function as the old one, so the old
- // cached data will be incompatible with it and will be rejected.
+
{
- v8::Local<v8::String> incompatible_source_str =
- v8_str(" function foo() {}");
- v8::ScriptCompiler::Source source_with_cached_data(
- incompatible_source_str, origin,
- new v8::ScriptCompiler::CachedData(original_cached_data->data,
- original_cached_data->length));
- v8::Handle<v8::Script> script =
- v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
- v8::ScriptCompiler::kConsumeParserCache);
- CHECK(!script.IsEmpty());
- const v8::ScriptCompiler::CachedData* new_cached_data =
- source_with_cached_data.GetCachedData();
- CHECK(new_cached_data != NULL);
- CHECK(new_cached_data->rejected);
+ v8::TryCatch try_catch(isolate);
+ fun->Call(v8::Undefined(isolate), 0, nullptr);
+ CHECK(try_catch.HasCaught());
}
-}
+ {
+ v8::TryCatch try_catch(isolate);
+ v8::Handle<Value> args[] = {v8_num(42)};
+ fun->Call(v8::Undefined(isolate), arraysize(args), args);
+ CHECK(!try_catch.HasCaught());
+ }
-TEST(StringConcatOverflow) {
- v8::V8::Initialize();
- v8::HandleScope scope(CcTest::isolate());
- RandomLengthOneByteResource* r =
- new RandomLengthOneByteResource(i::String::kMaxLength);
- v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
- CHECK(!str.IsEmpty());
- v8::TryCatch try_catch;
- v8::Local<v8::String> result = v8::String::Concat(str, str);
- CHECK(result.IsEmpty());
- CHECK(!try_catch.HasCaught());
+ {
+ v8::TryCatch try_catch(isolate);
+ v8::Handle<Value> args[] = {v8_num(42), v8_num(555)};
+ fun->Call(v8::Undefined(isolate), arraysize(args), args);
+ CHECK(!try_catch.HasCaught());
+ }
}
-TEST(TurboAsmDisablesNeuter) {
- v8::V8::Initialize();
- v8::HandleScope scope(CcTest::isolate());
- LocalContext context;
-#if V8_TURBOFAN_TARGET
- bool should_be_neuterable = !i::FLAG_turbo_asm;
-#else
- bool should_be_neuterable = true;
-#endif
- const char* load =
- "function Module(stdlib, foreign, heap) {"
- " 'use asm';"
- " var MEM32 = new stdlib.Int32Array(heap);"
- " function load() { return MEM32[0]; }"
- " return { load: load };"
- "}"
- "var buffer = new ArrayBuffer(4);"
- "Module(this, {}, buffer).load();"
- "buffer";
-
- v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
- CHECK_EQ(should_be_neuterable, result->IsNeuterable());
+TEST(StrongObjectDelete) {
+ i::FLAG_strong_mode = true;
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope scope(isolate);
+ Local<Object> obj;
+ {
+ v8::TryCatch try_catch;
+ obj = Local<Object>::Cast(CompileRun(
+ "'use strong';"
+ "({});"));
+ CHECK(!try_catch.HasCaught());
+ }
+ obj->ForceSet(v8_str("foo"), v8_num(1), v8::None);
+ obj->ForceSet(v8_str("2"), v8_num(1), v8::None);
+ CHECK(obj->HasOwnProperty(v8_str("foo")));
+ CHECK(obj->HasOwnProperty(v8_str("2")));
+ CHECK(!obj->Delete(v8_str("foo")));
+ CHECK(!obj->Delete(2));
+}
- const char* store =
- "function Module(stdlib, foreign, heap) {"
- " 'use asm';"
- " var MEM32 = new stdlib.Int32Array(heap);"
- " function store() { MEM32[0] = 0; }"
- " return { store: store };"
- "}"
- "var buffer = new ArrayBuffer(4);"
- "Module(this, {}, buffer).store();"
- "buffer";
- result = CompileRun(store).As<v8::ArrayBuffer>();
- CHECK_EQ(should_be_neuterable, result->IsNeuterable());
+static void ExtrasExportsTestRuntimeFunction(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ CHECK_EQ(3, args[0]->Int32Value());
+ args.GetReturnValue().Set(v8_num(7));
}
-TEST(GetPrototypeAccessControl) {
- i::FLAG_allow_natives_syntax = true;
+TEST(ExtrasExportsObject) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
- v8::Handle<v8::ObjectTemplate> obj_template =
- v8::ObjectTemplate::New(isolate);
- obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
- BlockEverythingIndexed);
+ // standalone.gypi ensures we include the test-extra.js file, which should
+ // export the tested functions.
+ v8::Local<v8::Object> exports = env->GetExtrasExportsObject();
- env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
+ auto func =
+ exports->Get(v8_str("testExtraShouldReturnFive")).As<v8::Function>();
+ auto undefined = v8::Undefined(isolate);
+ auto result = func->Call(undefined, 0, {}).As<v8::Number>();
+ CHECK_EQ(5, result->Int32Value());
- {
- v8::TryCatch try_catch;
- CompileRun(
- "function f() { %_GetPrototype(prohibited); }"
- "%OptimizeFunctionOnNextCall(f);"
- "f();");
- CHECK(try_catch.HasCaught());
- }
+ v8::Handle<v8::FunctionTemplate> runtimeFunction =
+ v8::FunctionTemplate::New(isolate, ExtrasExportsTestRuntimeFunction);
+ exports->Set(v8_str("runtime"), runtimeFunction->GetFunction());
+ func =
+ exports->Get(v8_str("testExtraShouldCallToRuntime")).As<v8::Function>();
+ result = func->Call(undefined, 0, {}).As<v8::Number>();
+ CHECK_EQ(7, result->Int32Value());
}
-TEST(GetPrototypeHidden) {
- i::FLAG_allow_natives_syntax = true;
+TEST(Map) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
- Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
- t->SetHiddenPrototype(true);
- Handle<Object> proto = t->GetFunction()->NewInstance();
- Handle<Object> object = Object::New(isolate);
- Handle<Object> proto2 = Object::New(isolate);
- object->SetPrototype(proto);
- proto->SetPrototype(proto2);
+ v8::Local<v8::Map> map = v8::Map::New(isolate);
+ CHECK(map->IsObject());
+ CHECK(map->IsMap());
+ CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype")));
+ CHECK_EQ(0U, map->Size());
- env->Global()->Set(v8_str("object"), object);
- env->Global()->Set(v8_str("proto"), proto);
- env->Global()->Set(v8_str("proto2"), proto2);
+ v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
+ CHECK(val->IsMap());
+ map = v8::Local<v8::Map>::Cast(val);
+ CHECK_EQ(2U, map->Size());
- v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
- CHECK(result->Equals(proto2));
+ v8::Local<v8::Array> contents = map->AsArray();
+ CHECK_EQ(4U, contents->Length());
+ CHECK_EQ(1, contents->Get(0).As<v8::Int32>()->Value());
+ CHECK_EQ(2, contents->Get(1).As<v8::Int32>()->Value());
+ CHECK_EQ(3, contents->Get(2).As<v8::Int32>()->Value());
+ CHECK_EQ(4, contents->Get(3).As<v8::Int32>()->Value());
- result = CompileRun(
- "function f() { return %_GetPrototype(object); }"
- "%OptimizeFunctionOnNextCall(f);"
- "f()");
- CHECK(result->Equals(proto2));
+ map = v8::Map::FromArray(env.local(), contents).ToLocalChecked();
+ CHECK_EQ(2U, map->Size());
+
+ CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
+ CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
+
+ CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
+ CHECK(!map->Has(env.local(), map).FromJust());
+
+ CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1))
+ .ToLocalChecked()
+ ->Int32Value());
+ CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3))
+ .ToLocalChecked()
+ ->Int32Value());
+
+ CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42))
+ .ToLocalChecked()
+ ->IsUndefined());
+
+ CHECK(!map->Set(env.local(), map, map).IsEmpty());
+ CHECK_EQ(3U, map->Size());
+ CHECK(map->Has(env.local(), map).FromJust());
+
+ CHECK(map->Delete(env.local(), map).FromJust());
+ CHECK_EQ(2U, map->Size());
+ CHECK(!map->Has(env.local(), map).FromJust());
+ CHECK(!map->Delete(env.local(), map).FromJust());
+
+ map->Clear();
+ CHECK_EQ(0U, map->Size());
}
-TEST(ClassPrototypeCreationContext) {
- i::FLAG_harmony_classes = true;
+TEST(MapFromArrayOddLength) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
-
- Handle<Object> result = Handle<Object>::Cast(
- CompileRun("'use strict'; class Example { }; Example.prototype"));
- CHECK(env.local() == result->CreationContext());
+ // Odd lengths result in a null MaybeLocal.
+ Local<v8::Array> contents = v8::Array::New(isolate, 41);
+ CHECK(v8::Map::FromArray(env.local(), contents).IsEmpty());
}
-TEST(SimpleStreamingScriptWithSourceURL) {
- const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
- "//# sourceURL=bar2.js\n", NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
- "bar2.js");
+TEST(Set) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handle_scope(isolate);
+ LocalContext env;
+
+ v8::Local<v8::Set> set = v8::Set::New(isolate);
+ CHECK(set->IsObject());
+ CHECK(set->IsSet());
+ CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype")));
+ CHECK_EQ(0U, set->Size());
+
+ v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
+ CHECK(val->IsSet());
+ set = v8::Local<v8::Set>::Cast(val);
+ CHECK_EQ(2U, set->Size());
+
+ v8::Local<v8::Array> keys = set->AsArray();
+ CHECK_EQ(2U, keys->Length());
+ CHECK_EQ(1, keys->Get(0).As<v8::Int32>()->Value());
+ CHECK_EQ(2, keys->Get(1).As<v8::Int32>()->Value());
+
+ set = v8::Set::FromArray(env.local(), keys).ToLocalChecked();
+ CHECK_EQ(2U, set->Size());
+
+ CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
+ CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
+
+ CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
+ CHECK(!set->Has(env.local(), set).FromJust());
+
+ CHECK(!set->Add(env.local(), set).IsEmpty());
+ CHECK_EQ(3U, set->Size());
+ CHECK(set->Has(env.local(), set).FromJust());
+
+ CHECK(set->Delete(env.local(), set).FromJust());
+ CHECK_EQ(2U, set->Size());
+ CHECK(!set->Has(env.local(), set).FromJust());
+ CHECK(!set->Delete(env.local(), set).FromJust());
+
+ set->Clear();
+ CHECK_EQ(0U, set->Size());
}
-TEST(StreamingScriptWithSplitSourceURL) {
- const char* chunks[] = {"function foo() { ret", "urn 13; } f",
- "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
- "bar2.js");
+TEST(CompatibleReceiverCheckOnCachedICHandler) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate);
+ v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent);
+ auto returns_42 =
+ v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature);
+ parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
+ v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
+ child->Inherit(parent);
+ LocalContext env;
+ env->Global()->Set(v8_str("Child"), child->GetFunction());
+
+ // Make sure there's a compiled stub for "Child.prototype.age" in the cache.
+ CompileRun(
+ "var real = new Child();\n"
+ "for (var i = 0; i < 3; ++i) {\n"
+ " real.age;\n"
+ "}\n");
+
+ // Check that the cached stub is never used.
+ ExpectInt32(
+ "var fake = Object.create(Child.prototype);\n"
+ "var result = 0;\n"
+ "function test(d) {\n"
+ " if (d == 3) return;\n"
+ " try {\n"
+ " fake.age;\n"
+ " result = 1;\n"
+ " } catch (e) {\n"
+ " }\n"
+ " test(d+1);\n"
+ "}\n"
+ "test(0);\n"
+ "result;\n",
+ 0);
}
-TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
- const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
- " sourceMappingURL=bar2.js\n", "foo();", NULL};
- RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
- "bar2.js");
+static int nb_uncaught_exception_callback_calls = 0;
+
+
+bool NoAbortOnUncaughtException(v8::Isolate* isolate) {
+ ++nb_uncaught_exception_callback_calls;
+ return false;
}
-TEST(NewStringRangeError) {
+TEST(AbortOnUncaughtExceptionNoAbort) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
- LocalContext env;
- const int length = i::String::kMaxLength + 1;
- const int buffer_size = length * sizeof(uint16_t);
- void* buffer = malloc(buffer_size);
- if (buffer == NULL) return;
- memset(buffer, 'A', buffer_size);
- {
- v8::TryCatch try_catch;
- char* data = reinterpret_cast<char*>(buffer);
- CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString,
- length).IsEmpty());
- CHECK(try_catch.HasCaught());
- }
- {
- v8::TryCatch try_catch;
- uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
- CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString,
- length).IsEmpty());
- CHECK(try_catch.HasCaught());
- }
- {
- v8::TryCatch try_catch;
- uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
- CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString,
- length).IsEmpty());
- CHECK(try_catch.HasCaught());
- }
- free(buffer);
+ v8::Handle<v8::ObjectTemplate> global_template =
+ v8::ObjectTemplate::New(isolate);
+ LocalContext env(NULL, global_template);
+
+ i::FLAG_abort_on_uncaught_exception = true;
+ isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException);
+
+ CompileRun("function boom() { throw new Error(\"boom\") }");
+
+ v8::Local<v8::Object> global_object = env->Global();
+ v8::Local<v8::Function> foo =
+ v8::Local<v8::Function>::Cast(global_object->Get(v8_str("boom")));
+
+ foo->Call(global_object, 0, NULL);
+
+ CHECK_EQ(1, nb_uncaught_exception_callback_calls);
}