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