Commit c001a9ec authored by mtrofin's avatar mtrofin Committed by Commit bot

[wasm] Serialization/Deserialization of compiled module

Implementation of serialization/deserialization for compiled wasm
module.

BUG=v8:5072

Review-Url: https://codereview.chromium.org/2205973003
Cr-Commit-Position: refs/heads/master@{#38498}
parent 2cf2eef7
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
#include "src/frames-inl.h" #include "src/frames-inl.h"
#include "src/full-codegen/full-codegen.h" #include "src/full-codegen/full-codegen.h"
#include "src/isolate-inl.h" #include "src/isolate-inl.h"
#include "src/snapshot/code-serializer.h"
#include "src/snapshot/natives.h" #include "src/snapshot/natives.h"
#include "src/wasm/wasm-module.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -640,6 +642,43 @@ RUNTIME_FUNCTION(Runtime_SpeciesProtector) { ...@@ -640,6 +642,43 @@ RUNTIME_FUNCTION(Runtime_SpeciesProtector) {
return isolate->heap()->ToBoolean(isolate->IsArraySpeciesLookupChainIntact()); return isolate->heap()->ToBoolean(isolate->IsArraySpeciesLookupChainIntact());
} }
// Take a compiled wasm module, serialize it and copy the buffer into an array
// buffer, which is then returned.
RUNTIME_FUNCTION(Runtime_SerializeWasmModule) {
HandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, module_obj, 0);
Handle<FixedArray> orig =
handle(FixedArray::cast(module_obj->GetInternalField(0)));
std::unique_ptr<ScriptData> data =
WasmCompiledModuleSerializer::SerializeWasmModule(isolate, orig);
void* buff = isolate->array_buffer_allocator()->Allocate(data->length());
Handle<JSArrayBuffer> ret = isolate->factory()->NewJSArrayBuffer();
JSArrayBuffer::Setup(ret, isolate, false, buff, data->length());
memcpy(buff, data->data(), data->length());
return *ret;
}
// Take an array buffer and attempt to reconstruct a compiled wasm module.
// Return undefined if unsuccessful.
RUNTIME_FUNCTION(Runtime_DeserializeWasmModule) {
HandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 0);
Address mem_start = static_cast<Address>(buffer->backing_store());
int mem_size = static_cast<int>(buffer->byte_length()->Number());
ScriptData sc(mem_start, mem_size);
MaybeHandle<FixedArray> maybe_compiled_module =
WasmCompiledModuleSerializer::DeserializeWasmModule(isolate, &sc);
Handle<FixedArray> compiled_module;
if (!maybe_compiled_module.ToHandle(&compiled_module)) {
return isolate->heap()->undefined_value();
}
return *wasm::CreateCompiledModuleObject(isolate, compiled_module);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -880,7 +880,9 @@ namespace internal { ...@@ -880,7 +880,9 @@ namespace internal {
F(HasFixedFloat32Elements, 1, 1) \ F(HasFixedFloat32Elements, 1, 1) \
F(HasFixedFloat64Elements, 1, 1) \ F(HasFixedFloat64Elements, 1, 1) \
F(HasFixedUint8ClampedElements, 1, 1) \ F(HasFixedUint8ClampedElements, 1, 1) \
F(SpeciesProtector, 0, 1) F(SpeciesProtector, 0, 1) \
F(SerializeWasmModule, 1, 1) \
F(DeserializeWasmModule, 1, 1)
#define FOR_EACH_INTRINSIC_TYPEDARRAY(F) \ #define FOR_EACH_INTRINSIC_TYPEDARRAY(F) \
F(ArrayBufferGetByteLength, 1, 1) \ F(ArrayBufferGetByteLength, 1, 1) \
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "src/log.h" #include "src/log.h"
#include "src/macro-assembler.h" #include "src/macro-assembler.h"
#include "src/snapshot/deserializer.h" #include "src/snapshot/deserializer.h"
#include "src/snapshot/snapshot.h"
#include "src/version.h" #include "src/version.h"
namespace v8 { namespace v8 {
...@@ -28,23 +29,30 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate, ...@@ -28,23 +29,30 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate,
} }
// Serialize code object. // Serialize code object.
CodeSerializer cs(isolate, *source); CodeSerializer cs(isolate, SerializedCodeData::SourceHash(source));
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
Object** location = Handle<Object>::cast(info).location(); cs.reference_map()->AddAttachedReference(*source);
cs.VisitPointer(location); ScriptData* ret = cs.Serialize(info);
cs.SerializeDeferredObjects();
cs.Pad();
SerializedCodeData data(cs.sink()->data(), &cs);
ScriptData* script_data = data.GetScriptData();
if (FLAG_profile_deserialization) { if (FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF(); double ms = timer.Elapsed().InMillisecondsF();
int length = script_data->length(); int length = ret->length();
PrintF("[Serializing to %d bytes took %0.3f ms]\n", length, ms); PrintF("[Serializing to %d bytes took %0.3f ms]\n", length, ms);
} }
return script_data; return ret;
}
ScriptData* CodeSerializer::Serialize(Handle<HeapObject> obj) {
DisallowHeapAllocation no_gc;
VisitPointer(Handle<Object>::cast(obj).location());
SerializeDeferredObjects();
Pad();
SerializedCodeData data(sink()->data(), this);
return data.GetScriptData();
} }
void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
...@@ -84,10 +92,8 @@ void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, ...@@ -84,10 +92,8 @@ void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
DCHECK(code_object->has_reloc_info_for_serialization()); DCHECK(code_object->has_reloc_info_for_serialization());
SerializeGeneric(code_object, how_to_code, where_to_point); SerializeGeneric(code_object, how_to_code, where_to_point);
return; return;
case Code::WASM_FUNCTION: default:
case Code::WASM_TO_JS_FUNCTION: return SerializeCodeObject(code_object, how_to_code, where_to_point);
case Code::JS_TO_WASM_FUNCTION:
UNREACHABLE();
} }
UNREACHABLE(); UNREACHABLE();
} }
...@@ -156,30 +162,37 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( ...@@ -156,30 +162,37 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
HandleScope scope(isolate); HandleScope scope(isolate);
std::unique_ptr<SerializedCodeData> scd( SerializedCodeData::SanityCheckResult sanity_check_result =
SerializedCodeData::FromCachedData(isolate, cached_data, *source)); SerializedCodeData::CHECK_SUCCESS;
if (!scd) { const SerializedCodeData scd = SerializedCodeData::FromCachedData(
isolate, cached_data, SerializedCodeData::SourceHash(source),
&sanity_check_result);
if (sanity_check_result != SerializedCodeData::CHECK_SUCCESS) {
if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n"); if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n");
DCHECK(cached_data->rejected()); DCHECK(cached_data->rejected());
source->GetIsolate()->counters()->code_cache_reject_reason()->AddSample(
sanity_check_result);
return MaybeHandle<SharedFunctionInfo>(); return MaybeHandle<SharedFunctionInfo>();
} }
Deserializer deserializer(scd.get()); Deserializer deserializer(&scd);
deserializer.AddAttachedObject(source); deserializer.AddAttachedObject(source);
Vector<const uint32_t> code_stub_keys = scd->CodeStubKeys(); Vector<const uint32_t> code_stub_keys = scd.CodeStubKeys();
for (int i = 0; i < code_stub_keys.length(); i++) { for (int i = 0; i < code_stub_keys.length(); i++) {
deserializer.AddAttachedObject( deserializer.AddAttachedObject(
CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked()); CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked());
} }
// Deserialize. // Deserialize.
Handle<SharedFunctionInfo> result; Handle<HeapObject> as_heap_object;
if (!deserializer.DeserializeCode(isolate).ToHandle(&result)) { if (!deserializer.DeserializeObject(isolate).ToHandle(&as_heap_object)) {
// Deserializing may fail if the reservations cannot be fulfilled. // Deserializing may fail if the reservations cannot be fulfilled.
if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n"); if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n");
return MaybeHandle<SharedFunctionInfo>(); return MaybeHandle<SharedFunctionInfo>();
} }
Handle<SharedFunctionInfo> result =
Handle<SharedFunctionInfo>::cast(as_heap_object);
if (FLAG_profile_deserialization) { if (FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF(); double ms = timer.Elapsed().InMillisecondsF();
int length = cached_data->length(); int length = cached_data->length();
...@@ -199,6 +212,40 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( ...@@ -199,6 +212,40 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
return scope.CloseAndEscape(result); return scope.CloseAndEscape(result);
} }
std::unique_ptr<ScriptData> WasmCompiledModuleSerializer::SerializeWasmModule(
Isolate* isolate, Handle<FixedArray> compiled_module) {
WasmCompiledModuleSerializer wasm_cs(isolate, 0);
wasm_cs.reference_map()->AddAttachedReference(*isolate->native_context());
ScriptData* data = wasm_cs.Serialize(compiled_module);
return std::unique_ptr<ScriptData>(data);
}
MaybeHandle<FixedArray> WasmCompiledModuleSerializer::DeserializeWasmModule(
Isolate* isolate, ScriptData* data) {
SerializedCodeData::SanityCheckResult sanity_check_result =
SerializedCodeData::CHECK_SUCCESS;
MaybeHandle<FixedArray> nothing;
const SerializedCodeData scd = SerializedCodeData::FromCachedData(
isolate, data, 0, &sanity_check_result);
if (sanity_check_result != SerializedCodeData::CHECK_SUCCESS) {
return nothing;
}
Deserializer deserializer(&scd, true);
deserializer.AddAttachedObject(isolate->native_context());
Vector<const uint32_t> stub_keys = scd.CodeStubKeys();
for (int i = 0; i < stub_keys.length(); ++i) {
deserializer.AddAttachedObject(
CodeStub::GetCode(isolate, stub_keys[i]).ToHandleChecked());
}
MaybeHandle<HeapObject> obj = deserializer.DeserializeObject(isolate);
if (obj.is_null() || !obj.ToHandleChecked()->IsFixedArray()) return nothing;
return Handle<FixedArray>::cast(obj.ToHandleChecked());
}
class Checksum { class Checksum {
public: public:
explicit Checksum(Vector<const byte> payload) { explicit Checksum(Vector<const byte> payload) {
...@@ -260,7 +307,7 @@ SerializedCodeData::SerializedCodeData(const List<byte>* payload, ...@@ -260,7 +307,7 @@ SerializedCodeData::SerializedCodeData(const List<byte>* payload,
// Set header values. // Set header values.
SetMagicNumber(cs->isolate()); SetMagicNumber(cs->isolate());
SetHeaderValue(kVersionHashOffset, Version::Hash()); SetHeaderValue(kVersionHashOffset, Version::Hash());
SetHeaderValue(kSourceHashOffset, SourceHash(cs->source())); SetHeaderValue(kSourceHashOffset, cs->source_hash());
SetHeaderValue(kCpuFeaturesOffset, SetHeaderValue(kCpuFeaturesOffset,
static_cast<uint32_t>(CpuFeatures::SupportedFeatures())); static_cast<uint32_t>(CpuFeatures::SupportedFeatures()));
SetHeaderValue(kFlagHashOffset, FlagList::Hash()); SetHeaderValue(kFlagHashOffset, FlagList::Hash());
...@@ -288,7 +335,7 @@ SerializedCodeData::SerializedCodeData(const List<byte>* payload, ...@@ -288,7 +335,7 @@ SerializedCodeData::SerializedCodeData(const List<byte>* payload,
} }
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck( SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, String* source) const { Isolate* isolate, uint32_t expected_source_hash) const {
uint32_t magic_number = GetMagicNumber(); uint32_t magic_number = GetMagicNumber();
if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH; if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH;
uint32_t version_hash = GetHeaderValue(kVersionHashOffset); uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
...@@ -298,7 +345,7 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck( ...@@ -298,7 +345,7 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
uint32_t c1 = GetHeaderValue(kChecksum1Offset); uint32_t c1 = GetHeaderValue(kChecksum1Offset);
uint32_t c2 = GetHeaderValue(kChecksum2Offset); uint32_t c2 = GetHeaderValue(kChecksum2Offset);
if (version_hash != Version::Hash()) return VERSION_MISMATCH; if (version_hash != Version::Hash()) return VERSION_MISMATCH;
if (source_hash != SourceHash(source)) return SOURCE_MISMATCH; if (source_hash != expected_source_hash) return SOURCE_MISMATCH;
if (cpu_features != static_cast<uint32_t>(CpuFeatures::SupportedFeatures())) { if (cpu_features != static_cast<uint32_t>(CpuFeatures::SupportedFeatures())) {
return CPU_FEATURES_MISMATCH; return CPU_FEATURES_MISMATCH;
} }
...@@ -307,7 +354,7 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck( ...@@ -307,7 +354,7 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
return CHECK_SUCCESS; return CHECK_SUCCESS;
} }
uint32_t SerializedCodeData::SourceHash(String* source) const { uint32_t SerializedCodeData::SourceHash(Handle<String> source) {
return source->length(); return source->length();
} }
...@@ -350,17 +397,17 @@ Vector<const uint32_t> SerializedCodeData::CodeStubKeys() const { ...@@ -350,17 +397,17 @@ Vector<const uint32_t> SerializedCodeData::CodeStubKeys() const {
SerializedCodeData::SerializedCodeData(ScriptData* data) SerializedCodeData::SerializedCodeData(ScriptData* data)
: SerializedData(const_cast<byte*>(data->data()), data->length()) {} : SerializedData(const_cast<byte*>(data->data()), data->length()) {}
SerializedCodeData* SerializedCodeData::FromCachedData(Isolate* isolate, const SerializedCodeData SerializedCodeData::FromCachedData(
ScriptData* cached_data, Isolate* isolate, ScriptData* cached_data, uint32_t expected_source_hash,
String* source) { SanityCheckResult* rejection_result) {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
SerializedCodeData* scd = new SerializedCodeData(cached_data); SerializedCodeData scd(cached_data);
SanityCheckResult r = scd->SanityCheck(isolate, source); *rejection_result = scd.SanityCheck(isolate, expected_source_hash);
if (r == CHECK_SUCCESS) return scd; if (*rejection_result != CHECK_SUCCESS) {
cached_data->Reject(); cached_data->Reject();
source->GetIsolate()->counters()->code_cache_reject_reason()->AddSample(r); return SerializedCodeData(nullptr, 0);
delete scd; }
return NULL; return scd;
} }
} // namespace internal } // namespace internal
......
...@@ -17,24 +17,29 @@ class CodeSerializer : public Serializer { ...@@ -17,24 +17,29 @@ class CodeSerializer : public Serializer {
Handle<SharedFunctionInfo> info, Handle<SharedFunctionInfo> info,
Handle<String> source); Handle<String> source);
ScriptData* Serialize(Handle<HeapObject> obj);
MUST_USE_RESULT static MaybeHandle<SharedFunctionInfo> Deserialize( MUST_USE_RESULT static MaybeHandle<SharedFunctionInfo> Deserialize(
Isolate* isolate, ScriptData* cached_data, Handle<String> source); Isolate* isolate, ScriptData* cached_data, Handle<String> source);
String* source() const {
DCHECK(!AllowHeapAllocation::IsAllowed());
return source_;
}
const List<uint32_t>* stub_keys() const { return &stub_keys_; } const List<uint32_t>* stub_keys() const { return &stub_keys_; }
private: uint32_t source_hash() const { return source_hash_; }
CodeSerializer(Isolate* isolate, String* source)
: Serializer(isolate), source_(source) {
reference_map_.AddAttachedReference(source);
}
protected:
explicit CodeSerializer(Isolate* isolate, uint32_t source_hash)
: Serializer(isolate), source_hash_(source_hash) {}
~CodeSerializer() override { OutputStatistics("CodeSerializer"); } ~CodeSerializer() override { OutputStatistics("CodeSerializer"); }
virtual void SerializeCodeObject(Code* code_object, HowToCode how_to_code,
WhereToPoint where_to_point) {
UNREACHABLE();
}
void SerializeGeneric(HeapObject* heap_object, HowToCode how_to_code,
WhereToPoint where_to_point);
private:
void SerializeObject(HeapObject* o, HowToCode how_to_code, void SerializeObject(HeapObject* o, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) override; WhereToPoint where_to_point, int skip) override;
...@@ -42,22 +47,55 @@ class CodeSerializer : public Serializer { ...@@ -42,22 +47,55 @@ class CodeSerializer : public Serializer {
WhereToPoint where_to_point); WhereToPoint where_to_point);
void SerializeCodeStub(Code* code_stub, HowToCode how_to_code, void SerializeCodeStub(Code* code_stub, HowToCode how_to_code,
WhereToPoint where_to_point); WhereToPoint where_to_point);
void SerializeGeneric(HeapObject* heap_object, HowToCode how_to_code,
WhereToPoint where_to_point);
DisallowHeapAllocation no_gc_; DisallowHeapAllocation no_gc_;
String* source_; uint32_t source_hash_;
List<uint32_t> stub_keys_; List<uint32_t> stub_keys_;
DISALLOW_COPY_AND_ASSIGN(CodeSerializer); DISALLOW_COPY_AND_ASSIGN(CodeSerializer);
}; };
class WasmCompiledModuleSerializer : public CodeSerializer {
public:
static std::unique_ptr<ScriptData> SerializeWasmModule(
Isolate* isolate, Handle<FixedArray> compiled_module);
static MaybeHandle<FixedArray> DeserializeWasmModule(Isolate* isolate,
ScriptData* data);
protected:
void SerializeCodeObject(Code* code_object, HowToCode how_to_code,
WhereToPoint where_to_point) override {
Code::Kind kind = code_object->kind();
if (kind == Code::WASM_FUNCTION || kind == Code::WASM_TO_JS_FUNCTION ||
kind == Code::JS_TO_WASM_FUNCTION) {
SerializeGeneric(code_object, how_to_code, where_to_point);
} else {
UNREACHABLE();
}
}
private:
WasmCompiledModuleSerializer(Isolate* isolate, uint32_t source_hash)
: CodeSerializer(isolate, source_hash) {}
DISALLOW_COPY_AND_ASSIGN(WasmCompiledModuleSerializer);
};
// Wrapper around ScriptData to provide code-serializer-specific functionality. // Wrapper around ScriptData to provide code-serializer-specific functionality.
class SerializedCodeData : public SerializedData { class SerializedCodeData : public SerializedData {
public: public:
enum SanityCheckResult {
CHECK_SUCCESS = 0,
MAGIC_NUMBER_MISMATCH = 1,
VERSION_MISMATCH = 2,
SOURCE_MISMATCH = 3,
CPU_FEATURES_MISMATCH = 4,
FLAGS_MISMATCH = 5,
CHECKSUM_MISMATCH = 6
};
// Used when consuming. // Used when consuming.
static SerializedCodeData* FromCachedData(Isolate* isolate, static const SerializedCodeData FromCachedData(
ScriptData* cached_data, Isolate* isolate, ScriptData* cached_data, uint32_t expected_source_hash,
String* source); SanityCheckResult* rejection_result);
// Used when producing. // Used when producing.
SerializedCodeData(const List<byte>* payload, const CodeSerializer* cs); SerializedCodeData(const List<byte>* payload, const CodeSerializer* cs);
...@@ -70,23 +108,15 @@ class SerializedCodeData : public SerializedData { ...@@ -70,23 +108,15 @@ class SerializedCodeData : public SerializedData {
Vector<const uint32_t> CodeStubKeys() const; Vector<const uint32_t> CodeStubKeys() const;
static uint32_t SourceHash(Handle<String> source);
private: private:
explicit SerializedCodeData(ScriptData* data); explicit SerializedCodeData(ScriptData* data);
SerializedCodeData(const byte* data, int size)
: SerializedData(const_cast<byte*>(data), size) {}
enum SanityCheckResult { SanityCheckResult SanityCheck(Isolate* isolate,
CHECK_SUCCESS = 0, uint32_t expected_source_hash) const;
MAGIC_NUMBER_MISMATCH = 1,
VERSION_MISMATCH = 2,
SOURCE_MISMATCH = 3,
CPU_FEATURES_MISMATCH = 4,
FLAGS_MISMATCH = 5,
CHECKSUM_MISMATCH = 6
};
SanityCheckResult SanityCheck(Isolate* isolate, String* source) const;
uint32_t SourceHash(String* source) const;
// The data header consists of uint32_t-sized entries: // The data header consists of uint32_t-sized entries:
// [0] magic number and external reference count // [0] magic number and external reference count
// [1] version hash // [1] version hash
......
...@@ -136,22 +136,21 @@ MaybeHandle<Object> Deserializer::DeserializePartial( ...@@ -136,22 +136,21 @@ MaybeHandle<Object> Deserializer::DeserializePartial(
return Handle<Object>(root, isolate); return Handle<Object>(root, isolate);
} }
MaybeHandle<SharedFunctionInfo> Deserializer::DeserializeCode( MaybeHandle<HeapObject> Deserializer::DeserializeObject(Isolate* isolate) {
Isolate* isolate) {
Initialize(isolate); Initialize(isolate);
if (!ReserveSpace()) { if (!ReserveSpace()) {
return Handle<SharedFunctionInfo>(); return MaybeHandle<HeapObject>();
} else { } else {
deserializing_user_code_ = true; deserializing_user_code_ = true;
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<SharedFunctionInfo> result; Handle<HeapObject> result;
{ {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
Object* root; Object* root;
VisitPointer(&root); VisitPointer(&root);
DeserializeDeferredObjects(); DeserializeDeferredObjects();
FlushICacheForNewCodeObjectsAndRecordEmbeddedObjects(); FlushICacheForNewCodeObjectsAndRecordEmbeddedObjects();
result = Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(root)); result = Handle<HeapObject>(HeapObject::cast(root));
isolate->heap()->RegisterReservationsForBlackAllocation(reservations_); isolate->heap()->RegisterReservationsForBlackAllocation(reservations_);
} }
CommitPostProcessedObjects(isolate); CommitPostProcessedObjects(isolate);
......
...@@ -30,13 +30,13 @@ class Deserializer : public SerializerDeserializer { ...@@ -30,13 +30,13 @@ class Deserializer : public SerializerDeserializer {
public: public:
// Create a deserializer from a snapshot byte source. // Create a deserializer from a snapshot byte source.
template <class Data> template <class Data>
explicit Deserializer(Data* data) explicit Deserializer(Data* data, bool deserializing_user_code = false)
: isolate_(NULL), : isolate_(NULL),
source_(data->Payload()), source_(data->Payload()),
magic_number_(data->GetMagicNumber()), magic_number_(data->GetMagicNumber()),
external_reference_table_(NULL), external_reference_table_(NULL),
deserialized_large_objects_(0), deserialized_large_objects_(0),
deserializing_user_code_(false), deserializing_user_code_(deserializing_user_code),
next_alignment_(kWordAligned) { next_alignment_(kWordAligned) {
DecodeReservation(data->Reservations()); DecodeReservation(data->Reservations());
} }
...@@ -50,8 +50,8 @@ class Deserializer : public SerializerDeserializer { ...@@ -50,8 +50,8 @@ class Deserializer : public SerializerDeserializer {
MaybeHandle<Object> DeserializePartial(Isolate* isolate, MaybeHandle<Object> DeserializePartial(Isolate* isolate,
Handle<JSGlobalProxy> global_proxy); Handle<JSGlobalProxy> global_proxy);
// Deserialize a shared function info. Fail gracefully. // Deserialize an object graph. Fail gracefully.
MaybeHandle<SharedFunctionInfo> DeserializeCode(Isolate* isolate); MaybeHandle<HeapObject> DeserializeObject(Isolate* isolate);
// Add an object to back an attached reference. The order to add objects must // Add an object to back an attached reference. The order to add objects must
// mirror the order they are added in the serializer. // mirror the order they are added in the serializer.
......
...@@ -318,17 +318,9 @@ static i::MaybeHandle<i::JSObject> CreateModuleObject( ...@@ -318,17 +318,9 @@ static i::MaybeHandle<i::JSObject> CreateModuleObject(
i::MaybeHandle<i::FixedArray> compiled_module = i::MaybeHandle<i::FixedArray> compiled_module =
decoded_module->CompileFunctions(i_isolate, thrower); decoded_module->CompileFunctions(i_isolate, thrower);
if (compiled_module.is_null()) return nothing; if (compiled_module.is_null()) return nothing;
Local<Context> context = isolate->GetCurrentContext();
i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
i::Handle<i::JSFunction> module_cons(i_context->wasm_module_constructor());
i::Handle<i::JSObject> module_obj =
i_isolate->factory()->NewJSObject(module_cons);
module_obj->SetInternalField(0, *compiled_module.ToHandleChecked());
i::Handle<i::Object> module_ref = Utils::OpenHandle(*source);
i::Handle<i::Symbol> module_sym(i_context->wasm_module_sym());
i::Object::SetProperty(module_obj, module_sym, module_ref, i::STRICT).Check();
return module_obj; return i::wasm::CreateCompiledModuleObject(i_isolate,
compiled_module.ToHandleChecked());
} }
void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) { void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
......
...@@ -5,12 +5,14 @@ ...@@ -5,12 +5,14 @@
#include <memory> #include <memory>
#include "src/base/atomic-utils.h" #include "src/base/atomic-utils.h"
#include "src/code-stubs.h"
#include "src/macro-assembler.h" #include "src/macro-assembler.h"
#include "src/objects.h" #include "src/objects.h"
#include "src/property-descriptor.h" #include "src/property-descriptor.h"
#include "src/v8.h"
#include "src/simulator.h" #include "src/simulator.h"
#include "src/snapshot/snapshot.h"
#include "src/v8.h"
#include "src/wasm/ast-decoder.h" #include "src/wasm/ast-decoder.h"
#include "src/wasm/module-decoder.h" #include "src/wasm/module-decoder.h"
...@@ -1571,6 +1573,17 @@ int GetNumberOfFunctions(JSObject* wasm) { ...@@ -1571,6 +1573,17 @@ int GetNumberOfFunctions(JSObject* wasm) {
return ByteArray::cast(func_names_obj)->get_int(0); return ByteArray::cast(func_names_obj)->get_int(0);
} }
Handle<JSObject> CreateCompiledModuleObject(
Isolate* isolate, Handle<FixedArray> compiled_module) {
Handle<JSFunction> module_cons(
isolate->native_context()->wasm_module_constructor());
Handle<JSObject> module_obj = isolate->factory()->NewJSObject(module_cons);
module_obj->SetInternalField(0, *compiled_module);
Handle<Symbol> module_sym(isolate->native_context()->wasm_module_sym());
Object::SetProperty(module_obj, module_sym, module_obj, STRICT).Check();
return module_obj;
}
namespace testing { namespace testing {
int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "src/api.h" #include "src/api.h"
#include "src/handles.h" #include "src/handles.h"
#include "src/parsing/preparse-data.h"
#include "src/wasm/wasm-opcodes.h" #include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-result.h" #include "src/wasm/wasm-result.h"
...@@ -396,6 +398,9 @@ Handle<FixedArray> BuildFunctionTable(Isolate* isolate, uint32_t index, ...@@ -396,6 +398,9 @@ Handle<FixedArray> BuildFunctionTable(Isolate* isolate, uint32_t index,
void PopulateFunctionTable(Handle<FixedArray> table, uint32_t table_size, void PopulateFunctionTable(Handle<FixedArray> table, uint32_t table_size,
const std::vector<Handle<Code>>* code_table); const std::vector<Handle<Code>>* code_table);
Handle<JSObject> CreateCompiledModuleObject(Isolate* isolate,
Handle<FixedArray> compiled_module);
namespace testing { namespace testing {
// Decode, verify, and run the function labeled "main" in the // Decode, verify, and run the function labeled "main" in the
......
// Copyright 2015 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.
// Flags: --expose-wasm --allow-natives-syntax --expose-gc
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
(function SerializeAndDeserializeModule() {
var builder = new WasmModuleBuilder();
builder.addMemory(1,1, true);
var kSig_v_i = makeSig([kAstI32], []);
var signature = builder.addType(kSig_v_i);
builder.addImport("some_value", kSig_i);
builder.addImport("writer", signature);
builder.addFunction("main", kSig_i_i)
.addBody([
kExprI32Const, 1,
kExprGetLocal, 0,
kExprI32LoadMem, 0, 0,
kExprCallIndirect, kArity1, signature,
kExprGetLocal,0,
kExprI32LoadMem,0, 0,
kExprCallImport, kArity0, 0,
kExprI32Add
]).exportFunc();
// writer(mem[i]);
// return mem[i] + some_value();
builder.addFunction("_wrap_writer", signature)
.addBody([
kExprGetLocal, 0,
kExprCallImport, kArity1, 1]);
builder.appendToTable([0, 1]);
var module = new WebAssembly.Module(builder.toBuffer());
var buff = %SerializeWasmModule(module);
module = null;
gc();
module = %DeserializeWasmModule(buff);
var mem_1 = new ArrayBuffer(4);
var view_1 = new Int32Array(mem_1);
view_1[0] = 42;
var outval_1;
var i1 = new WebAssembly.Instance(module, {some_value: () => 1,
writer: (x)=>outval_1 = x }, mem_1);
assertEquals(43, i1.exports.main(0));
assertEquals(42, outval_1);
})();
(function DeserializeInvalidObject() {
var invalid_buffer = new ArrayBuffer(10);
module = %DeserializeWasmModule(invalid_buffer);
assertEquals(module, undefined);
})();
(function RelationBetweenModuleAndClone() {
let builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i)
.addBody([kExprI8Const, 42])
.exportFunc();
var compiled_module = new WebAssembly.Module(builder.toBuffer());
var serialized = %SerializeWasmModule(compiled_module);
var clone = %DeserializeWasmModule(serialized);
assertNotNull(clone);
assertFalse(clone == undefined);
assertFalse(clone == compiled_module);
assertEquals(clone.constructor, compiled_module.constructor);
})()
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