Changing ScriptData API to serialize its internal representation to a
const char* array.
This decouples the API from the internal representation and avoids the need for
callers to serialize themselves.
As a side-effect, ScriptData::New() no longer assumes ownership of its input.
This shouldn't matter as typical usage patterns for the old API would have
required a copy prior to calling ScriptData::New().
Review URL: http://codereview.chromium.org/2118010/show
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4710
ce2b1a6d-e550-0410-aec6-
3dcde31c8c00
class V8EXPORT ScriptData { // NOLINT
public:
virtual ~ScriptData() { }
+ /**
+ * Pre-compiles the specified script (context-independent).
+ *
+ * \param input Pointer to UTF-8 script source code.
+ * \param length Length of UTF-8 script source code.
+ */
static ScriptData* PreCompile(const char* input, int length);
- static ScriptData* New(unsigned* data, int length);
+ /**
+ * Load previous pre-compilation data.
+ *
+ * \param data Pointer to data returned by a call to Data() of a previous
+ * ScriptData. Ownership is not transferred.
+ * \param length Length of data.
+ */
+ static ScriptData* New(const char* data, int length);
+
+ /**
+ * Returns the length of Data().
+ */
virtual int Length() = 0;
- virtual unsigned* Data() = 0;
+
+ /**
+ * Returns a serialized representation of this ScriptData that can later be
+ * passed to New(). NOTE: Serialized data is platform-dependent.
+ */
+ virtual const char* Data() = 0;
+
+ /**
+ * Returns true if the source code could not be parsed.
+ */
virtual bool HasError() = 0;
};
}
-ScriptData* ScriptData::New(unsigned* data, int length) {
- return new i::ScriptDataImpl(i::Vector<unsigned>(data, length));
+ScriptData* ScriptData::New(const char* data, int length) {
+ // Return an empty ScriptData if the length is obviously invalid.
+ if (length % sizeof(unsigned) != 0) {
+ return new i::ScriptDataImpl(i::Vector<unsigned>());
+ }
+
+ // Copy the data to ensure it is properly aligned.
+ int deserialized_data_length = length / sizeof(unsigned);
+ unsigned* deserialized_data = i::NewArray<unsigned>(deserialized_data_length);
+ memcpy(deserialized_data, data, length);
+
+ return new i::ScriptDataImpl(
+ i::Vector<unsigned>(deserialized_data, deserialized_data_length));
}
}
-Object* Object::GetPropertyWithCallback(Object* receiver,
+Object* Object::GetPropertyWithCallk
+jback(Object* receiver,
Object* structure,
String* name,
Object* holder) {
int ScriptDataImpl::Length() {
- return store_.length();
+ static const int kCharToUnsignedFactor = sizeof(unsigned) / sizeof(char);
+ return store_.length() * kCharToUnsignedFactor;
}
-unsigned* ScriptDataImpl::Data() {
- return store_.start();
+const char* ScriptDataImpl::Data() {
+ return reinterpret_cast<const char*>(store_.start());
}
last_entry_(0) { }
virtual ~ScriptDataImpl();
virtual int Length();
- virtual unsigned* Data();
+ virtual const char* Data();
virtual bool HasError();
FunctionEntry GetFunctionEnd(int start);
bool SanityCheck();
// TODO(155): This test would break without the initialization of V8. This is
// a workaround for now to make this test not fail.
v8::V8::Initialize();
- const char *script = "function foo(a) { return a+1; }";
- v8::ScriptData *sd =
+ const char* script = "function foo(a) { return a+1; }";
+ v8::ScriptData* sd =
v8::ScriptData::PreCompile(script, i::StrLength(script));
CHECK_NE(sd->Length(), 0);
CHECK_NE(sd->Data(), NULL);
TEST(PreCompileWithError) {
v8::V8::Initialize();
- const char *script = "function foo(a) { return 1 * * 2; }";
- v8::ScriptData *sd =
+ const char* script = "function foo(a) { return 1 * * 2; }";
+ v8::ScriptData* sd =
v8::ScriptData::PreCompile(script, i::StrLength(script));
CHECK(sd->HasError());
delete sd;
TEST(Regress31661) {
v8::V8::Initialize();
- const char *script = " The Definintive Guide";
- v8::ScriptData *sd =
+ const char* script = " The Definintive Guide";
+ v8::ScriptData* sd =
v8::ScriptData::PreCompile(script, i::StrLength(script));
CHECK(sd->HasError());
delete sd;
}
+// Tests that ScriptData can be serialized and deserialized.
+TEST(PreCompileSerialization) {
+ v8::V8::Initialize();
+ const char* script = "function foo(a) { return a+1; }";
+ v8::ScriptData* sd =
+ v8::ScriptData::PreCompile(script, i::StrLength(script));
+
+ // Serialize.
+ int serialized_data_length = sd->Length();
+ char* serialized_data = i::NewArray<char>(serialized_data_length);
+ memcpy(serialized_data, sd->Data(), serialized_data_length);
+
+ // Deserialize.
+ v8::ScriptData* deserialized_sd =
+ v8::ScriptData::New(serialized_data, serialized_data_length);
+
+ // Verify that the original is the same as the deserialized.
+ CHECK_EQ(sd->Length(), deserialized_sd->Length());
+ CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
+ CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
+
+ delete sd;
+ delete deserialized_sd;
+}
+
+
+// Attempts to deserialize bad data.
+TEST(PreCompileDeserializationError) {
+ v8::V8::Initialize();
+ const char* data = "DONT CARE";
+ int invalid_size = 3;
+ v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
+
+ CHECK_EQ(0, sd->Length());
+
+ delete sd;
+}
+
+
// This tests that we do not allow dictionary load/call inline caches
// to use functions that have not yet been compiled. The potential
// problem of loading a function that has not yet been compiled can