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 |