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 
SafeUint32(Object * value)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 
SafeInt32(Object * value)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 
New(Isolate * isolate,Handle<WasmCompiledModule> compiled_module)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 
cast(Object * object)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 
New(Isolate * isolate,uint32_t initial,uint32_t maximum,Handle<FixedArray> * js_functions)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 
DEFINE_GETTER(WasmTableObject,dispatch_tables,kDispatchTables,FixedArray)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 
DEFINE_ACCESSORS(WasmTableObject,functions,kFunctions,FixedArray)150 DEFINE_ACCESSORS(WasmTableObject, functions, kFunctions, FixedArray)
151 
152 uint32_t WasmTableObject::current_length() { return get_functions()->length(); }
153 
maximum_length()154 uint32_t WasmTableObject::maximum_length() {
155   return SafeUint32(GetInternalField(kMaximum));
156 }
157 
cast(Object * object)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 
New(Isolate * isolate,Handle<JSArrayBuffer> buffer,int maximum)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 
DEFINE_ACCESSORS(WasmMemoryObject,buffer,kArrayBuffer,JSArrayBuffer)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 
maximum_pages()184 int32_t WasmMemoryObject::maximum_pages() {
185   return SafeInt32(GetInternalField(kMaximum));
186 }
187 
cast(Object * object)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 
AddInstance(WasmInstanceObject * instance)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 
DEFINE_ACCESSORS(WasmInstanceObject,compiled_module,kCompiledModule,WasmCompiledModule)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 
module()215 WasmModule* WasmInstanceObject::module() {
216   return reinterpret_cast<WasmModuleWrapper*>(
217              *get_compiled_module()->module_wrapper())
218       ->get();
219 }
220 
cast(Object * object)221 WasmInstanceObject* WasmInstanceObject::cast(Object* object) {
222   DCHECK(IsWasmInstanceObject(object));
223   return reinterpret_cast<WasmInstanceObject*>(object);
224 }
225 
IsWasmInstanceObject(Object * object)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 
New(Isolate * isolate,Handle<WasmCompiledModule> compiled_module)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 
instance()261 WasmInstanceObject* WasmExportedFunction::instance() {
262   return WasmInstanceObject::cast(GetInternalField(kInstance));
263 }
264 
function_index()265 int WasmExportedFunction::function_index() {
266   return SafeInt32(GetInternalField(kIndex));
267 }
268 
cast(Object * object)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 
New(Isolate * isolate,Handle<WasmInstanceObject> instance,Handle<String> name,Handle<Code> export_wrapper,int arity,int func_index)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 
New(Isolate * isolate,Handle<WasmModuleWrapper> module_wrapper)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 
module() const306 wasm::WasmModule* WasmCompiledModule::module() const {
307   return reinterpret_cast<WasmModuleWrapper*>(*module_wrapper())->get();
308 }
309 
InitId()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 
IsWasmCompiledModule(Object * obj)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 
PrintInstancesChain()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 
mem_size() const353 uint32_t WasmCompiledModule::mem_size() const {
354   return has_memory() ? memory()->byte_length()->Number() : default_mem_size();
355 }
356 
default_mem_size() const357 uint32_t WasmCompiledModule::default_mem_size() const {
358   return min_mem_pages() * WasmModule::kPageSize;
359 }
360