Merge V8 5.3.332.45. DO NOT MERGE
Test: Manual
FPIIM-449
Change-Id: Id3254828b068abdea3cb10442e0172a8c9a98e03
(cherry picked from commit 13e2dadd00298019ed862f2b2fc5068bba730bcf)
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index da72ecd..5624e3f 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -47,11 +47,12 @@
#include "src/futex-emulation.h"
#include "src/objects.h"
#include "src/parsing/parser.h"
+#include "src/profiler/cpu-profiler.h"
#include "src/unicode-inl.h"
#include "src/utils.h"
#include "src/vm-state.h"
#include "test/cctest/heap/heap-tester.h"
-#include "test/cctest/heap/utils-inl.h"
+#include "test/cctest/heap/heap-utils.h"
static const bool kLogThreading = false;
@@ -555,40 +556,19 @@
CcTest::heap()->CollectGarbage(i::NEW_SPACE);
uint16_t* two_byte_string = AsciiToTwoByteString("s1");
- Local<String> small_string =
+ Local<String> local_string =
String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
v8::NewStringType::kNormal)
.ToLocalChecked();
i::DeleteArray(two_byte_string);
- // We should refuse to externalize small strings.
- CHECK(!small_string->CanMakeExternal());
+ // We should refuse to externalize new space strings.
+ CHECK(!local_string->CanMakeExternal());
// Trigger GCs so that the newly allocated string moves to old gen.
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
// Old space strings should be accepted.
- CHECK(small_string->CanMakeExternal());
-
- two_byte_string = AsciiToTwoByteString("small string 2");
- small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
- v8::NewStringType::kNormal)
- .ToLocalChecked();
- i::DeleteArray(two_byte_string);
-
- const int buf_size = 10 * 1024;
- char* buf = i::NewArray<char>(buf_size);
- memset(buf, 'a', buf_size);
- buf[buf_size - 1] = '\0';
-
- two_byte_string = AsciiToTwoByteString(buf);
- Local<String> large_string =
- String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
- v8::NewStringType::kNormal)
- .ToLocalChecked();
- i::DeleteArray(buf);
- i::DeleteArray(two_byte_string);
- // Large strings should be immediately accepted.
- CHECK(large_string->CanMakeExternal());
+ CHECK(local_string->CanMakeExternal());
}
@@ -600,23 +580,14 @@
CcTest::heap()->CollectGarbage(i::NEW_SPACE);
CcTest::heap()->CollectGarbage(i::NEW_SPACE);
- Local<String> small_string = v8_str("s1");
- // We should refuse to externalize small strings.
- CHECK(!small_string->CanMakeExternal());
+ Local<String> local_string = v8_str("s1");
+ // We should refuse to externalize new space strings.
+ CHECK(!local_string->CanMakeExternal());
// Trigger GCs so that the newly allocated string moves to old gen.
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
// Old space strings should be accepted.
- CHECK(small_string->CanMakeExternal());
-
- const int buf_size = 10 * 1024;
- char* buf = i::NewArray<char>(buf_size);
- memset(buf, 'a', buf_size);
- buf[buf_size - 1] = '\0';
- Local<String> large_string = v8_str(buf);
- i::DeleteArray(buf);
- // Large strings should be immediately accepted.
- CHECK(large_string->CanMakeExternal());
+ CHECK(local_string->CanMakeExternal());
}
@@ -634,7 +605,7 @@
"slice('abcdefghijklmnopqrstuvwxyz');"));
// Trigger GCs so that the newly allocated string moves to old gen.
- SimulateFullSpace(CcTest::heap()->old_space());
+ i::heap::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
@@ -2827,16 +2798,15 @@
CHECK(env->Global()
->Set(env.local(), v8_str("global"), global_proxy)
.FromJust());
- i::Handle<i::Object> original_hash;
+ int32_t hash1;
if (set_in_js) {
CompileRun("var m = new Set(); m.add(global);");
- original_hash = i::Handle<i::Object>(i_global_proxy->GetHash(), i_isolate);
+ i::Object* original_hash = i_global_proxy->GetHash();
+ CHECK(original_hash->IsSmi());
+ hash1 = i::Smi::cast(original_hash)->value();
} else {
- original_hash = i::Handle<i::Object>(
- i::Object::GetOrCreateHash(i_isolate, i_global_proxy));
+ hash1 = i::Object::GetOrCreateHash(i_isolate, i_global_proxy)->value();
}
- 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();
@@ -13381,7 +13351,7 @@
value =
context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
CHECK(value->IsString() &&
- value->Equals(context.local(), v8_str("[object global]")).FromJust());
+ value->Equals(context.local(), v8_str("[object Object]")).FromJust());
// Check ordinary object
Local<Value> object =
@@ -13427,7 +13397,7 @@
value =
context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
CHECK(value->IsString() &&
- value->Equals(context.local(), v8_str("[object global]")).FromJust());
+ value->Equals(context.local(), v8_str("[object Object]")).FromJust());
// Check ordinary object
Local<Value> object = CompileRun("new Object()");
@@ -14610,9 +14580,8 @@
test.RunTest();
}
-
-static i::HashMap* code_map = NULL;
-static i::HashMap* jitcode_line_info = NULL;
+static v8::base::HashMap* code_map = NULL;
+static v8::base::HashMap* jitcode_line_info = NULL;
static int saw_bar = 0;
static int move_events = 0;
@@ -14672,7 +14641,7 @@
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->LookupOrInsert(
+ v8::base::HashMap::Entry* entry = code_map->LookupOrInsert(
event->code_start, i::ComputePointerHash(event->code_start));
entry->value = reinterpret_cast<void*>(event->code_len);
@@ -14691,7 +14660,8 @@
// 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);
+ v8::base::HashMap::Entry* entry =
+ code_map->Lookup(event->code_start, hash);
if (entry != NULL) {
++move_events;
@@ -14718,7 +14688,7 @@
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->LookupOrInsert(
+ v8::base::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert(
line_info, i::ComputePointerHash(line_info));
entry->value = reinterpret_cast<void*>(line_info);
}
@@ -14729,7 +14699,7 @@
case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
CHECK(event->user_data != NULL);
uint32_t hash = i::ComputePointerHash(event->user_data);
- i::HashMap::Entry* entry =
+ v8::base::HashMap::Entry* entry =
jitcode_line_info->Lookup(event->user_data, hash);
CHECK(entry != NULL);
delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
@@ -14739,7 +14709,7 @@
case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
CHECK(event->user_data != NULL);
uint32_t hash = i::ComputePointerHash(event->user_data);
- i::HashMap::Entry* entry =
+ v8::base::HashMap::Entry* entry =
jitcode_line_info->Lookup(event->user_data, hash);
CHECK(entry != NULL);
}
@@ -14781,10 +14751,10 @@
{
v8::HandleScope scope(isolate);
- i::HashMap code(MatchPointers);
+ v8::base::HashMap code(MatchPointers);
code_map = &code;
- i::HashMap lineinfo(MatchPointers);
+ v8::base::HashMap lineinfo(MatchPointers);
jitcode_line_info = &lineinfo;
saw_bar = 0;
@@ -14798,8 +14768,8 @@
for (int i = 0; i < kIterations; ++i) {
LocalContext env(isolate);
i::AlwaysAllocateScope always_allocate(i_isolate);
- SimulateFullSpace(i::FLAG_ignition ? heap->old_space()
- : heap->code_space());
+ i::heap::SimulateFullSpace(i::FLAG_ignition ? heap->old_space()
+ : heap->code_space());
CompileRun(script);
// Keep a strong reference to the code object in the handle scope.
@@ -14847,10 +14817,10 @@
CompileRun(script);
// Now get code through initial iteration.
- i::HashMap code(MatchPointers);
+ v8::base::HashMap code(MatchPointers);
code_map = &code;
- i::HashMap lineinfo(MatchPointers);
+ v8::base::HashMap lineinfo(MatchPointers);
jitcode_line_info = &lineinfo;
isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
@@ -14883,8 +14853,7 @@
isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
CHECK_EQ(baseline,
isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
- const int64_t kTriggerGCSize =
- v8::internal::Internals::kExternalAllocationLimit + 1;
+ const int64_t kTriggerGCSize = i::kExternalAllocationLimit + 1;
CHECK_EQ(baseline + kTriggerGCSize,
isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
CHECK_EQ(baseline,
@@ -14896,8 +14865,7 @@
i::FLAG_incremental_marking = false;
CcTest::InitializeVM();
- const int64_t kTriggerGCSize =
- v8::internal::Internals::kExternalAllocationLimit + 1;
+ const int64_t kTriggerGCSize = i::kExternalAllocationLimit + 1;
v8::Isolate* isolate = CcTest::isolate();
isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize);
}
@@ -15072,18 +15040,39 @@
CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
}
+void CheckIsSymbolAt(v8::Isolate* isolate, v8::Local<v8::Array> properties,
+ unsigned index, const char* name) {
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Value> value =
+ properties->Get(context, v8::Integer::New(isolate, index))
+ .ToLocalChecked();
+ CHECK(value->IsSymbol());
+ v8::String::Utf8Value symbol_name(Local<Symbol>::Cast(value)->Name());
+ CHECK_EQ(0, strcmp(name, *symbol_name));
+}
+
+void CheckStringArray(v8::Isolate* isolate, v8::Local<v8::Array> properties,
+ unsigned length, const char* names[]) {
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ CHECK_EQ(length, properties->Length());
+ for (unsigned i = 0; i < length; i++) {
+ v8::Local<v8::Value> value =
+ properties->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked();
+ if (names[i] == nullptr) {
+ DCHECK(value->IsSymbol());
+ } else {
+ v8::String::Utf8Value elm(value);
+ CHECK_EQ(0, strcmp(names[i], *elm));
+ }
+ }
+}
void CheckProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
- unsigned elmc, const char* elmv[]) {
+ unsigned length, const char* names[]) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Object> obj = val.As<v8::Object>();
v8::Local<v8::Array> props = obj->GetPropertyNames(context).ToLocalChecked();
- CHECK_EQ(elmc, props->Length());
- for (unsigned i = 0; i < elmc; i++) {
- v8::String::Utf8Value elm(
- props->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked());
- CHECK_EQ(0, strcmp(elmv[i], *elm));
- }
+ CheckStringArray(isolate, props, length, names);
}
@@ -15194,6 +15183,97 @@
}
}
+THREADED_TEST(PropertyNames) {
+ LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
+ v8::HandleScope scope(isolate);
+ v8::Local<v8::Value> result = CompileRun(
+ "var result = {0: 0, 1: 1, a: 2, b: 3};"
+ "result[Symbol('symbol')] = true;"
+ "result.__proto__ = {2: 4, 3: 5, c: 6, d: 7};"
+ "result;");
+ v8::Local<v8::Object> object = result.As<v8::Object>();
+ v8::PropertyFilter default_filter =
+ static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS);
+ v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE;
+
+ v8::Local<v8::Array> properties =
+ object->GetPropertyNames(context.local()).ToLocalChecked();
+ const char* expected_properties1[] = {"0", "1", "a", "b", "2", "3", "c", "d"};
+ CheckStringArray(isolate, properties, 8, expected_properties1);
+
+ properties =
+ object
+ ->GetPropertyNames(context.local(),
+ v8::KeyCollectionMode::kIncludePrototypes,
+ default_filter, v8::IndexFilter::kIncludeIndices)
+ .ToLocalChecked();
+ CheckStringArray(isolate, properties, 8, expected_properties1);
+
+ properties = object
+ ->GetPropertyNames(context.local(),
+ v8::KeyCollectionMode::kIncludePrototypes,
+ include_symbols_filter,
+ v8::IndexFilter::kIncludeIndices)
+ .ToLocalChecked();
+ const char* expected_properties1_1[] = {"0", "1", "a", "b", nullptr,
+ "2", "3", "c", "d"};
+ CheckStringArray(isolate, properties, 9, expected_properties1_1);
+ CheckIsSymbolAt(isolate, properties, 4, "symbol");
+
+ properties =
+ object
+ ->GetPropertyNames(context.local(),
+ v8::KeyCollectionMode::kIncludePrototypes,
+ default_filter, v8::IndexFilter::kSkipIndices)
+ .ToLocalChecked();
+ const char* expected_properties2[] = {"a", "b", "c", "d"};
+ CheckStringArray(isolate, properties, 4, expected_properties2);
+
+ properties = object
+ ->GetPropertyNames(context.local(),
+ v8::KeyCollectionMode::kIncludePrototypes,
+ include_symbols_filter,
+ v8::IndexFilter::kSkipIndices)
+ .ToLocalChecked();
+ const char* expected_properties2_1[] = {"a", "b", nullptr, "c", "d"};
+ CheckStringArray(isolate, properties, 5, expected_properties2_1);
+ CheckIsSymbolAt(isolate, properties, 2, "symbol");
+
+ properties =
+ object
+ ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
+ default_filter, v8::IndexFilter::kIncludeIndices)
+ .ToLocalChecked();
+ const char* expected_properties3[] = {"0", "1", "a", "b"};
+ CheckStringArray(isolate, properties, 4, expected_properties3);
+
+ properties = object
+ ->GetPropertyNames(
+ context.local(), v8::KeyCollectionMode::kOwnOnly,
+ include_symbols_filter, v8::IndexFilter::kIncludeIndices)
+ .ToLocalChecked();
+ const char* expected_properties3_1[] = {"0", "1", "a", "b", nullptr};
+ CheckStringArray(isolate, properties, 5, expected_properties3_1);
+ CheckIsSymbolAt(isolate, properties, 4, "symbol");
+
+ properties =
+ object
+ ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
+ default_filter, v8::IndexFilter::kSkipIndices)
+ .ToLocalChecked();
+ const char* expected_properties4[] = {"a", "b"};
+ CheckStringArray(isolate, properties, 2, expected_properties4);
+
+ properties = object
+ ->GetPropertyNames(
+ context.local(), v8::KeyCollectionMode::kOwnOnly,
+ include_symbols_filter, v8::IndexFilter::kSkipIndices)
+ .ToLocalChecked();
+ const char* expected_properties4_1[] = {"a", "b", nullptr};
+ CheckStringArray(isolate, properties, 3, expected_properties4_1);
+ CheckIsSymbolAt(isolate, properties, 2, "symbol");
+}
THREADED_TEST(AccessChecksReenabledCorrectly) {
LocalContext context;
@@ -18462,7 +18542,6 @@
THREADED_TEST(FunctionGetDebugName) {
- i::FLAG_harmony_function_name = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
const char* code =
@@ -19001,7 +19080,7 @@
++prologue_call_count_alloc;
// Simulate full heap to see if we will reenter this callback
- SimulateFullSpace(CcTest::heap()->new_space());
+ i::heap::SimulateFullSpace(CcTest::heap()->new_space());
Local<Object> obj = Object::New(isolate);
CHECK(!obj.IsEmpty());
@@ -19021,7 +19100,7 @@
++epilogue_call_count_alloc;
// Simulate full heap to see if we will reenter this callback
- SimulateFullSpace(CcTest::heap()->new_space());
+ i::heap::SimulateFullSpace(CcTest::heap()->new_space());
Local<Object> obj = Object::New(isolate);
CHECK(!obj.IsEmpty());
@@ -19997,7 +20076,6 @@
TEST(RegExp) {
- i::FLAG_harmony_unicode_regexps = true;
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
@@ -21375,14 +21453,17 @@
env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
}
-
#ifdef ENABLE_DISASSEMBLER
-static int probes_counter = 0;
-static int misses_counter = 0;
-static int updates_counter = 0;
+// FLAG_test_primary_stub_cache and FLAG_test_secondary_stub_cache are read
+// only when ENABLE_DISASSEMBLER is not defined.
+namespace {
-static int* LookupCounter(const char* name) {
+int probes_counter = 0;
+int misses_counter = 0;
+int updates_counter = 0;
+
+int* LookupCounter(const char* name) {
if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
return &probes_counter;
} else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
@@ -21393,24 +21474,28 @@
return NULL;
}
+const char* kMegamorphicTestProgram =
+ "function CreateClass(name) {\n"
+ " var src = \n"
+ " ` function ${name}() {};` +\n"
+ " ` ${name}.prototype.foo = function() {};` +\n"
+ " ` ${name};\\n`;\n"
+ " return (0, eval)(src);\n"
+ "}\n"
+ "function fooify(obj) { obj.foo(); };\n"
+ "var objs = [];\n"
+ "for (var i = 0; i < 6; i++) {\n"
+ " var Class = CreateClass('Class' + i);\n"
+ " var obj = new Class();\n"
+ " objs.push(obj);\n"
+ "}\n"
+ "for (var i = 0; i < 10000; i++) {\n"
+ " for (var obj of objs) {\n"
+ " fooify(obj);\n"
+ " }\n"
+ "}\n";
-static const char* kMegamorphicTestProgram =
- "function ClassA() { };"
- "function ClassB() { };"
- "ClassA.prototype.foo = function() { };"
- "ClassB.prototype.foo = function() { };"
- "function fooify(obj) { obj.foo(); };"
- "var a = new ClassA();"
- "var b = new ClassB();"
- "for (var i = 0; i < 10000; i++) {"
- " fooify(a);"
- " fooify(b);"
- "}";
-#endif
-
-
-static void StubCacheHelper(bool primary) {
-#ifdef ENABLE_DISASSEMBLER
+void StubCacheHelper(bool primary) {
i::FLAG_native_code_counters = true;
if (primary) {
i::FLAG_test_primary_stub_cache = true;
@@ -21418,36 +21503,47 @@
i::FLAG_test_secondary_stub_cache = true;
}
i::FLAG_crankshaft = false;
- LocalContext env;
- env->GetIsolate()->SetCounterFunction(LookupCounter);
- v8::HandleScope scope(env->GetIsolate());
- int initial_probes = probes_counter;
- int initial_misses = misses_counter;
- int initial_updates = updates_counter;
- CompileRun(kMegamorphicTestProgram);
- int probes = probes_counter - initial_probes;
- int misses = misses_counter - initial_misses;
- int updates = updates_counter - initial_updates;
- CHECK_LT(updates, 10);
- CHECK_LT(misses, 10);
- // TODO(verwaest): Update this test to overflow the degree of polymorphism
- // before megamorphism. The number of probes will only work once we teach the
- // serializer to embed references to counters in the stubs, given that the
- // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
- CHECK_GE(probes, 0);
-#endif
+ i::FLAG_turbo = false;
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ create_params.counter_lookup_callback = LookupCounter;
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+
+ if (!i_isolate->snapshot_available()) {
+ // The test is valid only for no-snapshot mode.
+ v8::Isolate::Scope isolate_scope(isolate);
+ LocalContext env(isolate);
+ v8::HandleScope scope(isolate);
+
+ int initial_probes = probes_counter;
+ int initial_misses = misses_counter;
+ int initial_updates = updates_counter;
+ CompileRun(kMegamorphicTestProgram);
+ int probes = probes_counter - initial_probes;
+ int misses = misses_counter - initial_misses;
+ int updates = updates_counter - initial_updates;
+ const int kClassesCount = 6;
+ // Check that updates and misses counts are bounded.
+ CHECK_LE(kClassesCount, updates);
+ CHECK_LT(updates, kClassesCount * 3);
+ CHECK_LE(1, misses);
+ CHECK_LT(misses, kClassesCount * 2);
+ // 2 is for PREMONOMORPHIC and MONOMORPHIC states,
+ // 4 is for POLYMORPHIC states,
+ // and all the others probes are for MEGAMORPHIC state.
+ CHECK_EQ(10000 * kClassesCount - 2 - 4, probes);
+ }
+ isolate->Dispose();
}
+} // namespace
-TEST(SecondaryStubCache) {
- StubCacheHelper(true);
-}
+UNINITIALIZED_TEST(PrimaryStubCache) { StubCacheHelper(true); }
+UNINITIALIZED_TEST(SecondaryStubCache) { StubCacheHelper(false); }
-TEST(PrimaryStubCache) {
- StubCacheHelper(false);
-}
-
+#endif // ENABLE_DISASSEMBLER
#ifdef DEBUG
static int cow_arrays_created_runtime = 0;
@@ -22053,6 +22149,20 @@
ExpectString("JSON.stringify(obj)", *utf8);
}
+THREADED_TEST(JSONStringifyObjectWithGap) {
+ LocalContext context;
+ HandleScope scope(context->GetIsolate());
+ Local<Value> value =
+ v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
+ Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
+ Local<Object> global = context->Global();
+ global->Set(context.local(), v8_str("obj"), obj).FromJust();
+ Local<String> json =
+ v8::JSON::Stringify(context.local(), obj, v8_str("*")).ToLocalChecked();
+ v8::String::Utf8Value utf8(json);
+ ExpectString("JSON.stringify(obj, null, '*')", *utf8);
+}
+
#if V8_OS_POSIX && !V8_OS_NACL
class ThreadInterruptTest {
public:
@@ -23413,6 +23523,88 @@
CHECK_EQ(13, line_number);
}
+TEST(ScriptPositionInfo) {
+ 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;\n"
+ "var bar;\n"
+ "var fisk = foo + bar;\n"),
+ origin);
+ Local<Script> script =
+ v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
+
+ i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
+ v8::Utils::OpenHandle(*script->GetUnboundScript()));
+ CHECK(obj->script()->IsScript());
+
+ i::Handle<i::Script> script1(i::Script::cast(obj->script()));
+
+ v8::internal::Script::PositionInfo info;
+
+ // With offset.
+
+ // Behave as if 0 was passed if position is negative.
+ CHECK(script1->GetPositionInfo(-1, &info, script1->WITH_OFFSET));
+ CHECK_EQ(13, info.line);
+ CHECK_EQ(0, info.column);
+ CHECK_EQ(0, info.line_start);
+ CHECK_EQ(8, info.line_end);
+
+ CHECK(script1->GetPositionInfo(0, &info, script1->WITH_OFFSET));
+ CHECK_EQ(13, info.line);
+ CHECK_EQ(0, info.column);
+ CHECK_EQ(0, info.line_start);
+ CHECK_EQ(8, info.line_end);
+
+ CHECK(script1->GetPositionInfo(8, &info, script1->WITH_OFFSET));
+ CHECK_EQ(13, info.line);
+ CHECK_EQ(8, info.column);
+ CHECK_EQ(0, info.line_start);
+ CHECK_EQ(8, info.line_end);
+
+ CHECK(script1->GetPositionInfo(9, &info, script1->WITH_OFFSET));
+ CHECK_EQ(14, info.line);
+ CHECK_EQ(0, info.column);
+ CHECK_EQ(9, info.line_start);
+ CHECK_EQ(17, info.line_end);
+
+ // Fail when position is larger than script size.
+ CHECK(!script1->GetPositionInfo(220384, &info, script1->WITH_OFFSET));
+
+ // Without offset.
+
+ // Behave as if 0 was passed if position is negative.
+ CHECK(script1->GetPositionInfo(-1, &info, script1->NO_OFFSET));
+ CHECK_EQ(0, info.line);
+ CHECK_EQ(0, info.column);
+ CHECK_EQ(0, info.line_start);
+ CHECK_EQ(8, info.line_end);
+
+ CHECK(script1->GetPositionInfo(0, &info, script1->NO_OFFSET));
+ CHECK_EQ(0, info.line);
+ CHECK_EQ(0, info.column);
+ CHECK_EQ(0, info.line_start);
+ CHECK_EQ(8, info.line_end);
+
+ CHECK(script1->GetPositionInfo(8, &info, script1->NO_OFFSET));
+ CHECK_EQ(0, info.line);
+ CHECK_EQ(8, info.column);
+ CHECK_EQ(0, info.line_start);
+ CHECK_EQ(8, info.line_end);
+
+ CHECK(script1->GetPositionInfo(9, &info, script1->NO_OFFSET));
+ CHECK_EQ(1, info.line);
+ CHECK_EQ(0, info.column);
+ CHECK_EQ(9, info.line_start);
+ CHECK_EQ(17, info.line_end);
+
+ // Fail when position is larger than script size.
+ CHECK(!script1->GetPositionInfo(220384, &info, script1->NO_OFFSET));
+}
+
void CheckMagicComments(Local<Script> script, const char* expected_source_url,
const char* expected_source_mapping_url) {
if (expected_source_url != NULL) {