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 18using namespace v8::internal; 19using 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 43static 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 56static 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 67Handle<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 94WasmModuleObject* WasmModuleObject::cast(Object* object) { 95 DCHECK(object->IsJSObject()); 96 // TODO(titzer): brand check for WasmModuleObject. 97 return reinterpret_cast<WasmModuleObject*>(object); 98} 99 100Handle<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 122DEFINE_GETTER(WasmTableObject, dispatch_tables, kDispatchTables, FixedArray) 123 124Handle<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 150DEFINE_ACCESSORS(WasmTableObject, functions, kFunctions, FixedArray) 151 152uint32_t WasmTableObject::current_length() { return get_functions()->length(); } 153 154uint32_t WasmTableObject::maximum_length() { 155 return SafeUint32(GetInternalField(kMaximum)); 156} 157 158WasmTableObject* WasmTableObject::cast(Object* object) { 159 DCHECK(object && object->IsJSObject()); 160 // TODO(titzer): brand check for WasmTableObject. 161 return reinterpret_cast<WasmTableObject*>(object); 162} 163 164Handle<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 178DEFINE_ACCESSORS(WasmMemoryObject, buffer, kArrayBuffer, JSArrayBuffer) 179 180uint32_t WasmMemoryObject::current_pages() { 181 return SafeUint32(get_buffer()->byte_length()) / wasm::WasmModule::kPageSize; 182} 183 184int32_t WasmMemoryObject::maximum_pages() { 185 return SafeInt32(GetInternalField(kMaximum)); 186} 187 188WasmMemoryObject* WasmMemoryObject::cast(Object* object) { 189 DCHECK(object && object->IsJSObject()); 190 // TODO(titzer): brand check for WasmMemoryObject. 191 return reinterpret_cast<WasmMemoryObject*>(object); 192} 193 194void 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 200DEFINE_ACCESSORS(WasmInstanceObject, compiled_module, kCompiledModule, 201 WasmCompiledModule) 202DEFINE_OPTIONAL_ACCESSORS(WasmInstanceObject, globals_buffer, 203 kGlobalsArrayBuffer, JSArrayBuffer) 204DEFINE_OPTIONAL_ACCESSORS(WasmInstanceObject, memory_buffer, kMemoryArrayBuffer, 205 JSArrayBuffer) 206DEFINE_OPTIONAL_ACCESSORS(WasmInstanceObject, memory_object, kMemoryObject, 207 WasmMemoryObject) 208DEFINE_OPTIONAL_ACCESSORS(WasmInstanceObject, debug_info, kDebugInfo, 209 WasmDebugInfo) 210 211WasmModuleObject* WasmInstanceObject::module_object() { 212 return WasmModuleObject::cast(*get_compiled_module()->wasm_module()); 213} 214 215WasmModule* WasmInstanceObject::module() { 216 return reinterpret_cast<WasmModuleWrapper*>( 217 *get_compiled_module()->module_wrapper()) 218 ->get(); 219} 220 221WasmInstanceObject* WasmInstanceObject::cast(Object* object) { 222 DCHECK(IsWasmInstanceObject(object)); 223 return reinterpret_cast<WasmInstanceObject*>(object); 224} 225 226bool 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 247Handle<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 261WasmInstanceObject* WasmExportedFunction::instance() { 262 return WasmInstanceObject::cast(GetInternalField(kInstance)); 263} 264 265int WasmExportedFunction::function_index() { 266 return SafeInt32(GetInternalField(kIndex)); 267} 268 269WasmExportedFunction* 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 277Handle<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 294Handle<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 306wasm::WasmModule* WasmCompiledModule::module() const { 307 return reinterpret_cast<WasmModuleWrapper*>(*module_wrapper())->get(); 308} 309 310void 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 318bool 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 339void 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 353uint32_t WasmCompiledModule::mem_size() const { 354 return has_memory() ? memory()->byte_length()->Number() : default_mem_size(); 355} 356 357uint32_t WasmCompiledModule::default_mem_size() const { 358 return min_mem_pages() * WasmModule::kPageSize; 359} 360