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 3 // found in the LICENSE file. 4 5 #include "src/wasm/wasm-objects.h" 6 #include "src/utils.h" 7 8 #include "src/base/iterator.h" 9 #include "src/debug/debug-interface.h" 10 #include "src/objects-inl.h" 11 #include "src/wasm/module-decoder.h" 12 #include "src/wasm/wasm-module.h" 13 #include "src/wasm/wasm-text.h" 14 15 #define TRACE(...) \ 16 do { \ 17 if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \ 18 } while (false) 19 20 #define TRACE_CHAIN(instance) \ 21 do { \ 22 instance->PrintInstancesChain(); \ 23 } while (false) 24 25 using namespace v8::internal; 26 using namespace v8::internal::wasm; 27 28 #define DEFINE_GETTER0(getter, Container, name, field, type) \ 29 type* Container::name() { return type::cast(getter(field)); } 30 31 #define DEFINE_ACCESSORS0(getter, setter, Container, name, field, type) \ 32 DEFINE_GETTER0(getter, Container, name, field, type) \ 33 void Container::set_##name(type* value) { return setter(field, value); } 34 35 #define DEFINE_OPTIONAL_ACCESSORS0(getter, setter, Container, name, field, \ 36 type) \ 37 DEFINE_ACCESSORS0(getter, setter, Container, name, field, type) \ 38 bool Container::has_##name() { \ 39 return !getter(field)->IsUndefined(GetIsolate()); \ 40 } 41 42 #define DEFINE_OPTIONAL_GETTER0(getter, Container, name, field, type) \ 43 DEFINE_GETTER0(getter, Container, name, field, type) \ 44 bool Container::has_##name() { \ 45 return !getter(field)->IsUndefined(GetIsolate()); \ 46 } 47 48 #define DEFINE_GETTER0(getter, Container, name, field, type) \ 49 type* Container::name() { return type::cast(getter(field)); } 50 51 #define DEFINE_OBJ_GETTER(Container, name, field, type) \ 52 DEFINE_GETTER0(GetInternalField, Container, name, field, type) 53 #define DEFINE_OBJ_ACCESSORS(Container, name, field, type) \ 54 DEFINE_ACCESSORS0(GetInternalField, SetInternalField, Container, name, \ 55 field, type) 56 #define DEFINE_OPTIONAL_OBJ_ACCESSORS(Container, name, field, type) \ 57 DEFINE_OPTIONAL_ACCESSORS0(GetInternalField, SetInternalField, Container, \ 58 name, field, type) 59 #define DEFINE_ARR_GETTER(Container, name, field, type) \ 60 DEFINE_GETTER0(get, Container, name, field, type) 61 #define DEFINE_ARR_ACCESSORS(Container, name, field, type) \ 62 DEFINE_ACCESSORS0(get, set, Container, name, field, type) 63 #define DEFINE_OPTIONAL_ARR_ACCESSORS(Container, name, field, type) \ 64 DEFINE_OPTIONAL_ACCESSORS0(get, set, Container, name, field, type) 65 #define DEFINE_OPTIONAL_ARR_GETTER(Container, name, field, type) \ 66 DEFINE_OPTIONAL_GETTER0(get, Container, name, field, type) 67 68 namespace { 69 70 uint32_t SafeUint32(Object* value) { 71 if (value->IsSmi()) { 72 int32_t val = Smi::cast(value)->value(); 73 CHECK_GE(val, 0); 74 return static_cast<uint32_t>(val); 75 } 76 DCHECK(value->IsHeapNumber()); 77 HeapNumber* num = HeapNumber::cast(value); 78 CHECK_GE(num->value(), 0.0); 79 CHECK_LE(num->value(), kMaxUInt32); 80 return static_cast<uint32_t>(num->value()); 81 } 82 83 int32_t SafeInt32(Object* value) { 84 if (value->IsSmi()) { 85 return Smi::cast(value)->value(); 86 } 87 DCHECK(value->IsHeapNumber()); 88 HeapNumber* num = HeapNumber::cast(value); 89 CHECK_GE(num->value(), Smi::kMinValue); 90 CHECK_LE(num->value(), Smi::kMaxValue); 91 return static_cast<int32_t>(num->value()); 92 } 93 94 // An iterator that returns first the module itself, then all modules linked via 95 // next, then all linked via prev. 96 class CompiledModulesIterator 97 : public std::iterator<std::input_iterator_tag, 98 Handle<WasmCompiledModule>> { 99 public: 100 CompiledModulesIterator(Isolate* isolate, 101 Handle<WasmCompiledModule> start_module, bool at_end) 102 : isolate_(isolate), 103 start_module_(start_module), 104 current_(at_end ? Handle<WasmCompiledModule>::null() : start_module) {} 105 106 Handle<WasmCompiledModule> operator*() const { 107 DCHECK(!current_.is_null()); 108 return current_; 109 } 110 111 void operator++() { Advance(); } 112 113 bool operator!=(const CompiledModulesIterator& other) { 114 DCHECK(start_module_.is_identical_to(other.start_module_)); 115 return !current_.is_identical_to(other.current_); 116 } 117 118 private: 119 void Advance() { 120 DCHECK(!current_.is_null()); 121 if (!is_backwards_) { 122 if (current_->has_weak_next_instance()) { 123 WeakCell* weak_next = current_->ptr_to_weak_next_instance(); 124 if (!weak_next->cleared()) { 125 current_ = 126 handle(WasmCompiledModule::cast(weak_next->value()), isolate_); 127 return; 128 } 129 } 130 // No more modules in next-links, now try the previous-links. 131 is_backwards_ = true; 132 current_ = start_module_; 133 } 134 if (current_->has_weak_prev_instance()) { 135 WeakCell* weak_prev = current_->ptr_to_weak_prev_instance(); 136 if (!weak_prev->cleared()) { 137 current_ = 138 handle(WasmCompiledModule::cast(weak_prev->value()), isolate_); 139 return; 140 } 141 } 142 current_ = Handle<WasmCompiledModule>::null(); 143 } 144 145 friend class CompiledModuleInstancesIterator; 146 Isolate* isolate_; 147 Handle<WasmCompiledModule> start_module_; 148 Handle<WasmCompiledModule> current_; 149 bool is_backwards_ = false; 150 }; 151 152 // An iterator based on the CompiledModulesIterator, but it returns all live 153 // instances, not the WasmCompiledModules itself. 154 class CompiledModuleInstancesIterator 155 : public std::iterator<std::input_iterator_tag, 156 Handle<WasmInstanceObject>> { 157 public: 158 CompiledModuleInstancesIterator(Isolate* isolate, 159 Handle<WasmCompiledModule> start_module, 160 bool at_end) 161 : it(isolate, start_module, at_end) { 162 while (NeedToAdvance()) ++it; 163 } 164 165 Handle<WasmInstanceObject> operator*() { 166 return handle( 167 WasmInstanceObject::cast((*it)->weak_owning_instance()->value()), 168 it.isolate_); 169 } 170 171 void operator++() { 172 do { 173 ++it; 174 } while (NeedToAdvance()); 175 } 176 177 bool operator!=(const CompiledModuleInstancesIterator& other) { 178 return it != other.it; 179 } 180 181 private: 182 bool NeedToAdvance() { 183 return !it.current_.is_null() && 184 (!it.current_->has_weak_owning_instance() || 185 it.current_->ptr_to_weak_owning_instance()->cleared()); 186 } 187 CompiledModulesIterator it; 188 }; 189 190 v8::base::iterator_range<CompiledModuleInstancesIterator> 191 iterate_compiled_module_instance_chain( 192 Isolate* isolate, Handle<WasmCompiledModule> compiled_module) { 193 return {CompiledModuleInstancesIterator(isolate, compiled_module, false), 194 CompiledModuleInstancesIterator(isolate, compiled_module, true)}; 195 } 196 197 #ifdef DEBUG 198 bool IsBreakablePosition(Handle<WasmCompiledModule> compiled_module, 199 int func_index, int offset_in_func) { 200 DisallowHeapAllocation no_gc; 201 AccountingAllocator alloc; 202 Zone tmp(&alloc, ZONE_NAME); 203 BodyLocalDecls locals(&tmp); 204 const byte* module_start = compiled_module->module_bytes()->GetChars(); 205 WasmFunction& func = compiled_module->module()->functions[func_index]; 206 BytecodeIterator iterator(module_start + func.code_start_offset, 207 module_start + func.code_end_offset, &locals); 208 DCHECK_LT(0, locals.encoded_size); 209 for (uint32_t offset : iterator.offsets()) { 210 if (offset > static_cast<uint32_t>(offset_in_func)) break; 211 if (offset == static_cast<uint32_t>(offset_in_func)) return true; 212 } 213 return false; 214 } 215 #endif // DEBUG 216 217 } // namespace 218 219 Handle<WasmModuleObject> WasmModuleObject::New( 220 Isolate* isolate, Handle<WasmCompiledModule> compiled_module) { 221 ModuleOrigin origin = compiled_module->module()->origin; 222 223 Handle<JSObject> module_object; 224 if (origin == ModuleOrigin::kWasmOrigin) { 225 Handle<JSFunction> module_cons( 226 isolate->native_context()->wasm_module_constructor()); 227 module_object = isolate->factory()->NewJSObject(module_cons); 228 Handle<Symbol> module_sym(isolate->native_context()->wasm_module_sym()); 229 Object::SetProperty(module_object, module_sym, module_object, STRICT) 230 .Check(); 231 } else { 232 DCHECK(origin == ModuleOrigin::kAsmJsOrigin); 233 Handle<Map> map = isolate->factory()->NewMap( 234 JS_OBJECT_TYPE, 235 JSObject::kHeaderSize + WasmModuleObject::kFieldCount * kPointerSize); 236 module_object = isolate->factory()->NewJSObjectFromMap(map, TENURED); 237 } 238 module_object->SetInternalField(WasmModuleObject::kCompiledModule, 239 *compiled_module); 240 Handle<WeakCell> link_to_module = 241 isolate->factory()->NewWeakCell(module_object); 242 compiled_module->set_weak_wasm_module(link_to_module); 243 return Handle<WasmModuleObject>::cast(module_object); 244 } 245 246 WasmModuleObject* WasmModuleObject::cast(Object* object) { 247 DCHECK(object->IsJSObject()); 248 // TODO(titzer): brand check for WasmModuleObject. 249 return reinterpret_cast<WasmModuleObject*>(object); 250 } 251 252 bool WasmModuleObject::IsWasmModuleObject(Object* object) { 253 return object->IsJSObject() && 254 JSObject::cast(object)->GetInternalFieldCount() == kFieldCount; 255 } 256 257 DEFINE_OBJ_GETTER(WasmModuleObject, compiled_module, kCompiledModule, 258 WasmCompiledModule) 259 260 Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial, 261 int64_t maximum, 262 Handle<FixedArray>* js_functions) { 263 Handle<JSFunction> table_ctor( 264 isolate->native_context()->wasm_table_constructor()); 265 Handle<JSObject> table_obj = isolate->factory()->NewJSObject(table_ctor); 266 *js_functions = isolate->factory()->NewFixedArray(initial); 267 Object* null = isolate->heap()->null_value(); 268 for (int i = 0; i < static_cast<int>(initial); ++i) { 269 (*js_functions)->set(i, null); 270 } 271 table_obj->SetInternalField(kFunctions, *(*js_functions)); 272 Handle<Object> max = isolate->factory()->NewNumber(maximum); 273 table_obj->SetInternalField(kMaximum, *max); 274 275 Handle<FixedArray> dispatch_tables = isolate->factory()->NewFixedArray(0); 276 table_obj->SetInternalField(kDispatchTables, *dispatch_tables); 277 Handle<Symbol> table_sym(isolate->native_context()->wasm_table_sym()); 278 Object::SetProperty(table_obj, table_sym, table_obj, STRICT).Check(); 279 return Handle<WasmTableObject>::cast(table_obj); 280 } 281 282 DEFINE_OBJ_GETTER(WasmTableObject, dispatch_tables, kDispatchTables, FixedArray) 283 284 Handle<FixedArray> WasmTableObject::AddDispatchTable( 285 Isolate* isolate, Handle<WasmTableObject> table_obj, 286 Handle<WasmInstanceObject> instance, int table_index, 287 Handle<FixedArray> function_table, Handle<FixedArray> signature_table) { 288 Handle<FixedArray> dispatch_tables( 289 FixedArray::cast(table_obj->GetInternalField(kDispatchTables)), isolate); 290 DCHECK_EQ(0, dispatch_tables->length() % 4); 291 292 if (instance.is_null()) return dispatch_tables; 293 // TODO(titzer): use weak cells here to avoid leaking instances. 294 295 // Grow the dispatch table and add a new triple at the end. 296 Handle<FixedArray> new_dispatch_tables = 297 isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables, 4); 298 299 new_dispatch_tables->set(dispatch_tables->length() + 0, *instance); 300 new_dispatch_tables->set(dispatch_tables->length() + 1, 301 Smi::FromInt(table_index)); 302 new_dispatch_tables->set(dispatch_tables->length() + 2, *function_table); 303 new_dispatch_tables->set(dispatch_tables->length() + 3, *signature_table); 304 305 table_obj->SetInternalField(WasmTableObject::kDispatchTables, 306 *new_dispatch_tables); 307 308 return new_dispatch_tables; 309 } 310 311 DEFINE_OBJ_ACCESSORS(WasmTableObject, functions, kFunctions, FixedArray) 312 313 uint32_t WasmTableObject::current_length() { return functions()->length(); } 314 315 bool WasmTableObject::has_maximum_length() { 316 return GetInternalField(kMaximum)->Number() >= 0; 317 } 318 319 int64_t WasmTableObject::maximum_length() { 320 return static_cast<int64_t>(GetInternalField(kMaximum)->Number()); 321 } 322 323 WasmTableObject* WasmTableObject::cast(Object* object) { 324 DCHECK(object && object->IsJSObject()); 325 // TODO(titzer): brand check for WasmTableObject. 326 return reinterpret_cast<WasmTableObject*>(object); 327 } 328 329 void WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table, 330 uint32_t count) { 331 Handle<FixedArray> dispatch_tables(table->dispatch_tables()); 332 wasm::GrowDispatchTables(isolate, dispatch_tables, 333 table->functions()->length(), count); 334 } 335 336 Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate, 337 Handle<JSArrayBuffer> buffer, 338 int32_t maximum) { 339 Handle<JSFunction> memory_ctor( 340 isolate->native_context()->wasm_memory_constructor()); 341 Handle<JSObject> memory_obj = 342 isolate->factory()->NewJSObject(memory_ctor, TENURED); 343 memory_obj->SetInternalField(kArrayBuffer, *buffer); 344 Handle<Object> max = isolate->factory()->NewNumber(maximum); 345 memory_obj->SetInternalField(kMaximum, *max); 346 Handle<Symbol> memory_sym(isolate->native_context()->wasm_memory_sym()); 347 Object::SetProperty(memory_obj, memory_sym, memory_obj, STRICT).Check(); 348 return Handle<WasmMemoryObject>::cast(memory_obj); 349 } 350 351 DEFINE_OBJ_ACCESSORS(WasmMemoryObject, buffer, kArrayBuffer, JSArrayBuffer) 352 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmMemoryObject, instances_link, kInstancesLink, 353 WasmInstanceWrapper) 354 355 uint32_t WasmMemoryObject::current_pages() { 356 return SafeUint32(buffer()->byte_length()) / wasm::WasmModule::kPageSize; 357 } 358 359 bool WasmMemoryObject::has_maximum_pages() { 360 return GetInternalField(kMaximum)->Number() >= 0; 361 } 362 363 int32_t WasmMemoryObject::maximum_pages() { 364 return static_cast<int32_t>(GetInternalField(kMaximum)->Number()); 365 } 366 367 WasmMemoryObject* WasmMemoryObject::cast(Object* object) { 368 DCHECK(object && object->IsJSObject()); 369 // TODO(titzer): brand check for WasmMemoryObject. 370 return reinterpret_cast<WasmMemoryObject*>(object); 371 } 372 373 void WasmMemoryObject::AddInstance(Isolate* isolate, 374 Handle<WasmInstanceObject> instance) { 375 Handle<WasmInstanceWrapper> instance_wrapper = 376 handle(instance->instance_wrapper()); 377 if (has_instances_link()) { 378 Handle<WasmInstanceWrapper> current_wrapper(instances_link()); 379 DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*current_wrapper)); 380 DCHECK(!current_wrapper->has_previous()); 381 instance_wrapper->set_next_wrapper(*current_wrapper); 382 current_wrapper->set_previous_wrapper(*instance_wrapper); 383 } 384 set_instances_link(*instance_wrapper); 385 } 386 387 void WasmMemoryObject::ResetInstancesLink(Isolate* isolate) { 388 Handle<Object> undefined = isolate->factory()->undefined_value(); 389 SetInternalField(kInstancesLink, *undefined); 390 } 391 392 DEFINE_OBJ_ACCESSORS(WasmInstanceObject, compiled_module, kCompiledModule, 393 WasmCompiledModule) 394 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, globals_buffer, 395 kGlobalsArrayBuffer, JSArrayBuffer) 396 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_buffer, 397 kMemoryArrayBuffer, JSArrayBuffer) 398 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_object, kMemoryObject, 399 WasmMemoryObject) 400 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, debug_info, kDebugInfo, 401 WasmDebugInfo) 402 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, instance_wrapper, 403 kWasmMemInstanceWrapper, WasmInstanceWrapper) 404 405 WasmModuleObject* WasmInstanceObject::module_object() { 406 return *compiled_module()->wasm_module(); 407 } 408 409 WasmModule* WasmInstanceObject::module() { return compiled_module()->module(); } 410 411 Handle<WasmDebugInfo> WasmInstanceObject::GetOrCreateDebugInfo( 412 Handle<WasmInstanceObject> instance) { 413 if (instance->has_debug_info()) return handle(instance->debug_info()); 414 Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(instance); 415 instance->set_debug_info(*new_info); 416 return new_info; 417 } 418 419 WasmInstanceObject* WasmInstanceObject::cast(Object* object) { 420 DCHECK(IsWasmInstanceObject(object)); 421 return reinterpret_cast<WasmInstanceObject*>(object); 422 } 423 424 bool WasmInstanceObject::IsWasmInstanceObject(Object* object) { 425 if (!object->IsJSObject()) return false; 426 427 JSObject* obj = JSObject::cast(object); 428 Isolate* isolate = obj->GetIsolate(); 429 if (obj->GetInternalFieldCount() != kFieldCount) { 430 return false; 431 } 432 433 Object* mem = obj->GetInternalField(kMemoryArrayBuffer); 434 if (!(mem->IsUndefined(isolate) || mem->IsJSArrayBuffer()) || 435 !WasmCompiledModule::IsWasmCompiledModule( 436 obj->GetInternalField(kCompiledModule))) { 437 return false; 438 } 439 440 // All checks passed. 441 return true; 442 } 443 444 Handle<WasmInstanceObject> WasmInstanceObject::New( 445 Isolate* isolate, Handle<WasmCompiledModule> compiled_module) { 446 Handle<JSFunction> instance_cons( 447 isolate->native_context()->wasm_instance_constructor()); 448 Handle<JSObject> instance_object = 449 isolate->factory()->NewJSObject(instance_cons, TENURED); 450 Handle<Symbol> instance_sym(isolate->native_context()->wasm_instance_sym()); 451 Object::SetProperty(instance_object, instance_sym, instance_object, STRICT) 452 .Check(); 453 Handle<WasmInstanceObject> instance( 454 reinterpret_cast<WasmInstanceObject*>(*instance_object), isolate); 455 456 instance->SetInternalField(kCompiledModule, *compiled_module); 457 instance->SetInternalField(kMemoryObject, isolate->heap()->undefined_value()); 458 Handle<WasmInstanceWrapper> instance_wrapper = 459 WasmInstanceWrapper::New(isolate, instance); 460 instance->SetInternalField(kWasmMemInstanceWrapper, *instance_wrapper); 461 return instance; 462 } 463 464 WasmInstanceObject* WasmExportedFunction::instance() { 465 return WasmInstanceObject::cast(GetInternalField(kInstance)); 466 } 467 468 int WasmExportedFunction::function_index() { 469 return SafeInt32(GetInternalField(kIndex)); 470 } 471 472 WasmExportedFunction* WasmExportedFunction::cast(Object* object) { 473 DCHECK(object && object->IsJSFunction()); 474 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, 475 JSFunction::cast(object)->code()->kind()); 476 // TODO(titzer): brand check for WasmExportedFunction. 477 return reinterpret_cast<WasmExportedFunction*>(object); 478 } 479 480 Handle<WasmExportedFunction> WasmExportedFunction::New( 481 Isolate* isolate, Handle<WasmInstanceObject> instance, 482 MaybeHandle<String> maybe_name, int func_index, int arity, 483 Handle<Code> export_wrapper) { 484 Handle<String> name; 485 if (maybe_name.is_null()) { 486 EmbeddedVector<char, 16> buffer; 487 int length = SNPrintF(buffer, "%d", func_index); 488 name = isolate->factory() 489 ->NewStringFromAscii( 490 Vector<const char>::cast(buffer.SubVector(0, length))) 491 .ToHandleChecked(); 492 } else { 493 name = maybe_name.ToHandleChecked(); 494 } 495 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind()); 496 Handle<SharedFunctionInfo> shared = 497 isolate->factory()->NewSharedFunctionInfo(name, export_wrapper, false); 498 shared->set_length(arity); 499 shared->set_internal_formal_parameter_count(arity); 500 Handle<JSFunction> function = isolate->factory()->NewFunction( 501 isolate->wasm_function_map(), name, export_wrapper); 502 function->set_shared(*shared); 503 504 function->SetInternalField(kInstance, *instance); 505 function->SetInternalField(kIndex, Smi::FromInt(func_index)); 506 return Handle<WasmExportedFunction>::cast(function); 507 } 508 509 bool WasmSharedModuleData::IsWasmSharedModuleData(Object* object) { 510 if (!object->IsFixedArray()) return false; 511 FixedArray* arr = FixedArray::cast(object); 512 if (arr->length() != kFieldCount) return false; 513 Isolate* isolate = arr->GetIsolate(); 514 if (!arr->get(kModuleWrapper)->IsForeign()) return false; 515 if (!arr->get(kModuleBytes)->IsUndefined(isolate) && 516 !arr->get(kModuleBytes)->IsSeqOneByteString()) 517 return false; 518 if (!arr->get(kScript)->IsScript()) return false; 519 if (!arr->get(kAsmJsOffsetTable)->IsUndefined(isolate) && 520 !arr->get(kAsmJsOffsetTable)->IsByteArray()) 521 return false; 522 if (!arr->get(kBreakPointInfos)->IsUndefined(isolate) && 523 !arr->get(kBreakPointInfos)->IsFixedArray()) 524 return false; 525 return true; 526 } 527 528 WasmSharedModuleData* WasmSharedModuleData::cast(Object* object) { 529 DCHECK(IsWasmSharedModuleData(object)); 530 return reinterpret_cast<WasmSharedModuleData*>(object); 531 } 532 533 wasm::WasmModule* WasmSharedModuleData::module() { 534 // We populate the kModuleWrapper field with a Foreign holding the 535 // address to the address of a WasmModule. This is because we can 536 // handle both cases when the WasmModule's lifetime is managed through 537 // a Managed<WasmModule> object, as well as cases when it's managed 538 // by the embedder. CcTests fall into the latter case. 539 return *(reinterpret_cast<wasm::WasmModule**>( 540 Foreign::cast(get(kModuleWrapper))->foreign_address())); 541 } 542 543 DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, module_bytes, kModuleBytes, 544 SeqOneByteString); 545 DEFINE_ARR_GETTER(WasmSharedModuleData, script, kScript, Script); 546 DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, asm_js_offset_table, 547 kAsmJsOffsetTable, ByteArray); 548 DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, breakpoint_infos, 549 kBreakPointInfos, FixedArray); 550 551 Handle<WasmSharedModuleData> WasmSharedModuleData::New( 552 Isolate* isolate, Handle<Foreign> module_wrapper, 553 Handle<SeqOneByteString> module_bytes, Handle<Script> script, 554 Handle<ByteArray> asm_js_offset_table) { 555 Handle<FixedArray> arr = 556 isolate->factory()->NewFixedArray(kFieldCount, TENURED); 557 558 arr->set(kModuleWrapper, *module_wrapper); 559 if (!module_bytes.is_null()) { 560 arr->set(kModuleBytes, *module_bytes); 561 } 562 if (!script.is_null()) { 563 arr->set(kScript, *script); 564 } 565 if (!asm_js_offset_table.is_null()) { 566 arr->set(kAsmJsOffsetTable, *asm_js_offset_table); 567 } 568 569 DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*arr)); 570 return Handle<WasmSharedModuleData>::cast(arr); 571 } 572 573 bool WasmSharedModuleData::is_asm_js() { 574 bool asm_js = module()->origin == wasm::ModuleOrigin::kAsmJsOrigin; 575 DCHECK_EQ(asm_js, script()->type() == Script::TYPE_NORMAL); 576 DCHECK_EQ(asm_js, has_asm_js_offset_table()); 577 return asm_js; 578 } 579 580 void WasmSharedModuleData::ReinitializeAfterDeserialization( 581 Isolate* isolate, Handle<WasmSharedModuleData> shared) { 582 DCHECK(shared->get(kModuleWrapper)->IsUndefined(isolate)); 583 #ifdef DEBUG 584 // No BreakpointInfo objects should survive deserialization. 585 if (shared->has_breakpoint_infos()) { 586 for (int i = 0, e = shared->breakpoint_infos()->length(); i < e; ++i) { 587 DCHECK(shared->breakpoint_infos()->get(i)->IsUndefined(isolate)); 588 } 589 } 590 #endif 591 592 shared->set(kBreakPointInfos, isolate->heap()->undefined_value()); 593 594 WasmModule* module = nullptr; 595 { 596 // We parse the module again directly from the module bytes, so 597 // the underlying storage must not be moved meanwhile. 598 DisallowHeapAllocation no_allocation; 599 SeqOneByteString* module_bytes = shared->module_bytes(); 600 const byte* start = 601 reinterpret_cast<const byte*>(module_bytes->GetCharsAddress()); 602 const byte* end = start + module_bytes->length(); 603 // TODO(titzer): remember the module origin in the compiled_module 604 // For now, we assume serialized modules did not originate from asm.js. 605 ModuleResult result = 606 DecodeWasmModule(isolate, start, end, false, kWasmOrigin); 607 CHECK(result.ok()); 608 CHECK_NOT_NULL(result.val); 609 module = const_cast<WasmModule*>(result.val); 610 } 611 612 Handle<WasmModuleWrapper> module_wrapper = 613 WasmModuleWrapper::New(isolate, module); 614 615 shared->set(kModuleWrapper, *module_wrapper); 616 DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared)); 617 } 618 619 namespace { 620 621 int GetBreakpointPos(Isolate* isolate, Object* break_point_info_or_undef) { 622 if (break_point_info_or_undef->IsUndefined(isolate)) return kMaxInt; 623 return BreakPointInfo::cast(break_point_info_or_undef)->source_position(); 624 } 625 626 int FindBreakpointInfoInsertPos(Isolate* isolate, 627 Handle<FixedArray> breakpoint_infos, 628 int position) { 629 // Find insert location via binary search, taking care of undefined values on 630 // the right. Position is always greater than zero. 631 DCHECK_LT(0, position); 632 633 int left = 0; // inclusive 634 int right = breakpoint_infos->length(); // exclusive 635 while (right - left > 1) { 636 int mid = left + (right - left) / 2; 637 Object* mid_obj = breakpoint_infos->get(mid); 638 if (GetBreakpointPos(isolate, mid_obj) <= position) { 639 left = mid; 640 } else { 641 right = mid; 642 } 643 } 644 645 int left_pos = GetBreakpointPos(isolate, breakpoint_infos->get(left)); 646 return left_pos < position ? left + 1 : left; 647 } 648 649 } // namespace 650 651 void WasmSharedModuleData::AddBreakpoint(Handle<WasmSharedModuleData> shared, 652 int position, 653 Handle<Object> break_point_object) { 654 Isolate* isolate = shared->GetIsolate(); 655 Handle<FixedArray> breakpoint_infos; 656 if (shared->has_breakpoint_infos()) { 657 breakpoint_infos = handle(shared->breakpoint_infos(), isolate); 658 } else { 659 breakpoint_infos = isolate->factory()->NewFixedArray(4, TENURED); 660 shared->set(kBreakPointInfos, *breakpoint_infos); 661 } 662 663 int insert_pos = 664 FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position); 665 666 // If a BreakPointInfo object already exists for this position, add the new 667 // breakpoint object and return. 668 if (insert_pos < breakpoint_infos->length() && 669 GetBreakpointPos(isolate, breakpoint_infos->get(insert_pos)) == 670 position) { 671 Handle<BreakPointInfo> old_info( 672 BreakPointInfo::cast(breakpoint_infos->get(insert_pos)), isolate); 673 BreakPointInfo::SetBreakPoint(old_info, break_point_object); 674 return; 675 } 676 677 // Enlarge break positions array if necessary. 678 bool need_realloc = !breakpoint_infos->get(breakpoint_infos->length() - 1) 679 ->IsUndefined(isolate); 680 Handle<FixedArray> new_breakpoint_infos = breakpoint_infos; 681 if (need_realloc) { 682 new_breakpoint_infos = isolate->factory()->NewFixedArray( 683 2 * breakpoint_infos->length(), TENURED); 684 shared->set(kBreakPointInfos, *new_breakpoint_infos); 685 // Copy over the entries [0, insert_pos). 686 for (int i = 0; i < insert_pos; ++i) 687 new_breakpoint_infos->set(i, breakpoint_infos->get(i)); 688 } 689 690 // Move elements [insert_pos+1, ...] up by one. 691 for (int i = insert_pos + 1; i < breakpoint_infos->length(); ++i) { 692 Object* entry = breakpoint_infos->get(i); 693 if (entry->IsUndefined(isolate)) break; 694 new_breakpoint_infos->set(i + 1, entry); 695 } 696 697 // Generate new BreakpointInfo. 698 Handle<BreakPointInfo> breakpoint_info = 699 isolate->factory()->NewBreakPointInfo(position); 700 BreakPointInfo::SetBreakPoint(breakpoint_info, break_point_object); 701 702 // Now insert new position at insert_pos. 703 new_breakpoint_infos->set(insert_pos, *breakpoint_info); 704 } 705 706 void WasmSharedModuleData::SetBreakpointsOnNewInstance( 707 Handle<WasmSharedModuleData> shared, Handle<WasmInstanceObject> instance) { 708 if (!shared->has_breakpoint_infos()) return; 709 Isolate* isolate = shared->GetIsolate(); 710 Handle<WasmCompiledModule> compiled_module(instance->compiled_module(), 711 isolate); 712 Handle<WasmDebugInfo> debug_info = 713 WasmInstanceObject::GetOrCreateDebugInfo(instance); 714 715 Handle<FixedArray> breakpoint_infos(shared->breakpoint_infos(), isolate); 716 // If the array exists, it should not be empty. 717 DCHECK_LT(0, breakpoint_infos->length()); 718 719 for (int i = 0, e = breakpoint_infos->length(); i < e; ++i) { 720 Handle<Object> obj(breakpoint_infos->get(i), isolate); 721 if (obj->IsUndefined(isolate)) { 722 for (; i < e; ++i) { 723 DCHECK(breakpoint_infos->get(i)->IsUndefined(isolate)); 724 } 725 break; 726 } 727 Handle<BreakPointInfo> breakpoint_info = Handle<BreakPointInfo>::cast(obj); 728 int position = breakpoint_info->source_position(); 729 730 // Find the function for this breakpoint, and set the breakpoint. 731 int func_index = compiled_module->GetContainingFunction(position); 732 DCHECK_LE(0, func_index); 733 WasmFunction& func = compiled_module->module()->functions[func_index]; 734 int offset_in_func = position - func.code_start_offset; 735 WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func); 736 } 737 } 738 739 Handle<WasmCompiledModule> WasmCompiledModule::New( 740 Isolate* isolate, Handle<WasmSharedModuleData> shared) { 741 Handle<FixedArray> ret = 742 isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED); 743 // WasmCompiledModule::cast would fail since fields are not set yet. 744 Handle<WasmCompiledModule> compiled_module( 745 reinterpret_cast<WasmCompiledModule*>(*ret), isolate); 746 compiled_module->InitId(); 747 compiled_module->set_num_imported_functions(0); 748 compiled_module->set_shared(shared); 749 compiled_module->set_native_context(isolate->native_context()); 750 return compiled_module; 751 } 752 753 void WasmCompiledModule::InitId() { 754 #if DEBUG 755 static uint32_t instance_id_counter = 0; 756 set(kID_instance_id, Smi::FromInt(instance_id_counter++)); 757 TRACE("New compiled module id: %d\n", instance_id()); 758 #endif 759 } 760 761 MaybeHandle<String> WasmCompiledModule::ExtractUtf8StringFromModuleBytes( 762 Isolate* isolate, Handle<WasmCompiledModule> compiled_module, 763 uint32_t offset, uint32_t size) { 764 // TODO(wasm): cache strings from modules if it's a performance win. 765 Handle<SeqOneByteString> module_bytes(compiled_module->module_bytes(), 766 isolate); 767 DCHECK_GE(module_bytes->length(), offset); 768 DCHECK_GE(module_bytes->length() - offset, size); 769 Address raw = module_bytes->GetCharsAddress() + offset; 770 if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size)) 771 return {}; // UTF8 decoding error for name. 772 DCHECK_GE(kMaxInt, offset); 773 DCHECK_GE(kMaxInt, size); 774 return isolate->factory()->NewStringFromUtf8SubString( 775 module_bytes, static_cast<int>(offset), static_cast<int>(size)); 776 } 777 778 bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) { 779 if (!obj->IsFixedArray()) return false; 780 FixedArray* arr = FixedArray::cast(obj); 781 if (arr->length() != PropertyIndices::Count) return false; 782 Isolate* isolate = arr->GetIsolate(); 783 #define WCM_CHECK_TYPE(NAME, TYPE_CHECK) \ 784 do { \ 785 Object* obj = arr->get(kID_##NAME); \ 786 if (!(TYPE_CHECK)) return false; \ 787 } while (false); 788 #define WCM_CHECK_OBJECT(TYPE, NAME) \ 789 WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->Is##TYPE()) 790 #define WCM_CHECK_WASM_OBJECT(TYPE, NAME) \ 791 WCM_CHECK_TYPE(NAME, TYPE::Is##TYPE(obj)) 792 #define WCM_CHECK_WEAK_LINK(TYPE, NAME) WCM_CHECK_OBJECT(WeakCell, NAME) 793 #define WCM_CHECK_SMALL_NUMBER(TYPE, NAME) WCM_CHECK_TYPE(NAME, obj->IsSmi()) 794 #define WCM_CHECK(KIND, TYPE, NAME) WCM_CHECK_##KIND(TYPE, NAME) 795 WCM_PROPERTY_TABLE(WCM_CHECK) 796 #undef WCM_CHECK 797 798 // All checks passed. 799 return true; 800 } 801 802 void WasmCompiledModule::PrintInstancesChain() { 803 #if DEBUG 804 if (!FLAG_trace_wasm_instances) return; 805 for (WasmCompiledModule* current = this; current != nullptr;) { 806 PrintF("->%d", current->instance_id()); 807 if (!current->has_weak_next_instance()) break; 808 CHECK(!current->ptr_to_weak_next_instance()->cleared()); 809 current = 810 WasmCompiledModule::cast(current->ptr_to_weak_next_instance()->value()); 811 } 812 PrintF("\n"); 813 #endif 814 } 815 816 void WasmCompiledModule::ReinitializeAfterDeserialization( 817 Isolate* isolate, Handle<WasmCompiledModule> compiled_module) { 818 // This method must only be called immediately after deserialization. 819 // At this point, no module wrapper exists, so the shared module data is 820 // incomplete. 821 Handle<WasmSharedModuleData> shared( 822 static_cast<WasmSharedModuleData*>(compiled_module->get(kID_shared)), 823 isolate); 824 DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared)); 825 WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared); 826 DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared)); 827 } 828 829 uint32_t WasmCompiledModule::mem_size() const { 830 return has_memory() ? memory()->byte_length()->Number() : default_mem_size(); 831 } 832 833 uint32_t WasmCompiledModule::default_mem_size() const { 834 return min_mem_pages() * WasmModule::kPageSize; 835 } 836 837 MaybeHandle<String> WasmCompiledModule::GetFunctionNameOrNull( 838 Isolate* isolate, Handle<WasmCompiledModule> compiled_module, 839 uint32_t func_index) { 840 DCHECK_LT(func_index, compiled_module->module()->functions.size()); 841 WasmFunction& function = compiled_module->module()->functions[func_index]; 842 return WasmCompiledModule::ExtractUtf8StringFromModuleBytes( 843 isolate, compiled_module, function.name_offset, function.name_length); 844 } 845 846 Handle<String> WasmCompiledModule::GetFunctionName( 847 Isolate* isolate, Handle<WasmCompiledModule> compiled_module, 848 uint32_t func_index) { 849 MaybeHandle<String> name = 850 GetFunctionNameOrNull(isolate, compiled_module, func_index); 851 if (!name.is_null()) return name.ToHandleChecked(); 852 return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>"); 853 } 854 855 Vector<const uint8_t> WasmCompiledModule::GetRawFunctionName( 856 uint32_t func_index) { 857 DCHECK_GT(module()->functions.size(), func_index); 858 WasmFunction& function = module()->functions[func_index]; 859 SeqOneByteString* bytes = module_bytes(); 860 DCHECK_GE(bytes->length(), function.name_offset); 861 DCHECK_GE(bytes->length() - function.name_offset, function.name_length); 862 return Vector<const uint8_t>(bytes->GetCharsAddress() + function.name_offset, 863 function.name_length); 864 } 865 866 int WasmCompiledModule::GetFunctionOffset(uint32_t func_index) { 867 std::vector<WasmFunction>& functions = module()->functions; 868 if (static_cast<uint32_t>(func_index) >= functions.size()) return -1; 869 DCHECK_GE(kMaxInt, functions[func_index].code_start_offset); 870 return static_cast<int>(functions[func_index].code_start_offset); 871 } 872 873 int WasmCompiledModule::GetContainingFunction(uint32_t byte_offset) { 874 std::vector<WasmFunction>& functions = module()->functions; 875 876 // Binary search for a function containing the given position. 877 int left = 0; // inclusive 878 int right = static_cast<int>(functions.size()); // exclusive 879 if (right == 0) return false; 880 while (right - left > 1) { 881 int mid = left + (right - left) / 2; 882 if (functions[mid].code_start_offset <= byte_offset) { 883 left = mid; 884 } else { 885 right = mid; 886 } 887 } 888 // If the found function does not contains the given position, return -1. 889 WasmFunction& func = functions[left]; 890 if (byte_offset < func.code_start_offset || 891 byte_offset >= func.code_end_offset) { 892 return -1; 893 } 894 895 return left; 896 } 897 898 bool WasmCompiledModule::GetPositionInfo(uint32_t position, 899 Script::PositionInfo* info) { 900 int func_index = GetContainingFunction(position); 901 if (func_index < 0) return false; 902 903 WasmFunction& function = module()->functions[func_index]; 904 905 info->line = func_index; 906 info->column = position - function.code_start_offset; 907 info->line_start = function.code_start_offset; 908 info->line_end = function.code_end_offset; 909 return true; 910 } 911 912 namespace { 913 914 enum AsmJsOffsetTableEntryLayout { 915 kOTEByteOffset, 916 kOTECallPosition, 917 kOTENumberConvPosition, 918 kOTESize 919 }; 920 921 Handle<ByteArray> GetDecodedAsmJsOffsetTable( 922 Handle<WasmCompiledModule> compiled_module, Isolate* isolate) { 923 DCHECK(compiled_module->is_asm_js()); 924 Handle<ByteArray> offset_table( 925 compiled_module->shared()->asm_js_offset_table(), isolate); 926 927 // The last byte in the asm_js_offset_tables ByteArray tells whether it is 928 // still encoded (0) or decoded (1). 929 enum AsmJsTableType : int { Encoded = 0, Decoded = 1 }; 930 int table_type = offset_table->get(offset_table->length() - 1); 931 DCHECK(table_type == Encoded || table_type == Decoded); 932 if (table_type == Decoded) return offset_table; 933 934 AsmJsOffsetsResult asm_offsets; 935 { 936 DisallowHeapAllocation no_gc; 937 const byte* bytes_start = offset_table->GetDataStartAddress(); 938 const byte* bytes_end = bytes_start + offset_table->length() - 1; 939 asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end); 940 } 941 // Wasm bytes must be valid and must contain asm.js offset table. 942 DCHECK(asm_offsets.ok()); 943 DCHECK_GE(kMaxInt, asm_offsets.val.size()); 944 int num_functions = static_cast<int>(asm_offsets.val.size()); 945 int num_imported_functions = 946 static_cast<int>(compiled_module->module()->num_imported_functions); 947 DCHECK_EQ(compiled_module->module()->functions.size(), 948 static_cast<size_t>(num_functions) + num_imported_functions); 949 int num_entries = 0; 950 for (int func = 0; func < num_functions; ++func) { 951 size_t new_size = asm_offsets.val[func].size(); 952 DCHECK_LE(new_size, static_cast<size_t>(kMaxInt) - num_entries); 953 num_entries += static_cast<int>(new_size); 954 } 955 // One byte to encode that this is a decoded table. 956 DCHECK_GE(kMaxInt, 957 1 + static_cast<uint64_t>(num_entries) * kOTESize * kIntSize); 958 int total_size = 1 + num_entries * kOTESize * kIntSize; 959 Handle<ByteArray> decoded_table = 960 isolate->factory()->NewByteArray(total_size, TENURED); 961 decoded_table->set(total_size - 1, AsmJsTableType::Decoded); 962 compiled_module->shared()->set_asm_js_offset_table(*decoded_table); 963 964 int idx = 0; 965 std::vector<WasmFunction>& wasm_funs = compiled_module->module()->functions; 966 for (int func = 0; func < num_functions; ++func) { 967 std::vector<AsmJsOffsetEntry>& func_asm_offsets = asm_offsets.val[func]; 968 if (func_asm_offsets.empty()) continue; 969 int func_offset = 970 wasm_funs[num_imported_functions + func].code_start_offset; 971 for (AsmJsOffsetEntry& e : func_asm_offsets) { 972 // Byte offsets must be strictly monotonously increasing: 973 DCHECK_IMPLIES(idx > 0, func_offset + e.byte_offset > 974 decoded_table->get_int(idx - kOTESize)); 975 decoded_table->set_int(idx + kOTEByteOffset, func_offset + e.byte_offset); 976 decoded_table->set_int(idx + kOTECallPosition, e.source_position_call); 977 decoded_table->set_int(idx + kOTENumberConvPosition, 978 e.source_position_number_conversion); 979 idx += kOTESize; 980 } 981 } 982 DCHECK_EQ(total_size, idx * kIntSize + 1); 983 return decoded_table; 984 } 985 986 } // namespace 987 988 int WasmCompiledModule::GetAsmJsSourcePosition( 989 Handle<WasmCompiledModule> compiled_module, uint32_t func_index, 990 uint32_t byte_offset, bool is_at_number_conversion) { 991 Isolate* isolate = compiled_module->GetIsolate(); 992 Handle<ByteArray> offset_table = 993 GetDecodedAsmJsOffsetTable(compiled_module, isolate); 994 995 DCHECK_LT(func_index, compiled_module->module()->functions.size()); 996 uint32_t func_code_offset = 997 compiled_module->module()->functions[func_index].code_start_offset; 998 uint32_t total_offset = func_code_offset + byte_offset; 999 1000 // Binary search for the total byte offset. 1001 int left = 0; // inclusive 1002 int right = offset_table->length() / kIntSize / kOTESize; // exclusive 1003 DCHECK_LT(left, right); 1004 while (right - left > 1) { 1005 int mid = left + (right - left) / 2; 1006 int mid_entry = offset_table->get_int(kOTESize * mid); 1007 DCHECK_GE(kMaxInt, mid_entry); 1008 if (static_cast<uint32_t>(mid_entry) <= total_offset) { 1009 left = mid; 1010 } else { 1011 right = mid; 1012 } 1013 } 1014 // There should be an entry for each position that could show up on the stack 1015 // trace: 1016 DCHECK_EQ(total_offset, offset_table->get_int(kOTESize * left)); 1017 int idx = is_at_number_conversion ? kOTENumberConvPosition : kOTECallPosition; 1018 return offset_table->get_int(kOTESize * left + idx); 1019 } 1020 1021 v8::debug::WasmDisassembly WasmCompiledModule::DisassembleFunction( 1022 int func_index) { 1023 DisallowHeapAllocation no_gc; 1024 1025 if (func_index < 0 || 1026 static_cast<uint32_t>(func_index) >= module()->functions.size()) 1027 return {}; 1028 1029 SeqOneByteString* module_bytes_str = module_bytes(); 1030 Vector<const byte> module_bytes(module_bytes_str->GetChars(), 1031 module_bytes_str->length()); 1032 1033 std::ostringstream disassembly_os; 1034 v8::debug::WasmDisassembly::OffsetTable offset_table; 1035 1036 PrintWasmText(module(), module_bytes, static_cast<uint32_t>(func_index), 1037 disassembly_os, &offset_table); 1038 1039 return {disassembly_os.str(), std::move(offset_table)}; 1040 } 1041 1042 bool WasmCompiledModule::GetPossibleBreakpoints( 1043 const v8::debug::Location& start, const v8::debug::Location& end, 1044 std::vector<v8::debug::Location>* locations) { 1045 DisallowHeapAllocation no_gc; 1046 1047 std::vector<WasmFunction>& functions = module()->functions; 1048 if (start.GetLineNumber() < 0 || start.GetColumnNumber() < 0 || 1049 (!end.IsEmpty() && 1050 (end.GetLineNumber() < 0 || end.GetColumnNumber() < 0))) 1051 return false; 1052 1053 // start_func_index, start_offset and end_func_index is inclusive. 1054 // end_offset is exclusive. 1055 // start_offset and end_offset are module-relative byte offsets. 1056 uint32_t start_func_index = start.GetLineNumber(); 1057 if (start_func_index >= functions.size()) return false; 1058 int start_func_len = functions[start_func_index].code_end_offset - 1059 functions[start_func_index].code_start_offset; 1060 if (start.GetColumnNumber() > start_func_len) return false; 1061 uint32_t start_offset = 1062 functions[start_func_index].code_start_offset + start.GetColumnNumber(); 1063 uint32_t end_func_index; 1064 uint32_t end_offset; 1065 if (end.IsEmpty()) { 1066 // Default: everything till the end of the Script. 1067 end_func_index = static_cast<uint32_t>(functions.size() - 1); 1068 end_offset = functions[end_func_index].code_end_offset; 1069 } else { 1070 // If end is specified: Use it and check for valid input. 1071 end_func_index = static_cast<uint32_t>(end.GetLineNumber()); 1072 1073 // Special case: Stop before the start of the next function. Change to: Stop 1074 // at the end of the function before, such that we don't disassemble the 1075 // next function also. 1076 if (end.GetColumnNumber() == 0 && end_func_index > 0) { 1077 --end_func_index; 1078 end_offset = functions[end_func_index].code_end_offset; 1079 } else { 1080 if (end_func_index >= functions.size()) return false; 1081 end_offset = 1082 functions[end_func_index].code_start_offset + end.GetColumnNumber(); 1083 if (end_offset > functions[end_func_index].code_end_offset) return false; 1084 } 1085 } 1086 1087 AccountingAllocator alloc; 1088 Zone tmp(&alloc, ZONE_NAME); 1089 const byte* module_start = module_bytes()->GetChars(); 1090 1091 for (uint32_t func_idx = start_func_index; func_idx <= end_func_index; 1092 ++func_idx) { 1093 WasmFunction& func = functions[func_idx]; 1094 if (func.code_start_offset == func.code_end_offset) continue; 1095 1096 BodyLocalDecls locals(&tmp); 1097 BytecodeIterator iterator(module_start + func.code_start_offset, 1098 module_start + func.code_end_offset, &locals); 1099 DCHECK_LT(0u, locals.encoded_size); 1100 for (uint32_t offset : iterator.offsets()) { 1101 uint32_t total_offset = func.code_start_offset + offset; 1102 if (total_offset >= end_offset) { 1103 DCHECK_EQ(end_func_index, func_idx); 1104 break; 1105 } 1106 if (total_offset < start_offset) continue; 1107 locations->push_back(v8::debug::Location(func_idx, offset)); 1108 } 1109 } 1110 return true; 1111 } 1112 1113 bool WasmCompiledModule::SetBreakPoint( 1114 Handle<WasmCompiledModule> compiled_module, int* position, 1115 Handle<Object> break_point_object) { 1116 Isolate* isolate = compiled_module->GetIsolate(); 1117 1118 // Find the function for this breakpoint. 1119 int func_index = compiled_module->GetContainingFunction(*position); 1120 if (func_index < 0) return false; 1121 WasmFunction& func = compiled_module->module()->functions[func_index]; 1122 int offset_in_func = *position - func.code_start_offset; 1123 1124 // According to the current design, we should only be called with valid 1125 // breakable positions. 1126 DCHECK(IsBreakablePosition(compiled_module, func_index, offset_in_func)); 1127 1128 // Insert new break point into break_positions of shared module data. 1129 WasmSharedModuleData::AddBreakpoint(compiled_module->shared(), *position, 1130 break_point_object); 1131 1132 // Iterate over all instances of this module and tell them to set this new 1133 // breakpoint. 1134 for (Handle<WasmInstanceObject> instance : 1135 iterate_compiled_module_instance_chain(isolate, compiled_module)) { 1136 Handle<WasmDebugInfo> debug_info = 1137 WasmInstanceObject::GetOrCreateDebugInfo(instance); 1138 WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func); 1139 } 1140 1141 return true; 1142 } 1143 1144 MaybeHandle<FixedArray> WasmCompiledModule::CheckBreakPoints(int position) { 1145 Isolate* isolate = GetIsolate(); 1146 if (!shared()->has_breakpoint_infos()) return {}; 1147 1148 Handle<FixedArray> breakpoint_infos(shared()->breakpoint_infos(), isolate); 1149 int insert_pos = 1150 FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position); 1151 if (insert_pos >= breakpoint_infos->length()) return {}; 1152 1153 Handle<Object> maybe_breakpoint_info(breakpoint_infos->get(insert_pos), 1154 isolate); 1155 if (maybe_breakpoint_info->IsUndefined(isolate)) return {}; 1156 Handle<BreakPointInfo> breakpoint_info = 1157 Handle<BreakPointInfo>::cast(maybe_breakpoint_info); 1158 if (breakpoint_info->source_position() != position) return {}; 1159 1160 Handle<Object> breakpoint_objects(breakpoint_info->break_point_objects(), 1161 isolate); 1162 return isolate->debug()->GetHitBreakPointObjects(breakpoint_objects); 1163 } 1164 1165 Handle<WasmInstanceWrapper> WasmInstanceWrapper::New( 1166 Isolate* isolate, Handle<WasmInstanceObject> instance) { 1167 Handle<FixedArray> array = 1168 isolate->factory()->NewFixedArray(kWrapperPropertyCount, TENURED); 1169 Handle<WasmInstanceWrapper> instance_wrapper( 1170 reinterpret_cast<WasmInstanceWrapper*>(*array), isolate); 1171 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(instance); 1172 instance_wrapper->set(kWrapperInstanceObject, *cell); 1173 return instance_wrapper; 1174 } 1175 1176 bool WasmInstanceWrapper::IsWasmInstanceWrapper(Object* obj) { 1177 if (!obj->IsFixedArray()) return false; 1178 Handle<FixedArray> array = handle(FixedArray::cast(obj)); 1179 if (array->length() != kWrapperPropertyCount) return false; 1180 if (!array->get(kWrapperInstanceObject)->IsWeakCell()) return false; 1181 Isolate* isolate = array->GetIsolate(); 1182 if (!array->get(kNextInstanceWrapper)->IsUndefined(isolate) && 1183 !array->get(kNextInstanceWrapper)->IsFixedArray()) 1184 return false; 1185 if (!array->get(kPreviousInstanceWrapper)->IsUndefined(isolate) && 1186 !array->get(kPreviousInstanceWrapper)->IsFixedArray()) 1187 return false; 1188 return true; 1189 } 1190