OLD | NEW |
(Empty) | |
| 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/wasm/wasm-module.h" |
| 7 |
| 8 #define TRACE(...) \ |
| 9 do { \ |
| 10 if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \ |
| 11 } while (false) |
| 12 |
| 13 #define TRACE_CHAIN(instance) \ |
| 14 do { \ |
| 15 instance->PrintInstancesChain(); \ |
| 16 } while (false) |
| 17 |
| 18 using namespace v8::internal; |
| 19 using namespace v8::internal::wasm; |
| 20 |
| 21 #define DEFINE_ACCESSORS(Container, name, field, type) \ |
| 22 type* Container::get_##name() { \ |
| 23 return type::cast(GetInternalField(field)); \ |
| 24 } \ |
| 25 void Container::set_##name(type* value) { \ |
| 26 return SetInternalField(field, value); \ |
| 27 } |
| 28 |
| 29 #define DEFINE_OPTIONAL_ACCESSORS(Container, name, field, type) \ |
| 30 bool Container::has_##name() { \ |
| 31 return !GetInternalField(field)->IsUndefined(GetIsolate()); \ |
| 32 } \ |
| 33 type* Container::get_##name() { \ |
| 34 return type::cast(GetInternalField(field)); \ |
| 35 } \ |
| 36 void Container::set_##name(type* value) { \ |
| 37 return SetInternalField(field, value); \ |
| 38 } |
| 39 |
| 40 #define DEFINE_GETTER(Container, name, field, type) \ |
| 41 type* Container::get_##name() { return type::cast(GetInternalField(field)); } |
| 42 |
| 43 static uint32_t SafeUint32(Object* value) { |
| 44 if (value->IsSmi()) { |
| 45 int32_t val = Smi::cast(value)->value(); |
| 46 CHECK_GE(val, 0); |
| 47 return static_cast<uint32_t>(val); |
| 48 } |
| 49 DCHECK(value->IsHeapNumber()); |
| 50 HeapNumber* num = HeapNumber::cast(value); |
| 51 CHECK_GE(num->value(), 0.0); |
| 52 CHECK_LE(num->value(), static_cast<double>(kMaxUInt32)); |
| 53 return static_cast<uint32_t>(num->value()); |
| 54 } |
| 55 |
| 56 static int32_t SafeInt32(Object* value) { |
| 57 if (value->IsSmi()) { |
| 58 return Smi::cast(value)->value(); |
| 59 } |
| 60 DCHECK(value->IsHeapNumber()); |
| 61 HeapNumber* num = HeapNumber::cast(value); |
| 62 CHECK_GE(num->value(), static_cast<double>(Smi::kMinValue)); |
| 63 CHECK_LE(num->value(), static_cast<double>(Smi::kMaxValue)); |
| 64 return static_cast<int32_t>(num->value()); |
| 65 } |
| 66 |
| 67 Handle<WasmModuleObject> WasmModuleObject::New( |
| 68 Isolate* isolate, Handle<WasmCompiledModule> compiled_module) { |
| 69 ModuleOrigin origin = compiled_module->module()->origin; |
| 70 |
| 71 Handle<JSObject> module_object; |
| 72 if (origin == ModuleOrigin::kWasmOrigin) { |
| 73 Handle<JSFunction> module_cons( |
| 74 isolate->native_context()->wasm_module_constructor()); |
| 75 module_object = isolate->factory()->NewJSObject(module_cons); |
| 76 Handle<Symbol> module_sym(isolate->native_context()->wasm_module_sym()); |
| 77 Object::SetProperty(module_object, module_sym, module_object, STRICT) |
| 78 .Check(); |
| 79 } else { |
| 80 DCHECK(origin == ModuleOrigin::kAsmJsOrigin); |
| 81 Handle<Map> map = isolate->factory()->NewMap( |
| 82 JS_OBJECT_TYPE, |
| 83 JSObject::kHeaderSize + WasmModuleObject::kFieldCount * kPointerSize); |
| 84 module_object = isolate->factory()->NewJSObjectFromMap(map, TENURED); |
| 85 } |
| 86 module_object->SetInternalField(WasmModuleObject::kCompiledModule, |
| 87 *compiled_module); |
| 88 Handle<WeakCell> link_to_module = |
| 89 isolate->factory()->NewWeakCell(module_object); |
| 90 compiled_module->set_weak_wasm_module(link_to_module); |
| 91 return Handle<WasmModuleObject>::cast(module_object); |
| 92 } |
| 93 |
| 94 WasmModuleObject* WasmModuleObject::cast(Object* object) { |
| 95 DCHECK(object->IsJSObject()); |
| 96 // TODO(titzer): brand check for WasmModuleObject. |
| 97 return reinterpret_cast<WasmModuleObject*>(object); |
| 98 } |
| 99 |
| 100 Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial, |
| 101 uint32_t maximum, |
| 102 Handle<FixedArray>* js_functions) { |
| 103 Handle<JSFunction> table_ctor( |
| 104 isolate->native_context()->wasm_table_constructor()); |
| 105 Handle<JSObject> table_obj = isolate->factory()->NewJSObject(table_ctor); |
| 106 *js_functions = isolate->factory()->NewFixedArray(initial); |
| 107 Object* null = isolate->heap()->null_value(); |
| 108 for (int i = 0; i < static_cast<int>(initial); ++i) { |
| 109 (*js_functions)->set(i, null); |
| 110 } |
| 111 table_obj->SetInternalField(kFunctions, *(*js_functions)); |
| 112 table_obj->SetInternalField(kMaximum, |
| 113 static_cast<Object*>(Smi::FromInt(maximum))); |
| 114 |
| 115 Handle<FixedArray> dispatch_tables = isolate->factory()->NewFixedArray(0); |
| 116 table_obj->SetInternalField(kDispatchTables, *dispatch_tables); |
| 117 Handle<Symbol> table_sym(isolate->native_context()->wasm_table_sym()); |
| 118 Object::SetProperty(table_obj, table_sym, table_obj, STRICT).Check(); |
| 119 return Handle<WasmTableObject>::cast(table_obj); |
| 120 } |
| 121 |
| 122 DEFINE_GETTER(WasmTableObject, dispatch_tables, kDispatchTables, FixedArray) |
| 123 |
| 124 Handle<FixedArray> WasmTableObject::AddDispatchTable( |
| 125 Isolate* isolate, Handle<WasmTableObject> table_obj, |
| 126 Handle<WasmInstanceObject> instance, int table_index, |
| 127 Handle<FixedArray> dispatch_table) { |
| 128 Handle<FixedArray> dispatch_tables( |
| 129 FixedArray::cast(table_obj->GetInternalField(kDispatchTables)), isolate); |
| 130 DCHECK_EQ(0, dispatch_tables->length() % 3); |
| 131 |
| 132 if (instance.is_null()) return dispatch_tables; |
| 133 // TODO(titzer): use weak cells here to avoid leaking instances. |
| 134 |
| 135 // Grow the dispatch table and add a new triple at the end. |
| 136 Handle<FixedArray> new_dispatch_tables = |
| 137 isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables, 3); |
| 138 |
| 139 new_dispatch_tables->set(dispatch_tables->length() + 0, *instance); |
| 140 new_dispatch_tables->set(dispatch_tables->length() + 1, |
| 141 Smi::FromInt(table_index)); |
| 142 new_dispatch_tables->set(dispatch_tables->length() + 2, *dispatch_table); |
| 143 |
| 144 table_obj->SetInternalField(WasmTableObject::kDispatchTables, |
| 145 *new_dispatch_tables); |
| 146 |
| 147 return new_dispatch_tables; |
| 148 } |
| 149 |
| 150 DEFINE_ACCESSORS(WasmTableObject, functions, kFunctions, FixedArray) |
| 151 |
| 152 uint32_t WasmTableObject::current_length() { return get_functions()->length(); } |
| 153 |
| 154 uint32_t WasmTableObject::maximum_length() { |
| 155 return SafeUint32(GetInternalField(kMaximum)); |
| 156 } |
| 157 |
| 158 WasmTableObject* WasmTableObject::cast(Object* object) { |
| 159 DCHECK(object && object->IsJSObject()); |
| 160 // TODO(titzer): brand check for WasmTableObject. |
| 161 return reinterpret_cast<WasmTableObject*>(object); |
| 162 } |
| 163 |
| 164 Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate, |
| 165 Handle<JSArrayBuffer> buffer, |
| 166 int maximum) { |
| 167 Handle<JSFunction> memory_ctor( |
| 168 isolate->native_context()->wasm_memory_constructor()); |
| 169 Handle<JSObject> memory_obj = isolate->factory()->NewJSObject(memory_ctor); |
| 170 memory_obj->SetInternalField(kArrayBuffer, *buffer); |
| 171 memory_obj->SetInternalField(kMaximum, |
| 172 static_cast<Object*>(Smi::FromInt(maximum))); |
| 173 Handle<Symbol> memory_sym(isolate->native_context()->wasm_memory_sym()); |
| 174 Object::SetProperty(memory_obj, memory_sym, memory_obj, STRICT).Check(); |
| 175 return Handle<WasmMemoryObject>::cast(memory_obj); |
| 176 } |
| 177 |
| 178 DEFINE_ACCESSORS(WasmMemoryObject, buffer, kArrayBuffer, JSArrayBuffer) |
| 179 |
| 180 uint32_t WasmMemoryObject::current_pages() { |
| 181 return SafeUint32(get_buffer()->byte_length()) / wasm::WasmModule::kPageSize; |
| 182 } |
| 183 |
| 184 int32_t WasmMemoryObject::maximum_pages() { |
| 185 return SafeInt32(GetInternalField(kMaximum)); |
| 186 } |
| 187 |
| 188 WasmMemoryObject* WasmMemoryObject::cast(Object* object) { |
| 189 DCHECK(object && object->IsJSObject()); |
| 190 // TODO(titzer): brand check for WasmMemoryObject. |
| 191 return reinterpret_cast<WasmMemoryObject*>(object); |
| 192 } |
| 193 |
| 194 void WasmMemoryObject::AddInstance(WasmInstanceObject* instance) { |
| 195 // TODO(gdeepti): This should be a weak list of instance objects |
| 196 // for instances that share memory. |
| 197 SetInternalField(kInstance, instance); |
| 198 } |
| 199 |
| 200 DEFINE_ACCESSORS(WasmInstanceObject, compiled_module, kCompiledModule, |
| 201 WasmCompiledModule) |
| 202 DEFINE_OPTIONAL_ACCESSORS(WasmInstanceObject, globals_buffer, |
| 203 kGlobalsArrayBuffer, JSArrayBuffer) |
| 204 DEFINE_OPTIONAL_ACCESSORS(WasmInstanceObject, memory_buffer, kMemoryArrayBuffer, |
| 205 JSArrayBuffer) |
| 206 DEFINE_OPTIONAL_ACCESSORS(WasmInstanceObject, memory_object, kMemoryObject, |
| 207 WasmMemoryObject) |
| 208 DEFINE_OPTIONAL_ACCESSORS(WasmInstanceObject, debug_info, kDebugInfo, |
| 209 WasmDebugInfo) |
| 210 |
| 211 WasmModuleObject* WasmInstanceObject::module_object() { |
| 212 return WasmModuleObject::cast(*get_compiled_module()->wasm_module()); |
| 213 } |
| 214 |
| 215 WasmModule* WasmInstanceObject::module() { |
| 216 return reinterpret_cast<WasmModuleWrapper*>( |
| 217 *get_compiled_module()->module_wrapper()) |
| 218 ->get(); |
| 219 } |
| 220 |
| 221 WasmInstanceObject* WasmInstanceObject::cast(Object* object) { |
| 222 DCHECK(IsWasmInstanceObject(object)); |
| 223 return reinterpret_cast<WasmInstanceObject*>(object); |
| 224 } |
| 225 |
| 226 bool WasmInstanceObject::IsWasmInstanceObject(Object* object) { |
| 227 if (!object->IsObject()) return false; |
| 228 if (!object->IsJSObject()) return false; |
| 229 |
| 230 JSObject* obj = JSObject::cast(object); |
| 231 Isolate* isolate = obj->GetIsolate(); |
| 232 if (obj->GetInternalFieldCount() != kFieldCount) { |
| 233 return false; |
| 234 } |
| 235 |
| 236 Object* mem = obj->GetInternalField(kMemoryArrayBuffer); |
| 237 if (!(mem->IsUndefined(isolate) || mem->IsJSArrayBuffer()) || |
| 238 !WasmCompiledModule::IsWasmCompiledModule( |
| 239 obj->GetInternalField(kCompiledModule))) { |
| 240 return false; |
| 241 } |
| 242 |
| 243 // All checks passed. |
| 244 return true; |
| 245 } |
| 246 |
| 247 Handle<WasmInstanceObject> WasmInstanceObject::New( |
| 248 Isolate* isolate, Handle<WasmCompiledModule> compiled_module) { |
| 249 Handle<Map> map = isolate->factory()->NewMap( |
| 250 JS_OBJECT_TYPE, JSObject::kHeaderSize + kFieldCount * kPointerSize); |
| 251 Handle<WasmInstanceObject> instance( |
| 252 reinterpret_cast<WasmInstanceObject*>( |
| 253 *isolate->factory()->NewJSObjectFromMap(map, TENURED)), |
| 254 isolate); |
| 255 |
| 256 instance->SetInternalField(kCompiledModule, *compiled_module); |
| 257 instance->SetInternalField(kMemoryObject, isolate->heap()->undefined_value()); |
| 258 return instance; |
| 259 } |
| 260 |
| 261 WasmInstanceObject* WasmExportedFunction::instance() { |
| 262 return WasmInstanceObject::cast(GetInternalField(kInstance)); |
| 263 } |
| 264 |
| 265 int WasmExportedFunction::function_index() { |
| 266 return SafeInt32(GetInternalField(kIndex)); |
| 267 } |
| 268 |
| 269 WasmExportedFunction* WasmExportedFunction::cast(Object* object) { |
| 270 DCHECK(object && object->IsJSFunction()); |
| 271 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, |
| 272 JSFunction::cast(object)->code()->kind()); |
| 273 // TODO(titzer): brand check for WasmExportedFunction. |
| 274 return reinterpret_cast<WasmExportedFunction*>(object); |
| 275 } |
| 276 |
| 277 Handle<WasmExportedFunction> WasmExportedFunction::New( |
| 278 Isolate* isolate, Handle<WasmInstanceObject> instance, Handle<String> name, |
| 279 Handle<Code> export_wrapper, int arity, int func_index) { |
| 280 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind()); |
| 281 Handle<SharedFunctionInfo> shared = |
| 282 isolate->factory()->NewSharedFunctionInfo(name, export_wrapper, false); |
| 283 shared->set_length(arity); |
| 284 shared->set_internal_formal_parameter_count(arity); |
| 285 Handle<JSFunction> function = isolate->factory()->NewFunction( |
| 286 isolate->wasm_function_map(), name, export_wrapper); |
| 287 function->set_shared(*shared); |
| 288 |
| 289 function->SetInternalField(kInstance, *instance); |
| 290 function->SetInternalField(kIndex, Smi::FromInt(func_index)); |
| 291 return Handle<WasmExportedFunction>::cast(function); |
| 292 } |
| 293 |
| 294 Handle<WasmCompiledModule> WasmCompiledModule::New( |
| 295 Isolate* isolate, Handle<WasmModuleWrapper> module_wrapper) { |
| 296 Handle<FixedArray> ret = |
| 297 isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED); |
| 298 // WasmCompiledModule::cast would fail since module bytes are not set yet. |
| 299 Handle<WasmCompiledModule> compiled_module( |
| 300 reinterpret_cast<WasmCompiledModule*>(*ret), isolate); |
| 301 compiled_module->InitId(); |
| 302 compiled_module->set_module_wrapper(module_wrapper); |
| 303 return compiled_module; |
| 304 } |
| 305 |
| 306 wasm::WasmModule* WasmCompiledModule::module() const { |
| 307 return reinterpret_cast<WasmModuleWrapper*>(*module_wrapper())->get(); |
| 308 } |
| 309 |
| 310 void WasmCompiledModule::InitId() { |
| 311 #if DEBUG |
| 312 static uint32_t instance_id_counter = 0; |
| 313 set(kID_instance_id, Smi::FromInt(instance_id_counter++)); |
| 314 TRACE("New compiled module id: %d\n", instance_id()); |
| 315 #endif |
| 316 } |
| 317 |
| 318 bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) { |
| 319 if (!obj->IsFixedArray()) return false; |
| 320 FixedArray* arr = FixedArray::cast(obj); |
| 321 if (arr->length() != PropertyIndices::Count) return false; |
| 322 Isolate* isolate = arr->GetIsolate(); |
| 323 #define WCM_CHECK_SMALL_NUMBER(TYPE, NAME) \ |
| 324 if (!arr->get(kID_##NAME)->IsSmi()) return false; |
| 325 #define WCM_CHECK_OBJECT_OR_WEAK(TYPE, NAME) \ |
| 326 if (!arr->get(kID_##NAME)->IsUndefined(isolate) && \ |
| 327 !arr->get(kID_##NAME)->Is##TYPE()) \ |
| 328 return false; |
| 329 #define WCM_CHECK_OBJECT(TYPE, NAME) WCM_CHECK_OBJECT_OR_WEAK(TYPE, NAME) |
| 330 #define WCM_CHECK_WEAK_LINK(TYPE, NAME) WCM_CHECK_OBJECT_OR_WEAK(WeakCell, NAME) |
| 331 #define WCM_CHECK(KIND, TYPE, NAME) WCM_CHECK_##KIND(TYPE, NAME) |
| 332 WCM_PROPERTY_TABLE(WCM_CHECK) |
| 333 #undef WCM_CHECK |
| 334 |
| 335 // All checks passed. |
| 336 return true; |
| 337 } |
| 338 |
| 339 void WasmCompiledModule::PrintInstancesChain() { |
| 340 #if DEBUG |
| 341 if (!FLAG_trace_wasm_instances) return; |
| 342 for (WasmCompiledModule* current = this; current != nullptr;) { |
| 343 PrintF("->%d", current->instance_id()); |
| 344 if (current->ptr_to_weak_next_instance() == nullptr) break; |
| 345 CHECK(!current->ptr_to_weak_next_instance()->cleared()); |
| 346 current = |
| 347 WasmCompiledModule::cast(current->ptr_to_weak_next_instance()->value()); |
| 348 } |
| 349 PrintF("\n"); |
| 350 #endif |
| 351 } |
| 352 |
| 353 uint32_t WasmCompiledModule::mem_size() const { |
| 354 return has_memory() ? memory()->byte_length()->Number() : default_mem_size(); |
| 355 } |
| 356 |
| 357 uint32_t WasmCompiledModule::default_mem_size() const { |
| 358 return min_mem_pages() * WasmModule::kPageSize; |
| 359 } |
OLD | NEW |