v8/test/unittests/profiler/strings-storage-unittest.cc
Andrew Comminos 678afa3c04 [cpu-profiler] Fix string length calculation for GetConsName
Currently, GetConsName incorrectly includes the null terminator as part
of the length used in the string's hash. Exclude this to be consistent
with GetCopy, GetName, etc. and permit coalescing.

Bug: v8:0
Change-Id: I1e8a4eb7055637f3ed178014725b44e84d7788b6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2578192
Reviewed-by: Peter Marshall <petermarshall@chromium.org>
Commit-Queue: Andrew Comminos <acomminos@fb.com>
Cr-Commit-Position: refs/heads/master@{#71667}
2020-12-08 18:15:30 +00:00

174 lines
5.2 KiB
C++

// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/profiler/strings-storage.h"
#include <cstdio>
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace internal {
using StringsStorageWithIsolate = TestWithIsolate;
bool StringEq(const char* left, const char* right) {
return strcmp(left, right) == 0;
}
TEST_F(StringsStorageWithIsolate, GetNameFromString) {
StringsStorage storage;
// One char strings are canonical on the v8 heap so use a 2 char string here.
Handle<String> str = isolate()->factory()->NewStringFromAsciiChecked("xy");
const char* stored_str = storage.GetName(*str);
CHECK(StringEq("xy", stored_str));
// The storage should de-duplicate the underlying char arrays and return the
// exact same pointer for equivalent input strings.
const char* stored_str_twice = storage.GetName(*str);
CHECK_EQ(stored_str, stored_str_twice);
// Even if the input string was a different one on the v8 heap, if the char
// array is the same, it should be de-duplicated.
Handle<String> str2 = isolate()->factory()->NewStringFromAsciiChecked("xy");
CHECK_NE(*str, *str2);
const char* stored_str_thrice = storage.GetName(*str2);
CHECK_EQ(stored_str_twice, stored_str_thrice);
}
TEST_F(StringsStorageWithIsolate, GetNameFromSymbol) {
StringsStorage storage;
Handle<Symbol> symbol = isolate()->factory()->NewSymbol();
const char* stored_symbol = storage.GetName(*symbol);
CHECK(StringEq("<symbol>", stored_symbol));
Handle<Symbol> symbol2 = isolate()->factory()->NewSymbol();
CHECK_NE(*symbol, *symbol2);
const char* stored_symbol2 = storage.GetName(*symbol2);
CHECK_EQ(stored_symbol, stored_symbol2);
}
TEST_F(StringsStorageWithIsolate, GetConsName) {
StringsStorage storage;
Handle<String> str = isolate()->factory()->NewStringFromAsciiChecked("xy");
const char* empty_prefix_str = storage.GetConsName("", *str);
CHECK(StringEq("xy", empty_prefix_str));
const char* get_str = storage.GetConsName("get ", *str);
CHECK(StringEq("get xy", get_str));
}
TEST_F(StringsStorageWithIsolate, GetNameFromInt) {
StringsStorage storage;
const char* stored_str = storage.GetName(0);
CHECK(StringEq("0", stored_str));
stored_str = storage.GetName(2147483647);
CHECK(StringEq("2147483647", stored_str));
stored_str = storage.GetName(std::numeric_limits<int>::min());
char str_negative_int[12];
snprintf(str_negative_int, sizeof(str_negative_int), "%d",
std::numeric_limits<int>::min());
CHECK(StringEq(str_negative_int, stored_str));
}
TEST_F(StringsStorageWithIsolate, Format) {
StringsStorage storage;
const char* xy = "xy";
const char* stored_str = storage.GetFormatted("%s", xy);
CHECK(StringEq("xy", stored_str));
// Check that the string is copied.
CHECK_NE(xy, stored_str);
const char* formatted_str = storage.GetFormatted("%s / %s", xy, xy);
CHECK(StringEq("xy / xy", formatted_str));
// A different format specifier that results in the same string should share
// the string in storage.
const char* formatted_str2 = storage.GetFormatted("%s", "xy / xy");
CHECK_EQ(formatted_str, formatted_str2);
}
TEST_F(StringsStorageWithIsolate, FormatAndGetShareStorage) {
StringsStorage storage;
Handle<String> str = isolate()->factory()->NewStringFromAsciiChecked("xy");
const char* stored_str = storage.GetName(*str);
const char* formatted_str = storage.GetFormatted("%s", "xy");
CHECK_EQ(stored_str, formatted_str);
}
TEST_F(StringsStorageWithIsolate, Refcounting) {
StringsStorage storage;
const char* a = storage.GetCopy("12");
CHECK_EQ(storage.GetStringCountForTesting(), 1);
const char* b = storage.GetCopy("12");
CHECK_EQ(storage.GetStringCountForTesting(), 1);
// Ensure that we deduplicate the string.
CHECK_EQ(a, b);
CHECK(storage.Release(a));
CHECK_EQ(storage.GetStringCountForTesting(), 1);
CHECK(storage.Release(b));
CHECK_EQ(storage.GetStringCountForTesting(), 0);
#if !DEBUG
CHECK(!storage.Release("12"));
#endif // !DEBUG
// Verify that other constructors refcount as intended.
const char* c = storage.GetFormatted("%d", 12);
CHECK_EQ(storage.GetStringCountForTesting(), 1);
const char* d = storage.GetName(12);
CHECK_EQ(storage.GetStringCountForTesting(), 1);
CHECK_EQ(c, d);
CHECK(storage.Release(c));
CHECK_EQ(storage.GetStringCountForTesting(), 1);
CHECK(storage.Release(d));
CHECK_EQ(storage.GetStringCountForTesting(), 0);
#if !DEBUG
CHECK(!storage.Release("12"));
#endif // !DEBUG
}
TEST_F(StringsStorageWithIsolate, InvalidRelease) {
StringsStorage storage;
// If a refcount becomes invalid, throw in debug builds.
#ifdef DEBUG
ASSERT_DEATH_IF_SUPPORTED(storage.Release("12"), "check failed");
#else
CHECK(!storage.Release("12"));
#endif // DEBUG
}
TEST_F(StringsStorageWithIsolate, CopyAndConsShareStorage) {
StringsStorage storage;
Handle<String> str = isolate()->factory()->NewStringFromAsciiChecked("foo");
const char* copy_str = storage.GetCopy("get foo");
const char* cons_str = storage.GetConsName("get ", *str);
CHECK_EQ(storage.GetStringCountForTesting(), 1);
CHECK_EQ(copy_str, cons_str);
}
} // namespace internal
} // namespace v8