| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stdlib.h> | 5 #include <stdlib.h> |
| 6 #include <string.h> | 6 #include <string.h> |
| 7 | 7 |
| 8 #include "src/snapshot/code-serializer.h" | 8 #include "src/snapshot/code-serializer.h" |
| 9 #include "src/version.h" | 9 #include "src/version.h" |
| 10 #include "src/wasm/module-decoder.h" | 10 #include "src/wasm/module-decoder.h" |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 f1->EmitCode(code1, sizeof(code1)); | 166 f1->EmitCode(code1, sizeof(code1)); |
| 167 WasmFunctionBuilder* f2 = builder->AddFunction(sigs.i_v()); | 167 WasmFunctionBuilder* f2 = builder->AddFunction(sigs.i_v()); |
| 168 ExportAsMain(f2); | 168 ExportAsMain(f2); |
| 169 byte code2[] = {WASM_SET_GLOBAL(global1, WASM_I32V_1(56)), | 169 byte code2[] = {WASM_SET_GLOBAL(global1, WASM_I32V_1(56)), |
| 170 WASM_SET_GLOBAL(global2, WASM_I32V_1(41)), | 170 WASM_SET_GLOBAL(global2, WASM_I32V_1(41)), |
| 171 WASM_RETURN1(WASM_CALL_FUNCTION0(f1->func_index()))}; | 171 WASM_RETURN1(WASM_CALL_FUNCTION0(f1->func_index()))}; |
| 172 f2->EmitCode(code2, sizeof(code2)); | 172 f2->EmitCode(code2, sizeof(code2)); |
| 173 TestModule(&zone, builder, 97); | 173 TestModule(&zone, builder, 97); |
| 174 } | 174 } |
| 175 | 175 |
| 176 TEST(Run_WasmModule_Serialization) { | 176 // Approximate gtest TEST_F style, in case we adopt gtest. |
| 177 static const char* kFunctionName = "increment"; | 177 class WasmSerializationTest { |
| 178 v8::internal::AccountingAllocator allocator; | 178 public: |
| 179 Zone zone(&allocator, ZONE_NAME); | 179 WasmSerializationTest() : zone_(&allocator_, ZONE_NAME) { |
| 180 | 180 // Don't call here if we move to gtest. |
| 181 WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone); | 181 SetUp(); |
| 182 TestSignatures sigs; | |
| 183 | |
| 184 WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i()); | |
| 185 byte code[] = {WASM_GET_LOCAL(0), kExprI32Const, 1, kExprI32Add}; | |
| 186 f->EmitCode(code, sizeof(code)); | |
| 187 f->ExportAs(CStrVector(kFunctionName)); | |
| 188 | |
| 189 ZoneBuffer buffer(&zone); | |
| 190 builder->WriteTo(buffer); | |
| 191 | |
| 192 Isolate* isolate = CcTest::InitIsolateOnce(); | |
| 193 ErrorThrower thrower(isolate, ""); | |
| 194 uint8_t* bytes = nullptr; | |
| 195 size_t bytes_size = 0; | |
| 196 v8::WasmCompiledModule::SerializedModule data; | |
| 197 { | |
| 198 HandleScope scope(isolate); | |
| 199 testing::SetupIsolateForWasmModule(isolate); | |
| 200 | |
| 201 ModuleResult decoding_result = DecodeWasmModule( | |
| 202 isolate, &zone, buffer.begin(), buffer.end(), false, kWasmOrigin); | |
| 203 std::unique_ptr<const WasmModule> module(decoding_result.val); | |
| 204 CHECK(!decoding_result.failed()); | |
| 205 | |
| 206 MaybeHandle<WasmCompiledModule> compiled_module = | |
| 207 module->CompileFunctions(isolate, &thrower); | |
| 208 CHECK(!compiled_module.is_null()); | |
| 209 Handle<JSObject> module_obj = CreateCompiledModuleObject( | |
| 210 isolate, compiled_module.ToHandleChecked(), ModuleOrigin::kWasmOrigin); | |
| 211 v8::Local<v8::Object> v8_module_obj = v8::Utils::ToLocal(module_obj); | |
| 212 CHECK(v8_module_obj->IsWebAssemblyCompiledModule()); | |
| 213 | |
| 214 v8::Local<v8::WasmCompiledModule> v8_compiled_module = | |
| 215 v8_module_obj.As<v8::WasmCompiledModule>(); | |
| 216 v8::Local<v8::String> uncompiled_bytes = | |
| 217 v8_compiled_module->GetWasmWireBytes(); | |
| 218 bytes_size = static_cast<size_t>(uncompiled_bytes->Length()); | |
| 219 bytes = zone.NewArray<uint8_t>(uncompiled_bytes->Length()); | |
| 220 uncompiled_bytes->WriteOneByte(bytes); | |
| 221 data = v8_compiled_module->Serialize(); | |
| 222 } | 182 } |
| 223 | 183 |
| 224 v8::WasmCompiledModule::CallerOwnedBuffer wire_bytes = { | 184 void ClearSerializedData() { |
| 225 const_cast<const uint8_t*>(bytes), bytes_size}; | 185 serialized_bytes_.first = nullptr; |
| 186 serialized_bytes_.second = 0; |
| 187 } |
| 226 | 188 |
| 227 v8::WasmCompiledModule::CallerOwnedBuffer serialized_bytes = { | 189 void InvalidateVersion() { |
| 228 data.first.get(), data.second}; | 190 uint32_t* buffer = reinterpret_cast<uint32_t*>( |
| 229 v8::Isolate::CreateParams create_params; | 191 const_cast<uint8_t*>(serialized_bytes_.first)); |
| 230 create_params.array_buffer_allocator = | 192 buffer[SerializedCodeData::kVersionHashOffset] = Version::Hash() + 1; |
| 231 CcTest::InitIsolateOnce()->array_buffer_allocator(); | 193 } |
| 232 | 194 |
| 233 for (int i = 0; i < 3; ++i) { | 195 void InvalidateWireBytes() { |
| 234 v8::Isolate* v8_isolate = v8::Isolate::New(create_params); | 196 memset(const_cast<uint8_t*>(wire_bytes_.first), '\0', |
| 235 if (i == 1) { | 197 wire_bytes_.second / 2); |
| 236 // Invalidate the header by providing a mismatched version | 198 } |
| 237 uint32_t* buffer = reinterpret_cast<uint32_t*>( | 199 |
| 238 const_cast<uint8_t*>(serialized_bytes.first)); | 200 v8::MaybeLocal<v8::WasmCompiledModule> Deserialize() { |
| 239 buffer[SerializedCodeData::kVersionHashOffset] = Version::Hash() + 1; | 201 ErrorThrower thrower(current_isolate(), ""); |
| 202 v8::MaybeLocal<v8::WasmCompiledModule> deserialized = |
| 203 v8::WasmCompiledModule::DeserializeOrCompile( |
| 204 current_isolate_v8(), serialized_bytes(), wire_bytes()); |
| 205 return deserialized; |
| 206 } |
| 207 |
| 208 void DeserializeAndRun() { |
| 209 ErrorThrower thrower(current_isolate(), ""); |
| 210 v8::Local<v8::WasmCompiledModule> deserialized_module; |
| 211 CHECK(Deserialize().ToLocal(&deserialized_module)); |
| 212 Handle<JSObject> module_object = |
| 213 Handle<JSObject>::cast(v8::Utils::OpenHandle(*deserialized_module)); |
| 214 { |
| 215 DisallowHeapAllocation assume_no_gc; |
| 216 Handle<WasmCompiledModule> compiled_part( |
| 217 WasmCompiledModule::cast(module_object->GetInternalField(0)), |
| 218 current_isolate()); |
| 219 CHECK_EQ(memcmp(compiled_part->module_bytes()->GetCharsAddress(), |
| 220 wire_bytes().first, wire_bytes().second), |
| 221 0); |
| 222 } |
| 223 Handle<JSObject> instance = |
| 224 WasmModule::Instantiate(current_isolate(), &thrower, module_object, |
| 225 Handle<JSReceiver>::null(), |
| 226 Handle<JSArrayBuffer>::null()) |
| 227 .ToHandleChecked(); |
| 228 Handle<Object> params[1] = { |
| 229 Handle<Object>(Smi::FromInt(41), current_isolate())}; |
| 230 int32_t result = testing::CallWasmFunctionForTesting( |
| 231 current_isolate(), instance, &thrower, kFunctionName, 1, params, |
| 232 ModuleOrigin::kWasmOrigin); |
| 233 CHECK(result == 42); |
| 234 } |
| 235 |
| 236 Isolate* current_isolate() { |
| 237 return reinterpret_cast<Isolate*>(current_isolate_v8_); |
| 238 } |
| 239 |
| 240 ~WasmSerializationTest() { |
| 241 // Don't call from here if we move to gtest |
| 242 TearDown(); |
| 243 } |
| 244 |
| 245 private: |
| 246 static const char* kFunctionName; |
| 247 |
| 248 Zone* zone() { return &zone_; } |
| 249 const v8::WasmCompiledModule::CallerOwnedBuffer& wire_bytes() const { |
| 250 return wire_bytes_; |
| 251 } |
| 252 |
| 253 const v8::WasmCompiledModule::CallerOwnedBuffer& serialized_bytes() const { |
| 254 return serialized_bytes_; |
| 255 } |
| 256 |
| 257 v8::Isolate* current_isolate_v8() { return current_isolate_v8_; } |
| 258 |
| 259 void SetUp() { |
| 260 WasmModuleBuilder* builder = new (zone()) WasmModuleBuilder(zone()); |
| 261 TestSignatures sigs; |
| 262 |
| 263 WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i()); |
| 264 byte code[] = {WASM_GET_LOCAL(0), kExprI32Const, 1, kExprI32Add}; |
| 265 f->EmitCode(code, sizeof(code)); |
| 266 f->ExportAs(CStrVector(kFunctionName)); |
| 267 |
| 268 ZoneBuffer buffer(&zone_); |
| 269 builder->WriteTo(buffer); |
| 270 |
| 271 Isolate* serialization_isolate = CcTest::InitIsolateOnce(); |
| 272 ErrorThrower thrower(serialization_isolate, ""); |
| 273 uint8_t* bytes = nullptr; |
| 274 size_t bytes_size = 0; |
| 275 { |
| 276 HandleScope scope(serialization_isolate); |
| 277 testing::SetupIsolateForWasmModule(serialization_isolate); |
| 278 |
| 279 ModuleResult decoding_result = |
| 280 DecodeWasmModule(serialization_isolate, zone(), buffer.begin(), |
| 281 buffer.end(), false, kWasmOrigin); |
| 282 std::unique_ptr<const WasmModule> module(decoding_result.val); |
| 283 CHECK(!decoding_result.failed()); |
| 284 |
| 285 MaybeHandle<WasmCompiledModule> compiled_module = |
| 286 module->CompileFunctions(serialization_isolate, &thrower); |
| 287 CHECK(!compiled_module.is_null()); |
| 288 Handle<JSObject> module_obj = CreateCompiledModuleObject( |
| 289 serialization_isolate, compiled_module.ToHandleChecked(), |
| 290 ModuleOrigin::kWasmOrigin); |
| 291 v8::Local<v8::Object> v8_module_obj = v8::Utils::ToLocal(module_obj); |
| 292 CHECK(v8_module_obj->IsWebAssemblyCompiledModule()); |
| 293 |
| 294 v8::Local<v8::WasmCompiledModule> v8_compiled_module = |
| 295 v8_module_obj.As<v8::WasmCompiledModule>(); |
| 296 v8::Local<v8::String> uncompiled_bytes = |
| 297 v8_compiled_module->GetWasmWireBytes(); |
| 298 bytes_size = static_cast<size_t>(uncompiled_bytes->Length()); |
| 299 bytes = zone()->NewArray<uint8_t>(uncompiled_bytes->Length()); |
| 300 uncompiled_bytes->WriteOneByte(bytes); |
| 301 // keep alive data_ until the end |
| 302 data_ = v8_compiled_module->Serialize(); |
| 240 } | 303 } |
| 241 | 304 |
| 242 if (i == 2) { | 305 wire_bytes_ = {const_cast<const uint8_t*>(bytes), bytes_size}; |
| 243 // Provide no serialized data to force recompilation. | 306 |
| 244 serialized_bytes.first = nullptr; | 307 serialized_bytes_ = {data_.first.get(), data_.second}; |
| 245 serialized_bytes.second = 0; | 308 |
| 246 } | 309 v8::Isolate::CreateParams create_params; |
| 247 { | 310 create_params.array_buffer_allocator = |
| 248 v8::Isolate::Scope isolate_scope(v8_isolate); | 311 serialization_isolate->array_buffer_allocator(); |
| 249 v8::HandleScope new_scope(v8_isolate); | 312 |
| 250 v8::Local<v8::Context> new_ctx = v8::Context::New(v8_isolate); | 313 current_isolate_v8_ = v8::Isolate::New(create_params); |
| 251 new_ctx->Enter(); | 314 v8::HandleScope new_scope(current_isolate_v8()); |
| 252 isolate = reinterpret_cast<Isolate*>(v8_isolate); | 315 v8::Local<v8::Context> deserialization_context = |
| 253 testing::SetupIsolateForWasmModule(isolate); | 316 v8::Context::New(current_isolate_v8()); |
| 254 v8::MaybeLocal<v8::WasmCompiledModule> deserialized = | 317 deserialization_context->Enter(); |
| 255 v8::WasmCompiledModule::DeserializeOrCompile( | 318 testing::SetupIsolateForWasmModule(current_isolate()); |
| 256 v8_isolate, serialized_bytes, wire_bytes); | |
| 257 v8::Local<v8::WasmCompiledModule> compiled_module; | |
| 258 CHECK(deserialized.ToLocal(&compiled_module)); | |
| 259 Handle<JSObject> module_object = | |
| 260 Handle<JSObject>::cast(v8::Utils::OpenHandle(*compiled_module)); | |
| 261 Handle<JSObject> instance = | |
| 262 WasmModule::Instantiate(isolate, &thrower, module_object, | |
| 263 Handle<JSReceiver>::null(), | |
| 264 Handle<JSArrayBuffer>::null()) | |
| 265 .ToHandleChecked(); | |
| 266 Handle<Object> params[1] = {Handle<Object>(Smi::FromInt(41), isolate)}; | |
| 267 int32_t result = testing::CallWasmFunctionForTesting( | |
| 268 isolate, instance, &thrower, kFunctionName, 1, params, | |
| 269 ModuleOrigin::kWasmOrigin); | |
| 270 CHECK(result == 42); | |
| 271 new_ctx->Exit(); | |
| 272 } | |
| 273 v8_isolate->Dispose(); | |
| 274 } | 319 } |
| 320 |
| 321 void TearDown() { |
| 322 current_isolate_v8()->Dispose(); |
| 323 current_isolate_v8_ = nullptr; |
| 324 } |
| 325 |
| 326 v8::internal::AccountingAllocator allocator_; |
| 327 Zone zone_; |
| 328 v8::WasmCompiledModule::SerializedModule data_; |
| 329 v8::WasmCompiledModule::CallerOwnedBuffer wire_bytes_; |
| 330 v8::WasmCompiledModule::CallerOwnedBuffer serialized_bytes_; |
| 331 v8::Isolate* current_isolate_v8_; |
| 332 }; |
| 333 |
| 334 const char* WasmSerializationTest::kFunctionName = "increment"; |
| 335 |
| 336 TEST(DeserializeValidModule) { |
| 337 WasmSerializationTest test; |
| 338 HandleScope scope(test.current_isolate()); |
| 339 test.DeserializeAndRun(); |
| 340 } |
| 341 |
| 342 TEST(DeserializeMismatchingVersion) { |
| 343 WasmSerializationTest test; |
| 344 HandleScope scope(test.current_isolate()); |
| 345 test.InvalidateVersion(); |
| 346 test.DeserializeAndRun(); |
| 347 } |
| 348 |
| 349 TEST(DeserializeNoSerializedData) { |
| 350 WasmSerializationTest test; |
| 351 HandleScope scope(test.current_isolate()); |
| 352 test.ClearSerializedData(); |
| 353 test.DeserializeAndRun(); |
| 354 } |
| 355 |
| 356 TEST(DeserializeWireBytesAndSerializedDataInvalid) { |
| 357 WasmSerializationTest test; |
| 358 HandleScope scope(test.current_isolate()); |
| 359 test.InvalidateVersion(); |
| 360 test.InvalidateWireBytes(); |
| 361 test.Deserialize(); |
| 275 } | 362 } |
| 276 | 363 |
| 277 TEST(MemorySize) { | 364 TEST(MemorySize) { |
| 278 // Initial memory size is 16, see wasm-module-builder.cc | 365 // Initial memory size is 16, see wasm-module-builder.cc |
| 279 static const int kExpectedValue = 16; | 366 static const int kExpectedValue = 16; |
| 280 TestSignatures sigs; | 367 TestSignatures sigs; |
| 281 v8::internal::AccountingAllocator allocator; | 368 v8::internal::AccountingAllocator allocator; |
| 282 Zone zone(&allocator, ZONE_NAME); | 369 Zone zone(&allocator, ZONE_NAME); |
| 283 | 370 |
| 284 WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone); | 371 WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone); |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 619 | 706 |
| 620 TEST(Run_WasmModule_Global_f32) { | 707 TEST(Run_WasmModule_Global_f32) { |
| 621 RunWasmModuleGlobalInitTest<float>(kAstF32, -983.9f); | 708 RunWasmModuleGlobalInitTest<float>(kAstF32, -983.9f); |
| 622 RunWasmModuleGlobalInitTest<float>(kAstF32, 1122.99f); | 709 RunWasmModuleGlobalInitTest<float>(kAstF32, 1122.99f); |
| 623 } | 710 } |
| 624 | 711 |
| 625 TEST(Run_WasmModule_Global_f64) { | 712 TEST(Run_WasmModule_Global_f64) { |
| 626 RunWasmModuleGlobalInitTest<double>(kAstF64, -833.9); | 713 RunWasmModuleGlobalInitTest<double>(kAstF64, -833.9); |
| 627 RunWasmModuleGlobalInitTest<double>(kAstF64, 86374.25); | 714 RunWasmModuleGlobalInitTest<double>(kAstF64, 86374.25); |
| 628 } | 715 } |
| OLD | NEW |