Commit ef734e26 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Verify that source string matches serialized code.

R=mvstanton@chromium.org, vogelheim@chromium.org

Review URL: https://codereview.chromium.org/394793002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22417 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 3150bf38
......@@ -28,7 +28,8 @@ enum PerIsolateAssertType {
JAVASCRIPT_EXECUTION_ASSERT,
JAVASCRIPT_EXECUTION_THROWS,
ALLOCATION_FAILURE_ASSERT,
DEOPTIMIZATION_ASSERT
DEOPTIMIZATION_ASSERT,
COMPILATION_ASSERT
};
......@@ -254,6 +255,13 @@ typedef PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, false>
typedef PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, true>
AllowDeoptimization;
// Scope to document where we do not expect deoptimization.
typedef PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, false>
DisallowCompilation;
// Scope to introduce an exception to DisallowDeoptimization.
typedef PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, true>
AllowCompilation;
} } // namespace v8::internal
#endif // V8_ASSERT_SCOPE_H_
......@@ -631,6 +631,7 @@ static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
static bool CompileUnoptimizedCode(CompilationInfo* info) {
ASSERT(AllowCompilation::IsAllowed(info->isolate()));
ASSERT(info->function() != NULL);
if (!Rewriter::Rewrite(info)) return false;
if (!Scope::Analyze(info)) return false;
......@@ -1196,6 +1197,7 @@ MaybeHandle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function,
SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(function));
Isolate* isolate = info->isolate();
ASSERT(AllowCompilation::IsAllowed(isolate));
VMState<COMPILER> state(isolate);
ASSERT(!isolate->has_pending_exception());
PostponeInterruptsScope postpone(isolate);
......
......@@ -6562,6 +6562,35 @@ uint32_t StringHasher::HashSequentialString(const schar* chars,
}
uint32_t IteratingStringHasher::Hash(String* string, uint32_t seed) {
IteratingStringHasher hasher(string->length(), seed);
// Nothing to do.
if (hasher.has_trivial_hash()) return hasher.GetHashField();
ConsString* cons_string = String::VisitFlat(&hasher, string);
// The string was flat.
if (cons_string == NULL) return hasher.GetHashField();
// This is a ConsString, iterate across it.
ConsStringIteratorOp op(cons_string);
int offset;
while (NULL != (string = op.Next(&offset))) {
String::VisitFlat(&hasher, string, offset);
}
return hasher.GetHashField();
}
void IteratingStringHasher::VisitOneByteString(const uint8_t* chars,
int length) {
AddCharacters(chars, length);
}
void IteratingStringHasher::VisitTwoByteString(const uint16_t* chars,
int length) {
AddCharacters(chars, length);
}
bool Name::AsArrayIndex(uint32_t* index) {
return IsString() && String::cast(this)->AsArrayIndex(index);
}
......
......@@ -9332,38 +9332,6 @@ bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
}
class IteratingStringHasher: public StringHasher {
public:
static inline uint32_t Hash(String* string, uint32_t seed) {
IteratingStringHasher hasher(string->length(), seed);
// Nothing to do.
if (hasher.has_trivial_hash()) return hasher.GetHashField();
ConsString* cons_string = String::VisitFlat(&hasher, string);
// The string was flat.
if (cons_string == NULL) return hasher.GetHashField();
// This is a ConsString, iterate across it.
ConsStringIteratorOp op(cons_string);
int offset;
while (NULL != (string = op.Next(&offset))) {
String::VisitFlat(&hasher, string, offset);
}
return hasher.GetHashField();
}
inline void VisitOneByteString(const uint8_t* chars, int length) {
AddCharacters(chars, length);
}
inline void VisitTwoByteString(const uint16_t* chars, int length) {
AddCharacters(chars, length);
}
private:
inline IteratingStringHasher(int len, uint32_t seed)
: StringHasher(len, seed) {
}
DISALLOW_COPY_AND_ASSIGN(IteratingStringHasher);
};
uint32_t String::ComputeAndSetHash() {
// Should only be called if hash code has not yet been computed.
ASSERT(!HasHashCode());
......
......@@ -8854,6 +8854,19 @@ class StringHasher {
};
class IteratingStringHasher : public StringHasher {
public:
static inline uint32_t Hash(String* string, uint32_t seed);
inline void VisitOneByteString(const uint8_t* chars, int length);
inline void VisitTwoByteString(const uint16_t* chars, int length);
private:
inline IteratingStringHasher(int len, uint32_t seed)
: StringHasher(len, seed) {}
DISALLOW_COPY_AND_ASSIGN(IteratingStringHasher);
};
// The characteristics of a string are stored in its map. Retrieving these
// few bits of information is moderately expensive, involving two memory
// loads where the second is dependent on the first. To improve efficiency
......
......@@ -13,6 +13,7 @@
#include "src/global-handles.h"
#include "src/ic-inl.h"
#include "src/natives.h"
#include "src/objects.h"
#include "src/runtime.h"
#include "src/serialize.h"
#include "src/snapshot.h"
......@@ -1993,7 +1994,7 @@ void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
Handle<SharedFunctionInfo> CodeSerializer::Deserialize(Isolate* isolate,
ScriptData* data,
Handle<String> source) {
SerializedCodeData scd(data);
SerializedCodeData scd(data, *source);
SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
Deserializer deserializer(&payload);
STATIC_ASSERT(NEW_SPACE == 0);
......@@ -2017,6 +2018,7 @@ Handle<SharedFunctionInfo> CodeSerializer::Deserialize(Isolate* isolate,
SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
: owns_script_data_(true) {
DisallowHeapAllocation no_gc;
int data_length = payload->length() + kHeaderEntries * kIntSize;
byte* data = NewArray<byte>(data_length);
ASSERT(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
......@@ -2024,7 +2026,7 @@ SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
static_cast<size_t>(payload->length()));
script_data_ = new ScriptData(data, data_length);
script_data_->AcquireDataOwnership();
SetHeaderValue(kVersionHashOffset, Version::Hash());
SetHeaderValue(kCheckSumOffset, CheckSum(cs->source()));
STATIC_ASSERT(NEW_SPACE == 0);
for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i));
......@@ -2032,8 +2034,18 @@ SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
}
bool SerializedCodeData::IsSane() {
return GetHeaderValue(kVersionHashOffset) == Version::Hash() &&
bool SerializedCodeData::IsSane(String* source) {
return GetHeaderValue(kCheckSumOffset) == CheckSum(source) &&
PayloadLength() >= SharedFunctionInfo::kSize;
}
int SerializedCodeData::CheckSum(String* string) {
int checksum = Version::Hash();
#ifdef DEBUG
uint32_t seed = static_cast<uint32_t>(checksum);
checksum = static_cast<int>(IteratingStringHasher::Hash(string, seed));
#endif // DEBUG
return checksum;
}
} } // namespace v8::internal
......@@ -590,6 +590,11 @@ class CodeSerializer : public Serializer {
static const int kSourceObjectIndex = 0;
String* source() {
ASSERT(!AllowHeapAllocation::IsAllowed());
return source_;
}
private:
void SerializeBuiltin(Code* builtin, HowToCode how_to_code,
WhereToPoint where_to_point, int skip);
......@@ -606,9 +611,10 @@ class CodeSerializer : public Serializer {
class SerializedCodeData {
public:
// Used by when consuming.
explicit SerializedCodeData(ScriptData* data)
explicit SerializedCodeData(ScriptData* data, String* source)
: script_data_(data), owns_script_data_(false) {
CHECK(IsSane());
DisallowHeapAllocation no_gc;
CHECK(IsSane(source));
}
// Used when producing.
......@@ -649,12 +655,14 @@ class SerializedCodeData {
return reinterpret_cast<const int*>(script_data_->data())[offset];
}
bool IsSane();
bool IsSane(String* source);
int CheckSum(String* source);
// The data header consists of int-sized entries:
// [0] version hash
// [1..7] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
static const int kVersionHashOffset = 0;
static const int kCheckSumOffset = 0;
static const int kReservationsOffset = 1;
static const int kHeaderEntries = 8;
......
......@@ -32,6 +32,7 @@
#include "src/v8.h"
#include "src/bootstrapper.h"
#include "src/compilation-cache.h"
#include "src/debug.h"
#include "src/ic-inl.h"
#include "src/natives.h"
......@@ -678,36 +679,41 @@ int CountBuiltins() {
TEST(SerializeToplevelOnePlusOne) {
FLAG_serialize_toplevel = true;
LocalContext context;
v8::HandleScope scope(CcTest::isolate());
Isolate* isolate = CcTest::i_isolate();
isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
const char* source1 = "1 + 1";
const char* source2 = "1 + 2"; // Use alternate string to verify caching.
v8::HandleScope scope(CcTest::isolate());
Isolate* isolate = CcTest::i_isolate();
Handle<String> source1_string = isolate->factory()
->NewStringFromUtf8(CStrVector(source1))
.ToHandleChecked();
const char* source = "1 + 1";
Handle<String> source2_string = isolate->factory()
->NewStringFromUtf8(CStrVector(source2))
.ToHandleChecked();
Handle<String> orig_source = isolate->factory()
->NewStringFromUtf8(CStrVector(source))
.ToHandleChecked();
Handle<String> copy_source = isolate->factory()
->NewStringFromUtf8(CStrVector(source))
.ToHandleChecked();
CHECK(!orig_source.is_identical_to(copy_source));
CHECK(orig_source->Equals(*copy_source));
ScriptData* cache = NULL;
Handle<SharedFunctionInfo> orig =
Compiler::CompileScript(source1_string, Handle<String>(), 0, 0, false,
Compiler::CompileScript(orig_source, Handle<String>(), 0, 0, false,
Handle<Context>(isolate->native_context()), NULL,
&cache, PRODUCE_CACHED_DATA, NOT_NATIVES_CODE);
int builtins_count = CountBuiltins();
Handle<SharedFunctionInfo> copy =
Compiler::CompileScript(source2_string, Handle<String>(), 0, 0, false,
Handle<Context>(isolate->native_context()), NULL,
&cache, CONSUME_CACHED_DATA, NOT_NATIVES_CODE);
Handle<SharedFunctionInfo> copy;
{
DisallowCompilation no_compile_expected(isolate);
copy = Compiler::CompileScript(copy_source, Handle<String>(), 0, 0, false,
Handle<Context>(isolate->native_context()),
NULL, &cache, CONSUME_CACHED_DATA,
NOT_NATIVES_CODE);
}
CHECK_NE(*orig, *copy);
CHECK(Script::cast(copy->script())->source() == *source2_string);
CHECK(Script::cast(copy->script())->source() == *copy_source);
Handle<JSFunction> copy_fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
......@@ -726,24 +732,27 @@ TEST(SerializeToplevelOnePlusOne) {
TEST(SerializeToplevelInternalizedString) {
FLAG_serialize_toplevel = true;
LocalContext context;
Isolate* isolate = CcTest::i_isolate();
isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
v8::HandleScope scope(CcTest::isolate());
const char* source1 = "'string1'";
const char* source2 = "'string2'"; // Use alternate string to verify caching.
const char* source = "'string1'";
Isolate* isolate = CcTest::i_isolate();
Handle<String> source1_string = isolate->factory()
->NewStringFromUtf8(CStrVector(source1))
.ToHandleChecked();
Handle<String> orig_source = isolate->factory()
->NewStringFromUtf8(CStrVector(source))
.ToHandleChecked();
Handle<String> copy_source = isolate->factory()
->NewStringFromUtf8(CStrVector(source))
.ToHandleChecked();
CHECK(!orig_source.is_identical_to(copy_source));
CHECK(orig_source->Equals(*copy_source));
Handle<String> source2_string = isolate->factory()
->NewStringFromUtf8(CStrVector(source2))
.ToHandleChecked();
Handle<JSObject> global(isolate->context()->global_object());
ScriptData* cache = NULL;
Handle<SharedFunctionInfo> orig =
Compiler::CompileScript(source1_string, Handle<String>(), 0, 0, false,
Compiler::CompileScript(orig_source, Handle<String>(), 0, 0, false,
Handle<Context>(isolate->native_context()), NULL,
&cache, PRODUCE_CACHED_DATA, NOT_NATIVES_CODE);
Handle<JSFunction> orig_fun =
......@@ -755,12 +764,16 @@ TEST(SerializeToplevelInternalizedString) {
int builtins_count = CountBuiltins();
Handle<SharedFunctionInfo> copy =
Compiler::CompileScript(source2_string, Handle<String>(), 0, 0, false,
Handle<Context>(isolate->native_context()), NULL,
&cache, CONSUME_CACHED_DATA, NOT_NATIVES_CODE);
Handle<SharedFunctionInfo> copy;
{
DisallowCompilation no_compile_expected(isolate);
copy = Compiler::CompileScript(copy_source, Handle<String>(), 0, 0, false,
Handle<Context>(isolate->native_context()),
NULL, &cache, CONSUME_CACHED_DATA,
NOT_NATIVES_CODE);
}
CHECK_NE(*orig, *copy);
CHECK(Script::cast(copy->script())->source() == *source2_string);
CHECK(Script::cast(copy->script())->source() == *copy_source);
Handle<JSFunction> copy_fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment