Bug Summary

File:out/../deps/v8/src/wasm/module-instantiate.cc
Warning:line 475, column 17
Value stored to 'native_module' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name module-instantiate.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D V8_GYP_BUILD -D V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=64 -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D V8_TARGET_ARCH_X64 -D V8_HAVE_TARGET_OS -D V8_TARGET_OS_LINUX -D V8_EMBEDDER_STRING="-node.8" -D ENABLE_DISASSEMBLER -D V8_PROMISE_INTERNAL_FIELD_COUNT=1 -D V8_SHORT_BUILTIN_CALLS -D OBJECT_PRINT -D V8_INTL_SUPPORT -D V8_ATOMIC_OBJECT_FIELD_WRITES -D V8_ENABLE_LAZY_SOURCE_POSITIONS -D V8_USE_SIPHASH -D V8_SHARED_RO_HEAP -D V8_WIN64_UNWINDING_INFO -D V8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH -D V8_SNAPSHOT_COMPRESSION -D V8_ENABLE_WEBASSEMBLY -D V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS -D V8_ALLOCATION_FOLDING -D V8_ALLOCATION_SITE_TRACKING -D V8_SCRIPTORMODULE_LEGACY_LIFETIME -D V8_ADVANCED_BIGINT_ALGORITHMS -D ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_STATIC -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_STATIC_IMPLEMENTATION=1 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -I ../deps/v8 -I ../deps/v8/include -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/inspector-generated-output-root -I ../deps/v8/third_party/inspector_protocol -I /home/maurizio/node-v18.6.0/out/Release/obj/gen -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/generate-bytecode-output-root -I ../deps/icu-small/source/i18n -I ../deps/icu-small/source/common -I ../deps/v8/third_party/zlib -I ../deps/v8/third_party/zlib/google -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-return-type -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../deps/v8/src/wasm/module-instantiate.cc
1// Copyright 2019 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/module-instantiate.h"
6
7#include "src/api/api-inl.h"
8#include "src/asmjs/asm-js.h"
9#include "src/base/atomicops.h"
10#include "src/base/platform/wrappers.h"
11#include "src/logging/counters-scopes.h"
12#include "src/logging/metrics.h"
13#include "src/numbers/conversions-inl.h"
14#include "src/objects/descriptor-array-inl.h"
15#include "src/objects/property-descriptor.h"
16#include "src/tracing/trace-event.h"
17#include "src/utils/utils.h"
18#include "src/wasm/code-space-access.h"
19#include "src/wasm/init-expr-interface.h"
20#include "src/wasm/module-compiler.h"
21#include "src/wasm/wasm-constants.h"
22#include "src/wasm/wasm-engine.h"
23#include "src/wasm/wasm-external-refs.h"
24#include "src/wasm/wasm-import-wrapper-cache.h"
25#include "src/wasm/wasm-module.h"
26#include "src/wasm/wasm-objects-inl.h"
27#include "src/wasm/wasm-opcodes-inl.h"
28#include "src/wasm/wasm-subtyping.h"
29#include "src/wasm/wasm-value.h"
30
31#define TRACE(...) \
32 do { \
33 if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
34 } while (false)
35
36namespace v8 {
37namespace internal {
38namespace wasm {
39
40namespace {
41
42byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) {
43 return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset;
44}
45
46using ImportWrapperQueue = WrapperQueue<WasmImportWrapperCache::CacheKey,
47 WasmImportWrapperCache::CacheKeyHash>;
48
49class CompileImportWrapperJob final : public JobTask {
50 public:
51 CompileImportWrapperJob(
52 Counters* counters, NativeModule* native_module,
53 ImportWrapperQueue* queue,
54 WasmImportWrapperCache::ModificationScope* cache_scope)
55 : counters_(counters),
56 native_module_(native_module),
57 queue_(queue),
58 cache_scope_(cache_scope) {}
59
60 size_t GetMaxConcurrency(size_t worker_count) const override {
61 size_t flag_limit =
62 static_cast<size_t>(std::max(1, FLAG_wasm_num_compilation_tasks));
63 // Add {worker_count} to the queue size because workers might still be
64 // processing units that have already been popped from the queue.
65 return std::min(flag_limit, worker_count + queue_->size());
66 }
67
68 void Run(JobDelegate* delegate) override {
69 TRACE_EVENT0("v8.wasm", "wasm.CompileImportWrapperJob.Run")static v8::base::AtomicWord trace_event_unique_atomic69 = 0; const
uint8_t* trace_event_unique_category_group_enabled69; trace_event_unique_category_group_enabled69
= reinterpret_cast<const uint8_t*>(v8::base::Relaxed_Load
(&(trace_event_unique_atomic69))); if (!trace_event_unique_category_group_enabled69
) { trace_event_unique_category_group_enabled69 = v8::internal
::tracing::TraceEventHelper::GetTracingController() ->GetCategoryGroupEnabled
("v8.wasm"); v8::base::Relaxed_Store(&(trace_event_unique_atomic69
), (reinterpret_cast<v8::base::AtomicWord>( trace_event_unique_category_group_enabled69
))); };; v8::internal::tracing::ScopedTracer trace_event_unique_tracer69
; if (v8::base::Relaxed_Load(reinterpret_cast<const v8::base
::Atomic8*>( trace_event_unique_category_group_enabled69))
& (kEnabledForRecording_CategoryGroupEnabledFlags | kEnabledForEventCallback_CategoryGroupEnabledFlags
)) { uint64_t h = v8::internal::tracing::AddTraceEvent( ('X')
, trace_event_unique_category_group_enabled69, "wasm.CompileImportWrapperJob.Run"
, v8::internal::tracing::kGlobalScope, v8::internal::tracing::
kNoId, v8::internal::tracing::kNoId, (static_cast<unsigned
int>(0))); trace_event_unique_tracer69 .Initialize(trace_event_unique_category_group_enabled69
, "wasm.CompileImportWrapperJob.Run", h); }
;
70 while (base::Optional<WasmImportWrapperCache::CacheKey> key =
71 queue_->pop()) {
72 // TODO(wasm): Batch code publishing, to avoid repeated locking and
73 // permission switching.
74 CompileImportWrapper(native_module_, counters_, key->kind, key->signature,
75 key->expected_arity, key->suspend, cache_scope_);
76 if (delegate->ShouldYield()) return;
77 }
78 }
79
80 private:
81 Counters* const counters_;
82 NativeModule* const native_module_;
83 ImportWrapperQueue* const queue_;
84 WasmImportWrapperCache::ModificationScope* const cache_scope_;
85};
86
87Handle<DescriptorArray> CreateStructDescriptorArray(
88 Isolate* isolate, const wasm::StructType* type) {
89 if (type->field_count() == 0) {
90 return isolate->factory()->empty_descriptor_array();
91 }
92 uint32_t field_count = type->field_count();
93 static_assert(kV8MaxWasmStructFields <= kMaxNumberOfDescriptors,
94 "Bigger numbers of struct fields require different approach");
95 Handle<DescriptorArray> descriptors =
96 isolate->factory()->NewDescriptorArray(field_count);
97
98 // TODO(ishell): cache Wasm field type in FieldType value.
99 MaybeObject any_type = MaybeObject::FromObject(FieldType::Any());
100 DCHECK(any_type->IsSmi())((void) 0);
101
102 base::EmbeddedVector<char, 128> name_buffer;
103 for (uint32_t i = 0; i < field_count; i++) {
104 // TODO(ishell): consider introducing a cache of first N internalized field
105 // names similar to LookupSingleCharacterStringFromCode().
106 SNPrintF(name_buffer, "$field%d", i);
107 Handle<String> name =
108 isolate->factory()->InternalizeUtf8String(name_buffer.begin());
109
110 PropertyAttributes attributes = type->mutability(i) ? SEALED : FROZEN;
111 PropertyDetails details(
112 PropertyKind::kData, attributes, PropertyLocation::kField,
113 PropertyConstness::kMutable, // Don't track constness
114 Representation::WasmValue(), static_cast<int>(i));
115 descriptors->Set(InternalIndex(i), *name, any_type, details);
116 }
117 descriptors->Sort();
118 return descriptors;
119}
120
121Handle<DescriptorArray> CreateArrayDescriptorArray(
122 Isolate* isolate, const wasm::ArrayType* type) {
123 uint32_t kDescriptorsCount = 1;
124 Handle<DescriptorArray> descriptors =
125 isolate->factory()->NewDescriptorArray(kDescriptorsCount);
126
127 // TODO(ishell): cache Wasm field type in FieldType value.
128 MaybeObject any_type = MaybeObject::FromObject(FieldType::Any());
129 DCHECK(any_type->IsSmi())((void) 0);
130
131 // Add descriptor for length property.
132 PropertyDetails details(PropertyKind::kData, FROZEN, PropertyLocation::kField,
133 PropertyConstness::kConst,
134 Representation::WasmValue(), static_cast<int>(0));
135 descriptors->Set(InternalIndex(0), *isolate->factory()->length_string(),
136 any_type, details);
137
138 descriptors->Sort();
139 return descriptors;
140}
141
142Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
143 int struct_index, Handle<Map> opt_rtt_parent,
144 Handle<WasmInstanceObject> instance) {
145 const wasm::StructType* type = module->struct_type(struct_index);
146 const int inobject_properties = 0;
147 // We have to use the variable size sentinel because the instance size
148 // stored directly in a Map is capped at 255 pointer sizes.
149 const int map_instance_size = kVariableSizeSentinel;
150 const int real_instance_size = WasmStruct::Size(type);
151 const InstanceType instance_type = WASM_STRUCT_TYPE;
152 // TODO(jkummerow): If NO_ELEMENTS were supported, we could use that here.
153 const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
154 Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
155 reinterpret_cast<Address>(type), opt_rtt_parent, real_instance_size,
156 instance);
157 Handle<DescriptorArray> descriptors =
158 CreateStructDescriptorArray(isolate, type);
159 Handle<Map> map = isolate->factory()->NewMap(
160 instance_type, map_instance_size, elements_kind, inobject_properties);
161 map->set_wasm_type_info(*type_info);
162 map->SetInstanceDescriptors(isolate, *descriptors,
163 descriptors->number_of_descriptors());
164 map->set_is_extensible(false);
165 WasmStruct::EncodeInstanceSizeInMap(real_instance_size, *map);
166 return map;
167}
168
169Handle<Map> CreateArrayMap(Isolate* isolate, const WasmModule* module,
170 int array_index, Handle<Map> opt_rtt_parent,
171 Handle<WasmInstanceObject> instance) {
172 const wasm::ArrayType* type = module->array_type(array_index);
173 const int inobject_properties = 0;
174 const int instance_size = kVariableSizeSentinel;
175 // Wasm Arrays don't have a static instance size.
176 const int cached_instance_size = 0;
177 const InstanceType instance_type = WASM_ARRAY_TYPE;
178 const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
179 Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
180 reinterpret_cast<Address>(type), opt_rtt_parent, cached_instance_size,
181 instance);
182 // TODO(ishell): get canonical descriptor array for WasmArrays from roots.
183 Handle<DescriptorArray> descriptors =
184 CreateArrayDescriptorArray(isolate, type);
185 Handle<Map> map = isolate->factory()->NewMap(
186 instance_type, instance_size, elements_kind, inobject_properties);
187 map->set_wasm_type_info(*type_info);
188 map->SetInstanceDescriptors(isolate, *descriptors,
189 descriptors->number_of_descriptors());
190 map->set_is_extensible(false);
191 WasmArray::EncodeElementSizeInMap(type->element_type().value_kind_size(),
192 *map);
193 return map;
194}
195
196Handle<Map> CreateFuncRefMap(Isolate* isolate, const WasmModule* module,
197 Handle<Map> opt_rtt_parent,
198 Handle<WasmInstanceObject> instance) {
199 const int inobject_properties = 0;
200 const int instance_size =
201 Map::cast(isolate->root(RootIndex::kWasmInternalFunctionMap))
202 .instance_size();
203 const InstanceType instance_type = WASM_INTERNAL_FUNCTION_TYPE;
204 const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
205 Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
206 kNullAddress, opt_rtt_parent, instance_size, instance);
207 Handle<Map> map = isolate->factory()->NewMap(
208 instance_type, instance_size, elements_kind, inobject_properties);
209 map->set_wasm_type_info(*type_info);
210 return map;
211}
212
213void CreateMapForType(Isolate* isolate, const WasmModule* module,
214 int type_index, Handle<WasmInstanceObject> instance,
215 Handle<FixedArray> maps) {
216 // Recursive calls for supertypes may already have created this map.
217 if (maps->get(type_index).IsMap()) return;
218
219 Handle<WeakArrayList> canonical_rtts;
220 uint32_t canonical_type_index =
221 module->isorecursive_canonical_type_ids[type_index];
222
223 if (FLAG_wasm_type_canonicalization) {
224 // Try to find the canonical map for this type in the isolate store.
225 canonical_rtts = handle(isolate->heap()->wasm_canonical_rtts(), isolate);
226 DCHECK_GT(static_cast<uint32_t>(canonical_rtts->length()),((void) 0)
227 canonical_type_index)((void) 0);
228 MaybeObject maybe_canonical_map = canonical_rtts->Get(canonical_type_index);
229 if (maybe_canonical_map.IsStrongOrWeak() &&
230 maybe_canonical_map.GetHeapObject().IsMap()) {
231 maps->set(type_index, maybe_canonical_map.GetHeapObject());
232 return;
233 }
234 }
235
236 Handle<Map> rtt_parent;
237 // If the type with {type_index} has an explicit supertype, make sure the
238 // map for that supertype is created first, so that the supertypes list
239 // that's cached on every RTT can be set up correctly.
240 uint32_t supertype = module->supertype(type_index);
241 if (supertype != kNoSuperType) {
242 // This recursion is safe, because kV8MaxRttSubtypingDepth limits the
243 // number of recursive steps, so we won't overflow the stack.
244 CreateMapForType(isolate, module, supertype, instance, maps);
245 rtt_parent = handle(Map::cast(maps->get(supertype)), isolate);
246 }
247 Handle<Map> map;
248 switch (module->types[type_index].kind) {
249 case TypeDefinition::kStruct:
250 map = CreateStructMap(isolate, module, type_index, rtt_parent, instance);
251 break;
252 case TypeDefinition::kArray:
253 map = CreateArrayMap(isolate, module, type_index, rtt_parent, instance);
254 break;
255 case TypeDefinition::kFunction:
256 map = CreateFuncRefMap(isolate, module, rtt_parent, instance);
257 break;
258 }
259 if (FLAG_wasm_type_canonicalization) {
260 canonical_rtts->Set(canonical_type_index, HeapObjectReference::Weak(*map));
261 }
262 maps->set(type_index, *map);
263}
264
265} // namespace
266
267// A helper class to simplify instantiating a module from a module object.
268// It closes over the {Isolate}, the {ErrorThrower}, etc.
269class InstanceBuilder {
270 public:
271 InstanceBuilder(Isolate* isolate, v8::metrics::Recorder::ContextId context_id,
272 ErrorThrower* thrower, Handle<WasmModuleObject> module_object,
273 MaybeHandle<JSReceiver> ffi,
274 MaybeHandle<JSArrayBuffer> memory_buffer);
275
276 // Build an instance, in all of its glory.
277 MaybeHandle<WasmInstanceObject> Build();
278 // Run the start function, if any.
279 bool ExecuteStartFunction();
280
281 private:
282 // A pre-evaluated value to use in import binding.
283 struct SanitizedImport {
284 Handle<String> module_name;
285 Handle<String> import_name;
286 Handle<Object> value;
287 };
288
289 Isolate* isolate_;
290 v8::metrics::Recorder::ContextId context_id_;
291 const WasmFeatures enabled_;
292 const WasmModule* const module_;
293 ErrorThrower* thrower_;
294 Handle<WasmModuleObject> module_object_;
295 MaybeHandle<JSReceiver> ffi_;
296 MaybeHandle<JSArrayBuffer> memory_buffer_;
297 Handle<WasmMemoryObject> memory_object_;
298 Handle<JSArrayBuffer> untagged_globals_;
299 Handle<FixedArray> tagged_globals_;
300 std::vector<Handle<WasmTagObject>> tags_wrappers_;
301 Handle<WasmExportedFunction> start_function_;
302 std::vector<SanitizedImport> sanitized_imports_;
303 // We pass this {Zone} to the temporary {WasmFullDecoder} we allocate during
304 // each call to {EvaluateInitExpression}. This has been found to improve
305 // performance a bit over allocating a new {Zone} each time.
306 Zone init_expr_zone_;
307
308// Helper routines to print out errors with imports.
309#define ERROR_THROWER_WITH_MESSAGE(TYPE) \
310 void Report##TYPE(const char* error, uint32_t index, \
311 Handle<String> module_name, Handle<String> import_name) { \
312 thrower_->TYPE("Import #%d module=\"%s\" function=\"%s\" error: %s", \
313 index, module_name->ToCString().get(), \
314 import_name->ToCString().get(), error); \
315 } \
316 \
317 MaybeHandle<Object> Report##TYPE(const char* error, uint32_t index, \
318 Handle<String> module_name) { \
319 thrower_->TYPE("Import #%d module=\"%s\" error: %s", index, \
320 module_name->ToCString().get(), error); \
321 return MaybeHandle<Object>(); \
322 }
323
324 ERROR_THROWER_WITH_MESSAGE(LinkError)
325 ERROR_THROWER_WITH_MESSAGE(TypeError)
326
327#undef ERROR_THROWER_WITH_MESSAGE
328
329 // Look up an import value in the {ffi_} object.
330 MaybeHandle<Object> LookupImport(uint32_t index, Handle<String> module_name,
331 Handle<String> import_name);
332
333 // Look up an import value in the {ffi_} object specifically for linking an
334 // asm.js module. This only performs non-observable lookups, which allows
335 // falling back to JavaScript proper (and hence re-executing all lookups) if
336 // module instantiation fails.
337 MaybeHandle<Object> LookupImportAsm(uint32_t index,
338 Handle<String> import_name);
339
340 // Load data segments into the memory.
341 void LoadDataSegments(Handle<WasmInstanceObject> instance);
342
343 void WriteGlobalValue(const WasmGlobal& global, const WasmValue& value);
344
345 void SanitizeImports();
346
347 // Find the imported memory if there is one.
348 bool FindImportedMemory();
349
350 // Allocate the memory.
351 bool AllocateMemory();
352
353 // Processes a single imported function.
354 bool ProcessImportedFunction(Handle<WasmInstanceObject> instance,
355 int import_index, int func_index,
356 Handle<String> module_name,
357 Handle<String> import_name,
358 Handle<Object> value);
359
360 // Initialize imported tables of type funcref.
361 bool InitializeImportedIndirectFunctionTable(
362 Handle<WasmInstanceObject> instance, int table_index, int import_index,
363 Handle<WasmTableObject> table_object);
364
365 // Process a single imported table.
366 bool ProcessImportedTable(Handle<WasmInstanceObject> instance,
367 int import_index, int table_index,
368 Handle<String> module_name,
369 Handle<String> import_name, Handle<Object> value);
370
371 // Process a single imported memory.
372 bool ProcessImportedMemory(Handle<WasmInstanceObject> instance,
373 int import_index, Handle<String> module_name,
374 Handle<String> import_name, Handle<Object> value);
375
376 // Process a single imported global.
377 bool ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
378 int import_index, int global_index,
379 Handle<String> module_name,
380 Handle<String> import_name, Handle<Object> value);
381
382 // Process a single imported WasmGlobalObject.
383 bool ProcessImportedWasmGlobalObject(Handle<WasmInstanceObject> instance,
384 int import_index,
385 Handle<String> module_name,
386 Handle<String> import_name,
387 const WasmGlobal& global,
388 Handle<WasmGlobalObject> global_object);
389
390 // Compile import wrappers in parallel. The result goes into the native
391 // module's import_wrapper_cache.
392 void CompileImportWrappers(Handle<WasmInstanceObject> instance);
393
394 // Process the imports, including functions, tables, globals, and memory, in
395 // order, loading them from the {ffi_} object. Returns the number of imported
396 // functions, or {-1} on error.
397 int ProcessImports(Handle<WasmInstanceObject> instance);
398
399 template <typename T>
400 T* GetRawUntaggedGlobalPtr(const WasmGlobal& global);
401
402 // Process initialization of globals.
403 void InitGlobals(Handle<WasmInstanceObject> instance);
404
405 // Process the exports, creating wrappers for functions, tables, memories,
406 // and globals.
407 void ProcessExports(Handle<WasmInstanceObject> instance);
408
409 void InitializeNonDefaultableTables(Handle<WasmInstanceObject> instance);
410
411 void LoadTableSegments(Handle<WasmInstanceObject> instance);
412
413 // Creates new tags. Note that some tags might already exist if they were
414 // imported, those tags will be re-used.
415 void InitializeTags(Handle<WasmInstanceObject> instance);
416};
417
418MaybeHandle<WasmInstanceObject> InstantiateToInstanceObject(
419 Isolate* isolate, ErrorThrower* thrower,
420 Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
421 MaybeHandle<JSArrayBuffer> memory_buffer) {
422 v8::metrics::Recorder::ContextId context_id =
423 isolate->GetOrRegisterRecorderContextId(isolate->native_context());
424 InstanceBuilder builder(isolate, context_id, thrower, module_object, imports,
425 memory_buffer);
426 auto instance = builder.Build();
427 if (!instance.is_null() && builder.ExecuteStartFunction()) {
428 return instance;
429 }
430 DCHECK(isolate->has_pending_exception() || thrower->error())((void) 0);
431 return {};
432}
433
434InstanceBuilder::InstanceBuilder(Isolate* isolate,
435 v8::metrics::Recorder::ContextId context_id,
436 ErrorThrower* thrower,
437 Handle<WasmModuleObject> module_object,
438 MaybeHandle<JSReceiver> ffi,
439 MaybeHandle<JSArrayBuffer> memory_buffer)
440 : isolate_(isolate),
441 context_id_(context_id),
442 enabled_(module_object->native_module()->enabled_features()),
443 module_(module_object->module()),
444 thrower_(thrower),
445 module_object_(module_object),
446 ffi_(ffi),
447 memory_buffer_(memory_buffer),
448 init_expr_zone_(isolate_->allocator(), "init. expression zone") {
449 sanitized_imports_.reserve(module_->import_table.size());
450}
451
452// Build an instance, in all of its glory.
453MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
454 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),static v8::base::AtomicWord trace_event_unique_atomic455 = 0;
const uint8_t* trace_event_unique_category_group_enabled455;
trace_event_unique_category_group_enabled455 = reinterpret_cast
<const uint8_t*>(v8::base::Relaxed_Load(&(trace_event_unique_atomic455
))); if (!trace_event_unique_category_group_enabled455) { trace_event_unique_category_group_enabled455
= v8::internal::tracing::TraceEventHelper::GetTracingController
() ->GetCategoryGroupEnabled("disabled-by-default-" "v8.wasm.detailed"
); v8::base::Relaxed_Store(&(trace_event_unique_atomic455
), (reinterpret_cast<v8::base::AtomicWord>( trace_event_unique_category_group_enabled455
))); };; v8::internal::tracing::ScopedTracer trace_event_unique_tracer455
; if (v8::base::Relaxed_Load(reinterpret_cast<const v8::base
::Atomic8*>( trace_event_unique_category_group_enabled455)
) & (kEnabledForRecording_CategoryGroupEnabledFlags | kEnabledForEventCallback_CategoryGroupEnabledFlags
)) { uint64_t h = v8::internal::tracing::AddTraceEvent( ('X')
, trace_event_unique_category_group_enabled455, "wasm.InstanceBuilder.Build"
, v8::internal::tracing::kGlobalScope, v8::internal::tracing::
kNoId, v8::internal::tracing::kNoId, (static_cast<unsigned
int>(0))); trace_event_unique_tracer455 .Initialize(trace_event_unique_category_group_enabled455
, "wasm.InstanceBuilder.Build", h); }
455 "wasm.InstanceBuilder.Build")static v8::base::AtomicWord trace_event_unique_atomic455 = 0;
const uint8_t* trace_event_unique_category_group_enabled455;
trace_event_unique_category_group_enabled455 = reinterpret_cast
<const uint8_t*>(v8::base::Relaxed_Load(&(trace_event_unique_atomic455
))); if (!trace_event_unique_category_group_enabled455) { trace_event_unique_category_group_enabled455
= v8::internal::tracing::TraceEventHelper::GetTracingController
() ->GetCategoryGroupEnabled("disabled-by-default-" "v8.wasm.detailed"
); v8::base::Relaxed_Store(&(trace_event_unique_atomic455
), (reinterpret_cast<v8::base::AtomicWord>( trace_event_unique_category_group_enabled455
))); };; v8::internal::tracing::ScopedTracer trace_event_unique_tracer455
; if (v8::base::Relaxed_Load(reinterpret_cast<const v8::base
::Atomic8*>( trace_event_unique_category_group_enabled455)
) & (kEnabledForRecording_CategoryGroupEnabledFlags | kEnabledForEventCallback_CategoryGroupEnabledFlags
)) { uint64_t h = v8::internal::tracing::AddTraceEvent( ('X')
, trace_event_unique_category_group_enabled455, "wasm.InstanceBuilder.Build"
, v8::internal::tracing::kGlobalScope, v8::internal::tracing::
kNoId, v8::internal::tracing::kNoId, (static_cast<unsigned
int>(0))); trace_event_unique_tracer455 .Initialize(trace_event_unique_category_group_enabled455
, "wasm.InstanceBuilder.Build", h); }
;
456 // Check that an imports argument was provided, if the module requires it.
457 // No point in continuing otherwise.
458 if (!module_->import_table.empty() && ffi_.is_null()) {
459 thrower_->TypeError(
460 "Imports argument must be present and must be an object");
461 return {};
462 }
463
464 SanitizeImports();
465 if (thrower_->error()) return {};
466
467 // From here on, we expect the build pipeline to run without exiting to JS.
468 DisallowJavascriptExecution no_js(isolate_);
469 // Record build time into correct bucket, then build instance.
470 TimedHistogramScope wasm_instantiate_module_time_scope(SELECT_WASM_COUNTER(((module_->origin) == kWasmOrigin ? (isolate_->counters
())->wasm_instantiate_wasm_module_time() : (isolate_->counters
())->wasm_instantiate_asm_module_time())
471 isolate_->counters(), module_->origin, wasm_instantiate, module_time)((module_->origin) == kWasmOrigin ? (isolate_->counters
())->wasm_instantiate_wasm_module_time() : (isolate_->counters
())->wasm_instantiate_asm_module_time())
);
472 v8::metrics::WasmModuleInstantiated wasm_module_instantiated;
473 base::ElapsedTimer timer;
474 timer.Start();
475 NativeModule* native_module = module_object_->native_module();
Value stored to 'native_module' during its initialization is never read
476
477 //--------------------------------------------------------------------------
478 // Set up the memory buffer and memory objects.
479 //--------------------------------------------------------------------------
480 uint32_t initial_pages = module_->initial_pages;
481 auto initial_pages_counter = SELECT_WASM_COUNTER(((module_->origin) == kWasmOrigin ? (isolate_->counters
())->wasm_wasm_min_mem_pages_count() : (isolate_->counters
())->wasm_asm_min_mem_pages_count())
482 isolate_->counters(), module_->origin, wasm, min_mem_pages_count)((module_->origin) == kWasmOrigin ? (isolate_->counters
())->wasm_wasm_min_mem_pages_count() : (isolate_->counters
())->wasm_asm_min_mem_pages_count())
;
483 initial_pages_counter->AddSample(initial_pages);
484 if (module_->has_maximum_pages) {
485 DCHECK_EQ(kWasmOrigin, module_->origin)((void) 0);
486 auto max_pages_counter =
487 isolate_->counters()->wasm_wasm_max_mem_pages_count();
488 max_pages_counter->AddSample(module_->maximum_pages);
489 }
490
491 if (is_asmjs_module(module_)) {
492 Handle<JSArrayBuffer> buffer;
493 if (memory_buffer_.ToHandle(&buffer)) {
494 // asm.js instantiation should have changed the state of the buffer.
495 CHECK(!buffer->is_detachable())do { if ((__builtin_expect(!!(!(!buffer->is_detachable()))
, 0))) { V8_Fatal("Check failed: %s.", "!buffer->is_detachable()"
); } } while (false)
;
496 CHECK(buffer->is_asmjs_memory())do { if ((__builtin_expect(!!(!(buffer->is_asmjs_memory())
), 0))) { V8_Fatal("Check failed: %s.", "buffer->is_asmjs_memory()"
); } } while (false)
;
497 } else {
498 // Use an empty JSArrayBuffer for degenerate asm.js modules.
499 memory_buffer_ = isolate_->factory()->NewJSArrayBufferAndBackingStore(
500 0, InitializedFlag::kUninitialized);
501 if (!memory_buffer_.ToHandle(&buffer)) {
502 thrower_->RangeError("Out of memory: asm.js memory");
503 return {};
504 }
505 buffer->set_is_asmjs_memory(true);
506 buffer->set_is_detachable(false);
507 }
508
509 // The maximum number of pages isn't strictly necessary for memory
510 // objects used for asm.js, as they are never visible, but we might
511 // as well make it accurate.
512 auto maximum_pages =
513 static_cast<int>(RoundUp(buffer->byte_length(), wasm::kWasmPageSize) /
514 wasm::kWasmPageSize);
515 memory_object_ =
516 WasmMemoryObject::New(isolate_, memory_buffer_, maximum_pages)
517 .ToHandleChecked();
518 } else {
519 // Actual wasm module must have either imported or created memory.
520 CHECK(memory_buffer_.is_null())do { if ((__builtin_expect(!!(!(memory_buffer_.is_null())), 0
))) { V8_Fatal("Check failed: %s.", "memory_buffer_.is_null()"
); } } while (false)
;
521 if (!FindImportedMemory()) {
522 if (module_->has_memory && !AllocateMemory()) {
523 DCHECK(isolate_->has_pending_exception() || thrower_->error())((void) 0);
524 return {};
525 }
526 }
527 }
528
529 //--------------------------------------------------------------------------
530 // Create the WebAssembly.Instance object.
531 //--------------------------------------------------------------------------
532 TRACE("New module instantiation for %p\n", native_module);
533 Handle<WasmInstanceObject> instance =
534 WasmInstanceObject::New(isolate_, module_object_);
535
536 //--------------------------------------------------------------------------
537 // Attach the memory to the instance.
538 //--------------------------------------------------------------------------
539 if (module_->has_memory) {
540 DCHECK(!memory_object_.is_null())((void) 0);
541 if (!instance->has_memory_object()) {
542 instance->set_memory_object(*memory_object_);
543 }
544 // Add the instance object to the list of instances for this memory.
545 WasmMemoryObject::AddInstance(isolate_, memory_object_, instance);
546
547 // Double-check the {memory} array buffer matches the instance.
548 Handle<JSArrayBuffer> memory = memory_buffer_.ToHandleChecked();
549 CHECK_EQ(instance->memory_size(), memory->byte_length())do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(instance->memory_size())>
::type, typename ::v8::base::pass_value_or_ref<decltype(memory
->byte_length())>::type>((instance->memory_size()
), (memory->byte_length())); do { if ((__builtin_expect(!!
(!(_cmp)), 0))) { V8_Fatal("Check failed: %s.", "instance->memory_size()"
" " "==" " " "memory->byte_length()"); } } while (false);
} while (false)
;
550 CHECK_EQ(instance->memory_start(), memory->backing_store())do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(instance->memory_start())>
::type, typename ::v8::base::pass_value_or_ref<decltype(memory
->backing_store())>::type>((instance->memory_start
()), (memory->backing_store())); do { if ((__builtin_expect
(!!(!(_cmp)), 0))) { V8_Fatal("Check failed: %s.", "instance->memory_start()"
" " "==" " " "memory->backing_store()"); } } while (false
); } while (false)
;
551 }
552
553 //--------------------------------------------------------------------------
554 // Set up the globals for the new instance.
555 //--------------------------------------------------------------------------
556 uint32_t untagged_globals_buffer_size = module_->untagged_globals_buffer_size;
557 if (untagged_globals_buffer_size > 0) {
558 MaybeHandle<JSArrayBuffer> result =
559 isolate_->factory()->NewJSArrayBufferAndBackingStore(
560 untagged_globals_buffer_size, InitializedFlag::kZeroInitialized,
561 AllocationType::kOld);
562
563 if (!result.ToHandle(&untagged_globals_)) {
564 thrower_->RangeError("Out of memory: wasm globals");
565 return {};
566 }
567
568 instance->set_untagged_globals_buffer(*untagged_globals_);
569 instance->set_globals_start(
570 reinterpret_cast<byte*>(untagged_globals_->backing_store()));
571 }
572
573 uint32_t tagged_globals_buffer_size = module_->tagged_globals_buffer_size;
574 if (tagged_globals_buffer_size > 0) {
575 tagged_globals_ = isolate_->factory()->NewFixedArray(
576 static_cast<int>(tagged_globals_buffer_size));
577 instance->set_tagged_globals_buffer(*tagged_globals_);
578 }
579
580 //--------------------------------------------------------------------------
581 // Set up the array of references to imported globals' array buffers.
582 //--------------------------------------------------------------------------
583 if (module_->num_imported_mutable_globals > 0) {
584 // TODO(binji): This allocates one slot for each mutable global, which is
585 // more than required if multiple globals are imported from the same
586 // module.
587 Handle<FixedArray> buffers_array = isolate_->factory()->NewFixedArray(
588 module_->num_imported_mutable_globals, AllocationType::kOld);
589 instance->set_imported_mutable_globals_buffers(*buffers_array);
590 }
591
592 //--------------------------------------------------------------------------
593 // Set up the tag table used for exception tag checks.
594 //--------------------------------------------------------------------------
595 int tags_count = static_cast<int>(module_->tags.size());
596 if (tags_count > 0) {
597 Handle<FixedArray> tag_table =
598 isolate_->factory()->NewFixedArray(tags_count, AllocationType::kOld);
599 instance->set_tags_table(*tag_table);
600 tags_wrappers_.resize(tags_count);
601 }
602
603 //--------------------------------------------------------------------------
604 // Set up table storage space.
605 //--------------------------------------------------------------------------
606 int table_count = static_cast<int>(module_->tables.size());
607 {
608 for (int i = 0; i < table_count; i++) {
609 const WasmTable& table = module_->tables[i];
610 if (table.initial_size > FLAG_wasm_max_table_size) {
611 thrower_->RangeError(
612 "initial table size (%u elements) is larger than implementation "
613 "limit (%u elements)",
614 table.initial_size, FLAG_wasm_max_table_size);
615 return {};
616 }
617 }
618
619 Handle<FixedArray> tables = isolate_->factory()->NewFixedArray(table_count);
620 for (int i = module_->num_imported_tables; i < table_count; i++) {
621 const WasmTable& table = module_->tables[i];
622 // Initialize tables with null for now. We will initialize non-defaultable
623 // tables later, in {InitializeNonDefaultableTables}.
624 Handle<WasmTableObject> table_obj = WasmTableObject::New(
625 isolate_, instance, table.type, table.initial_size,
626 table.has_maximum_size, table.maximum_size, nullptr,
627 isolate_->factory()->null_value());
628 tables->set(i, *table_obj);
629 }
630 instance->set_tables(*tables);
631 }
632
633 {
634 Handle<FixedArray> tables = isolate_->factory()->NewFixedArray(table_count);
635 for (int i = 0; i < table_count; ++i) {
636 const WasmTable& table = module_->tables[i];
637 if (IsSubtypeOf(table.type, kWasmFuncRef, module_)) {
638 Handle<WasmIndirectFunctionTable> table_obj =
639 WasmIndirectFunctionTable::New(isolate_, table.initial_size);
640 tables->set(i, *table_obj);
641 }
642 }
643 instance->set_indirect_function_tables(*tables);
644 }
645
646 instance->SetIndirectFunctionTableShortcuts(isolate_);
647
648 //--------------------------------------------------------------------------
649 // Process the imports for the module.
650 //--------------------------------------------------------------------------
651 if (!module_->import_table.empty()) {
652 int num_imported_functions = ProcessImports(instance);
653 if (num_imported_functions < 0) return {};
654 wasm_module_instantiated.imported_function_count = num_imported_functions;
655 }
656
657 //--------------------------------------------------------------------------
658 // Create maps for managed objects (GC proposal).
659 // Must happen before {InitGlobals} because globals can refer to these maps.
660 // We do not need to cache the canonical rtts to (rtt.canon any)'s subtype
661 // list.
662 //--------------------------------------------------------------------------
663 if (enabled_.has_gc()) {
664 if (FLAG_wasm_type_canonicalization) {
665 uint32_t maximum_canonical_type_index =
666 *std::max_element(module_->isorecursive_canonical_type_ids.begin(),
667 module_->isorecursive_canonical_type_ids.end());
668 // Make sure all canonical indices have been set.
669 DCHECK_NE(maximum_canonical_type_index, kNoSuperType)((void) 0);
670 isolate_->heap()->EnsureWasmCanonicalRttsSize(
671 maximum_canonical_type_index + 1);
672 }
673 Handle<FixedArray> maps = isolate_->factory()->NewFixedArray(
674 static_cast<int>(module_->types.size()));
675 for (uint32_t index = 0; index < module_->types.size(); index++) {
676 CreateMapForType(isolate_, module_, index, instance, maps);
677 }
678 instance->set_managed_object_maps(*maps);
679 }
680
681 //--------------------------------------------------------------------------
682 // Allocate type feedback vectors for functions.
683 //--------------------------------------------------------------------------
684 if (FLAG_wasm_speculative_inlining) {
685 int num_functions = static_cast<int>(module_->num_declared_functions);
686 Handle<FixedArray> vectors =
687 isolate_->factory()->NewFixedArray(num_functions, AllocationType::kOld);
688 instance->set_feedback_vectors(*vectors);
689 for (int i = 0; i < num_functions; i++) {
690 int func_index = module_->num_imported_functions + i;
691 int slots =
692 base::Relaxed_Load(&module_->functions[func_index].feedback_slots);
693 if (slots == 0) continue;
694 if (FLAG_trace_wasm_speculative_inlining) {
695 PrintF("[Function %d (declared %d): allocating %d feedback slots]\n",
696 func_index, i, slots);
697 }
698 Handle<FixedArray> feedback =
699 isolate_->factory()->NewFixedArrayWithZeroes(slots);
700 vectors->set(i, *feedback);
701 }
702 }
703
704 //--------------------------------------------------------------------------
705 // Process the initialization for the module's globals.
706 //--------------------------------------------------------------------------
707 InitGlobals(instance);
708
709 //--------------------------------------------------------------------------
710 // Initialize the indirect function tables and dispatch tables. We do this
711 // before initializing non-defaultable tables and loading element segments, so
712 // that indirect function tables in this module are included in the updates
713 // when we do so.
714 //--------------------------------------------------------------------------
715 for (int table_index = 0;
716 table_index < static_cast<int>(module_->tables.size()); ++table_index) {
717 const WasmTable& table = module_->tables[table_index];
718
719 if (IsSubtypeOf(table.type, kWasmFuncRef, module_)) {
720 WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
721 instance, table_index, table.initial_size);
722 if (thrower_->error()) return {};
723 auto table_object = handle(
724 WasmTableObject::cast(instance->tables().get(table_index)), isolate_);
725 WasmTableObject::AddDispatchTable(isolate_, table_object, instance,
726 table_index);
727 }
728 }
729
730 //--------------------------------------------------------------------------
731 // Initialize non-defaultable tables.
732 //--------------------------------------------------------------------------
733 if (FLAG_experimental_wasm_typed_funcref) {
734 InitializeNonDefaultableTables(instance);
735 }
736
737 //--------------------------------------------------------------------------
738 // Initialize the tags table.
739 //--------------------------------------------------------------------------
740 if (tags_count > 0) {
741 InitializeTags(instance);
742 }
743
744 //--------------------------------------------------------------------------
745 // Set up the exports object for the new instance.
746 //--------------------------------------------------------------------------
747 ProcessExports(instance);
748 if (thrower_->error()) return {};
749
750 //--------------------------------------------------------------------------
751 // Load element segments into tables.
752 //--------------------------------------------------------------------------
753 if (table_count > 0) {
754 LoadTableSegments(instance);
755 if (thrower_->error()) return {};
756 }
757
758 //--------------------------------------------------------------------------
759 // Initialize the memory by loading data segments.
760 //--------------------------------------------------------------------------
761 if (module_->data_segments.size() > 0) {
762 LoadDataSegments(instance);
763 if (thrower_->error()) return {};
764 }
765
766 //--------------------------------------------------------------------------
767 // Create a wrapper for the start function.
768 //--------------------------------------------------------------------------
769 if (module_->start_function_index >= 0) {
770 int start_index = module_->start_function_index;
771 auto& function = module_->functions[start_index];
772 Handle<CodeT> wrapper_code =
773 ToCodeT(JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper(
774 isolate_, function.sig, module_, function.imported),
775 isolate_);
776 // TODO(clemensb): Don't generate an exported function for the start
777 // function. Use CWasmEntry instead.
778 start_function_ = WasmExportedFunction::New(
779 isolate_, instance, start_index,
780 static_cast<int>(function.sig->parameter_count()), wrapper_code);
781
782 if (function.imported) {
783 ImportedFunctionEntry entry(instance, module_->start_function_index);
784 Object callable = entry.maybe_callable();
785 if (callable.IsJSFunction()) {
786 // If the start function was imported and calls into Blink, we have
787 // to pretend that the V8 API was used to enter its correct context.
788 // To get that context to {ExecuteStartFunction} below, we install it
789 // as the context of the wrapper we just compiled. That's a bit of a
790 // hack because it's not really the wrapper's context, only its wrapped
791 // target's context, but the end result is the same, and since the
792 // start function wrapper doesn't leak, neither does this
793 // implementation detail.
794 start_function_->set_context(JSFunction::cast(callable).context());
795 }
796 }
797 }
798
799 DCHECK(!isolate_->has_pending_exception())((void) 0);
800 TRACE("Successfully built instance for module %p\n",
801 module_object_->native_module());
802 wasm_module_instantiated.success = true;
803 wasm_module_instantiated.wall_clock_duration_in_us =
804 timer.Elapsed().InMicroseconds();
805 timer.Stop();
806 isolate_->metrics_recorder()->DelayMainThreadEvent(wasm_module_instantiated,
807 context_id_);
808 return instance;
809}
810
811bool InstanceBuilder::ExecuteStartFunction() {
812 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),static v8::base::AtomicWord trace_event_unique_atomic813 = 0;
const uint8_t* trace_event_unique_category_group_enabled813;
trace_event_unique_category_group_enabled813 = reinterpret_cast
<const uint8_t*>(v8::base::Relaxed_Load(&(trace_event_unique_atomic813
))); if (!trace_event_unique_category_group_enabled813) { trace_event_unique_category_group_enabled813
= v8::internal::tracing::TraceEventHelper::GetTracingController
() ->GetCategoryGroupEnabled("disabled-by-default-" "v8.wasm.detailed"
); v8::base::Relaxed_Store(&(trace_event_unique_atomic813
), (reinterpret_cast<v8::base::AtomicWord>( trace_event_unique_category_group_enabled813
))); };; v8::internal::tracing::ScopedTracer trace_event_unique_tracer813
; if (v8::base::Relaxed_Load(reinterpret_cast<const v8::base
::Atomic8*>( trace_event_unique_category_group_enabled813)
) & (kEnabledForRecording_CategoryGroupEnabledFlags | kEnabledForEventCallback_CategoryGroupEnabledFlags
)) { uint64_t h = v8::internal::tracing::AddTraceEvent( ('X')
, trace_event_unique_category_group_enabled813, "wasm.ExecuteStartFunction"
, v8::internal::tracing::kGlobalScope, v8::internal::tracing::
kNoId, v8::internal::tracing::kNoId, (static_cast<unsigned
int>(0))); trace_event_unique_tracer813 .Initialize(trace_event_unique_category_group_enabled813
, "wasm.ExecuteStartFunction", h); }
813 "wasm.ExecuteStartFunction")static v8::base::AtomicWord trace_event_unique_atomic813 = 0;
const uint8_t* trace_event_unique_category_group_enabled813;
trace_event_unique_category_group_enabled813 = reinterpret_cast
<const uint8_t*>(v8::base::Relaxed_Load(&(trace_event_unique_atomic813
))); if (!trace_event_unique_category_group_enabled813) { trace_event_unique_category_group_enabled813
= v8::internal::tracing::TraceEventHelper::GetTracingController
() ->GetCategoryGroupEnabled("disabled-by-default-" "v8.wasm.detailed"
); v8::base::Relaxed_Store(&(trace_event_unique_atomic813
), (reinterpret_cast<v8::base::AtomicWord>( trace_event_unique_category_group_enabled813
))); };; v8::internal::tracing::ScopedTracer trace_event_unique_tracer813
; if (v8::base::Relaxed_Load(reinterpret_cast<const v8::base
::Atomic8*>( trace_event_unique_category_group_enabled813)
) & (kEnabledForRecording_CategoryGroupEnabledFlags | kEnabledForEventCallback_CategoryGroupEnabledFlags
)) { uint64_t h = v8::internal::tracing::AddTraceEvent( ('X')
, trace_event_unique_category_group_enabled813, "wasm.ExecuteStartFunction"
, v8::internal::tracing::kGlobalScope, v8::internal::tracing::
kNoId, v8::internal::tracing::kNoId, (static_cast<unsigned
int>(0))); trace_event_unique_tracer813 .Initialize(trace_event_unique_category_group_enabled813
, "wasm.ExecuteStartFunction", h); }
;
814 if (start_function_.is_null()) return true; // No start function.
815
816 HandleScope scope(isolate_);
817 // In case the start function calls out to Blink, we have to make sure that
818 // the correct "entered context" is available. This is the equivalent of
819 // v8::Context::Enter() and must happen in addition to the function call
820 // sequence doing the compiled version of "isolate->set_context(...)".
821 HandleScopeImplementer* hsi = isolate_->handle_scope_implementer();
822 hsi->EnterContext(start_function_->native_context());
823
824 // Call the JS function.
825 Handle<Object> undefined = isolate_->factory()->undefined_value();
826 MaybeHandle<Object> retval =
827 Execution::Call(isolate_, start_function_, undefined, 0, nullptr);
828 hsi->LeaveContext();
829
830 if (retval.is_null()) {
831 DCHECK(isolate_->has_pending_exception())((void) 0);
832 return false;
833 }
834 return true;
835}
836
837// Look up an import value in the {ffi_} object.
838MaybeHandle<Object> InstanceBuilder::LookupImport(uint32_t index,
839 Handle<String> module_name,
840 Handle<String> import_name) {
841 // We pre-validated in the js-api layer that the ffi object is present, and
842 // a JSObject, if the module has imports.
843 DCHECK(!ffi_.is_null())((void) 0);
844 // Look up the module first.
845 MaybeHandle<Object> result = Object::GetPropertyOrElement(
846 isolate_, ffi_.ToHandleChecked(), module_name);
847 if (result.is_null()) {
848 return ReportTypeError("module not found", index, module_name);
849 }
850
851 Handle<Object> module = result.ToHandleChecked();
852
853 // Look up the value in the module.
854 if (!module->IsJSReceiver()) {
855 return ReportTypeError("module is not an object or function", index,
856 module_name);
857 }
858
859 result = Object::GetPropertyOrElement(isolate_, module, import_name);
860 if (result.is_null()) {
861 ReportLinkError("import not found", index, module_name, import_name);
862 return MaybeHandle<JSFunction>();
863 }
864
865 return result;
866}
867
868namespace {
869bool HasDefaultToNumberBehaviour(Isolate* isolate,
870 Handle<JSFunction> function) {
871 // Disallow providing a [Symbol.toPrimitive] member.
872 LookupIterator to_primitive_it{isolate, function,
873 isolate->factory()->to_primitive_symbol()};
874 if (to_primitive_it.state() != LookupIterator::NOT_FOUND) return false;
875
876 // The {valueOf} member must be the default "ObjectPrototypeValueOf".
877 LookupIterator value_of_it{isolate, function,
878 isolate->factory()->valueOf_string()};
879 if (value_of_it.state() != LookupIterator::DATA) return false;
880 Handle<Object> value_of = value_of_it.GetDataValue();
881 if (!value_of->IsJSFunction()) return false;
882 Builtin value_of_builtin_id =
883 Handle<JSFunction>::cast(value_of)->code().builtin_id();
884 if (value_of_builtin_id != Builtin::kObjectPrototypeValueOf) return false;
885
886 // The {toString} member must be the default "FunctionPrototypeToString".
887 LookupIterator to_string_it{isolate, function,
888 isolate->factory()->toString_string()};
889 if (to_string_it.state() != LookupIterator::DATA) return false;
890 Handle<Object> to_string = to_string_it.GetDataValue();
891 if (!to_string->IsJSFunction()) return false;
892 Builtin to_string_builtin_id =
893 Handle<JSFunction>::cast(to_string)->code().builtin_id();
894 if (to_string_builtin_id != Builtin::kFunctionPrototypeToString) return false;
895
896 // Just a default function, which will convert to "Nan". Accept this.
897 return true;
898}
899
900V8_INLINEinline __attribute__((always_inline)) WasmValue EvaluateInitExpression(Zone* zone, ConstantExpression expr,
901 ValueType expected, Isolate* isolate,
902 Handle<WasmInstanceObject> instance,
903 ErrorThrower* thrower) {
904 switch (expr.kind()) {
905 case ConstantExpression::kEmpty:
906 UNREACHABLE()V8_Fatal("unreachable code");
907 case ConstantExpression::kI32Const:
908 return WasmValue(expr.i32_value());
909 case ConstantExpression::kRefNull:
910 return WasmValue(isolate->factory()->null_value(),
911 ValueType::Ref(expr.repr(), kNullable));
912 case ConstantExpression::kRefFunc: {
913 uint32_t index = expr.index();
914 Handle<Object> value =
915 WasmInstanceObject::GetOrCreateWasmInternalFunction(isolate, instance,
916 index);
917 return WasmValue(value, expected);
918 }
919 case ConstantExpression::kWireBytesRef: {
920 WireBytesRef ref = expr.wire_bytes_ref();
921
922 base::Vector<const byte> module_bytes =
923 instance->module_object().native_module()->wire_bytes();
924
925 const byte* start = module_bytes.begin() + ref.offset();
926 const byte* end = module_bytes.begin() + ref.end_offset();
927
928 auto sig = FixedSizeSignature<ValueType>::Returns(expected);
929 FunctionBody body(&sig, ref.offset(), start, end);
930 WasmFeatures detected;
931 // We use kFullValidation so we do not have to create another template
932 // instance of WasmFullDecoder, which would cost us >50Kb binary code
933 // size.
934 WasmFullDecoder<Decoder::kFullValidation, InitExprInterface,
935 kInitExpression>
936 decoder(zone, instance->module(), WasmFeatures::All(), &detected,
937 body, instance->module(), isolate, instance);
938
939 decoder.DecodeFunctionBody();
940
941 if (decoder.interface().runtime_error()) {
942 thrower->RuntimeError("%s", decoder.interface().runtime_error_msg());
943 return {};
944 }
945
946 return decoder.interface().result();
947 }
948 }
949}
950} // namespace
951
952// Look up an import value in the {ffi_} object specifically for linking an
953// asm.js module. This only performs non-observable lookups, which allows
954// falling back to JavaScript proper (and hence re-executing all lookups) if
955// module instantiation fails.
956MaybeHandle<Object> InstanceBuilder::LookupImportAsm(
957 uint32_t index, Handle<String> import_name) {
958 // Check that a foreign function interface object was provided.
959 if (ffi_.is_null()) {
960 return ReportLinkError("missing imports object", index, import_name);
961 }
962
963 // Perform lookup of the given {import_name} without causing any observable
964 // side-effect. We only accept accesses that resolve to data properties,
965 // which is indicated by the asm.js spec in section 7 ("Linking") as well.
966 PropertyKey key(isolate_, Handle<Name>::cast(import_name));
967 LookupIterator it(isolate_, ffi_.ToHandleChecked(), key);
968 switch (it.state()) {
969 case LookupIterator::ACCESS_CHECK:
970 case LookupIterator::INTEGER_INDEXED_EXOTIC:
971 case LookupIterator::INTERCEPTOR:
972 case LookupIterator::JSPROXY:
973 case LookupIterator::ACCESSOR:
974 case LookupIterator::TRANSITION:
975 return ReportLinkError("not a data property", index, import_name);
976 case LookupIterator::NOT_FOUND:
977 // Accepting missing properties as undefined does not cause any
978 // observable difference from JavaScript semantics, we are lenient.
979 return isolate_->factory()->undefined_value();
980 case LookupIterator::DATA: {
981 Handle<Object> value = it.GetDataValue();
982 // For legacy reasons, we accept functions for imported globals (see
983 // {ProcessImportedGlobal}), but only if we can easily determine that
984 // their Number-conversion is side effect free and returns NaN (which is
985 // the case as long as "valueOf" (or others) are not overwritten).
986 if (value->IsJSFunction() &&
987 module_->import_table[index].kind == kExternalGlobal &&
988 !HasDefaultToNumberBehaviour(isolate_,
989 Handle<JSFunction>::cast(value))) {
990 return ReportLinkError("function has special ToNumber behaviour", index,
991 import_name);
992 }
993 return value;
994 }
995 }
996}
997
998// Load data segments into the memory.
999void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
1000 base::Vector<const uint8_t> wire_bytes =
1001 module_object_->native_module()->wire_bytes();
1002 for (const WasmDataSegment& segment : module_->data_segments) {
1003 uint32_t size = segment.source.length();
1004
1005 // Passive segments are not copied during instantiation.
1006 if (!segment.active) continue;
1007
1008 size_t dest_offset;
1009 if (module_->is_memory64) {
1010 uint64_t dest_offset_64 =
1011 EvaluateInitExpression(&init_expr_zone_, segment.dest_addr, kWasmI64,
1012 isolate_, instance, thrower_)
1013 .to_u64();
1014 if (thrower_->error()) return;
1015 // Clamp to {std::numeric_limits<size_t>::max()}, which is always an
1016 // invalid offset.
1017 DCHECK_GT(std::numeric_limits<size_t>::max(), instance->memory_size())((void) 0);
1018 dest_offset = static_cast<size_t>(std::min(
1019 dest_offset_64, uint64_t{std::numeric_limits<size_t>::max()}));
1020 } else {
1021 dest_offset =
1022 EvaluateInitExpression(&init_expr_zone_, segment.dest_addr, kWasmI32,
1023 isolate_, instance, thrower_)
1024 .to_u32();
1025 if (thrower_->error()) return;
1026 }
1027
1028 if (!base::IsInBounds<size_t>(dest_offset, size, instance->memory_size())) {
1029 thrower_->RuntimeError("data segment is out of bounds");
1030 return;
1031 }
1032
1033 std::memcpy(instance->memory_start() + dest_offset,
1034 wire_bytes.begin() + segment.source.offset(), size);
1035 }
1036}
1037
1038void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global,
1039 const WasmValue& value) {
1040 TRACE("init [globals_start=%p + %u] = %s, type = %s\n",
1041 global.type.is_reference()
1042 ? reinterpret_cast<byte*>(tagged_globals_->address())
1043 : raw_buffer_ptr(untagged_globals_, 0),
1044 global.offset, value.to_string().c_str(), global.type.name().c_str());
1045 DCHECK(IsSubtypeOf(value.type(), global.type, module_))((void) 0);
1046 if (global.type.is_numeric()) {
1047 value.CopyTo(GetRawUntaggedGlobalPtr<byte>(global));
1048 } else {
1049 tagged_globals_->set(global.offset, *value.to_ref());
1050 }
1051}
1052
1053void InstanceBuilder::SanitizeImports() {
1054 base::Vector<const uint8_t> wire_bytes =
1055 module_object_->native_module()->wire_bytes();
1056 for (size_t index = 0; index < module_->import_table.size(); ++index) {
1057 const WasmImport& import = module_->import_table[index];
1058
1059 Handle<String> module_name =
1060 WasmModuleObject::ExtractUtf8StringFromModuleBytes(
1061 isolate_, wire_bytes, import.module_name, kInternalize);
1062
1063 Handle<String> import_name =
1064 WasmModuleObject::ExtractUtf8StringFromModuleBytes(
1065 isolate_, wire_bytes, import.field_name, kInternalize);
1066
1067 int int_index = static_cast<int>(index);
1068 MaybeHandle<Object> result =
1069 is_asmjs_module(module_)
1070 ? LookupImportAsm(int_index, import_name)
1071 : LookupImport(int_index, module_name, import_name);
1072 if (thrower_->error()) {
1073 thrower_->LinkError("Could not find value for import %zu", index);
1074 return;
1075 }
1076 Handle<Object> value = result.ToHandleChecked();
1077 sanitized_imports_.push_back({module_name, import_name, value});
1078 }
1079}
1080
1081bool InstanceBuilder::FindImportedMemory() {
1082 DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size())((void) 0);
1083 for (size_t index = 0; index < module_->import_table.size(); index++) {
1084 WasmImport import = module_->import_table[index];
1085
1086 if (import.kind == kExternalMemory) {
1087 auto& value = sanitized_imports_[index].value;
1088 if (!value->IsWasmMemoryObject()) return false;
1089 memory_object_ = Handle<WasmMemoryObject>::cast(value);
1090 memory_buffer_ =
1091 Handle<JSArrayBuffer>(memory_object_->array_buffer(), isolate_);
1092 return true;
1093 }
1094 }
1095 return false;
1096}
1097
1098bool InstanceBuilder::ProcessImportedFunction(
1099 Handle<WasmInstanceObject> instance, int import_index, int func_index,
1100 Handle<String> module_name, Handle<String> import_name,
1101 Handle<Object> value) {
1102 // Function imports must be callable.
1103 if (!value->IsCallable()) {
1104 ReportLinkError("function import requires a callable", import_index,
1105 module_name, import_name);
1106 return false;
1107 }
1108 // Store any {WasmExternalFunction} callable in the instance before the call
1109 // is resolved to preserve its identity. This handles exported functions as
1110 // well as functions constructed via other means (e.g. WebAssembly.Function).
1111 if (WasmExternalFunction::IsWasmExternalFunction(*value)) {
1112 WasmInstanceObject::SetWasmInternalFunction(
1113 isolate_, instance, func_index,
1114 WasmInternalFunction::FromExternal(
1115 Handle<WasmExternalFunction>::cast(value), isolate_)
1116 .ToHandleChecked());
1117 }
1118 auto js_receiver = Handle<JSReceiver>::cast(value);
1119 const FunctionSig* expected_sig = module_->functions[func_index].sig;
1120 auto resolved = compiler::ResolveWasmImportCall(js_receiver, expected_sig,
1121 module_, enabled_);
1122 compiler::WasmImportCallKind kind = resolved.kind;
1123 js_receiver = resolved.callable;
1124 switch (kind) {
1125 case compiler::WasmImportCallKind::kLinkError:
1126 ReportLinkError("imported function does not match the expected type",
1127 import_index, module_name, import_name);
1128 return false;
1129 case compiler::WasmImportCallKind::kWasmToWasm: {
1130 // The imported function is a Wasm function from another instance.
1131 auto imported_function = Handle<WasmExportedFunction>::cast(js_receiver);
1132 Handle<WasmInstanceObject> imported_instance(
1133 imported_function->instance(), isolate_);
1134 // The import reference is the instance object itself.
1135 Address imported_target = imported_function->GetWasmCallTarget();
1136 ImportedFunctionEntry entry(instance, func_index);
1137 entry.SetWasmToWasm(*imported_instance, imported_target);
1138 break;
1139 }
1140 case compiler::WasmImportCallKind::kWasmToCapi: {
1141 NativeModule* native_module = instance->module_object().native_module();
1142 int expected_arity = static_cast<int>(expected_sig->parameter_count());
1143 WasmImportWrapperCache* cache = native_module->import_wrapper_cache();
1144 // TODO(jkummerow): Consider precompiling CapiCallWrappers in parallel,
1145 // just like other import wrappers.
1146 WasmCode* wasm_code =
1147 cache->MaybeGet(kind, expected_sig, expected_arity, kNoSuspend);
1148 if (wasm_code == nullptr) {
1149 WasmCodeRefScope code_ref_scope;
1150 WasmImportWrapperCache::ModificationScope cache_scope(cache);
1151 wasm_code =
1152 compiler::CompileWasmCapiCallWrapper(native_module, expected_sig);
1153 WasmImportWrapperCache::CacheKey key(kind, expected_sig, expected_arity,
1154 kNoSuspend);
1155 cache_scope[key] = wasm_code;
1156 wasm_code->IncRef();
1157 isolate_->counters()->wasm_generated_code_size()->Increment(
1158 wasm_code->instructions().length());
1159 isolate_->counters()->wasm_reloc_size()->Increment(
1160 wasm_code->reloc_info().length());
1161 }
1162
1163 ImportedFunctionEntry entry(instance, func_index);
1164 // We re-use the SetWasmToJs infrastructure because it passes the
1165 // callable to the wrapper, which we need to get the function data.
1166 entry.SetWasmToJs(isolate_, js_receiver, wasm_code,
1167 isolate_->factory()->undefined_value());
1168 break;
1169 }
1170 case compiler::WasmImportCallKind::kWasmToJSFastApi: {
1171 NativeModule* native_module = instance->module_object().native_module();
1172 DCHECK(js_receiver->IsJSFunction())((void) 0);
1173 Handle<JSFunction> function = Handle<JSFunction>::cast(js_receiver);
1174
1175 WasmCodeRefScope code_ref_scope;
1176 WasmCode* wasm_code = compiler::CompileWasmJSFastCallWrapper(
1177 native_module, expected_sig, function);
1178 ImportedFunctionEntry entry(instance, func_index);
1179 entry.SetWasmToJs(isolate_, js_receiver, wasm_code,
1180 isolate_->factory()->undefined_value());
1181 break;
1182 }
1183 default: {
1184 // The imported function is a callable.
1185
1186 int expected_arity = static_cast<int>(expected_sig->parameter_count());
1187 if (kind == compiler::WasmImportCallKind::kJSFunctionArityMismatch) {
1188 Handle<JSFunction> function = Handle<JSFunction>::cast(js_receiver);
1189 SharedFunctionInfo shared = function->shared();
1190 expected_arity =
1191 shared.internal_formal_parameter_count_without_receiver();
1192 }
1193
1194 NativeModule* native_module = instance->module_object().native_module();
1195 Suspend suspend =
1196 resolved.suspender.is_null() || resolved.suspender->IsUndefined()
1197 ? kNoSuspend
1198 : kSuspend;
1199 WasmCode* wasm_code = native_module->import_wrapper_cache()->Get(
1200 kind, expected_sig, expected_arity, suspend);
1201 DCHECK_NOT_NULL(wasm_code)((void) 0);
1202 ImportedFunctionEntry entry(instance, func_index);
1203 if (wasm_code->kind() == WasmCode::kWasmToJsWrapper) {
1204 // Wasm to JS wrappers are treated specially in the import table.
1205 entry.SetWasmToJs(isolate_, js_receiver, wasm_code, resolved.suspender);
1206 } else {
1207 // Wasm math intrinsics are compiled as regular Wasm functions.
1208 DCHECK(kind >= compiler::WasmImportCallKind::kFirstMathIntrinsic &&((void) 0)
1209 kind <= compiler::WasmImportCallKind::kLastMathIntrinsic)((void) 0);
1210 entry.SetWasmToWasm(*instance, wasm_code->instruction_start());
1211 }
1212 break;
1213 }
1214 }
1215 return true;
1216}
1217
1218bool InstanceBuilder::InitializeImportedIndirectFunctionTable(
1219 Handle<WasmInstanceObject> instance, int table_index, int import_index,
1220 Handle<WasmTableObject> table_object) {
1221 int imported_table_size = table_object->current_length();
1222 // Allocate a new dispatch table.
1223 WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
1224 instance, table_index, imported_table_size);
1225 // Initialize the dispatch table with the (foreign) JS functions
1226 // that are already in the table.
1227 for (int i = 0; i < imported_table_size; ++i) {
1228 bool is_valid;
1229 bool is_null;
1230 MaybeHandle<WasmInstanceObject> maybe_target_instance;
1231 int function_index;
1232 MaybeHandle<WasmJSFunction> maybe_js_function;
1233 WasmTableObject::GetFunctionTableEntry(
1234 isolate_, module_, table_object, i, &is_valid, &is_null,
1235 &maybe_target_instance, &function_index, &maybe_js_function);
1236 if (!is_valid) {
1237 thrower_->LinkError("table import %d[%d] is not a wasm function",
1238 import_index, i);
1239 return false;
1240 }
1241 if (is_null) continue;
1242 Handle<WasmJSFunction> js_function;
1243 if (maybe_js_function.ToHandle(&js_function)) {
1244 WasmInstanceObject::ImportWasmJSFunctionIntoTable(
1245 isolate_, instance, table_index, i, js_function);
1246 continue;
1247 }
1248
1249 Handle<WasmInstanceObject> target_instance =
1250 maybe_target_instance.ToHandleChecked();
1251 const FunctionSig* sig = target_instance->module_object()
1252 .module()
1253 ->functions[function_index]
1254 .sig;
1255
1256 // Look up the signature's canonical id. If there is no canonical
1257 // id, then the signature does not appear at all in this module,
1258 // so putting {-1} in the table will cause checks to always fail.
1259 FunctionTargetAndRef entry(target_instance, function_index);
1260 instance->GetIndirectFunctionTable(isolate_, table_index)
1261 ->Set(i, module_->signature_map.Find(*sig), entry.call_target(),
1262 *entry.ref());
1263 }
1264 return true;
1265}
1266
1267bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance,
1268 int import_index, int table_index,
1269 Handle<String> module_name,
1270 Handle<String> import_name,
1271 Handle<Object> value) {
1272 if (!value->IsWasmTableObject()) {
1273 ReportLinkError("table import requires a WebAssembly.Table", import_index,
1274 module_name, import_name);
1275 return false;
1276 }
1277 const WasmTable& table = module_->tables[table_index];
1278
1279 auto table_object = Handle<WasmTableObject>::cast(value);
1280
1281 uint32_t imported_table_size =
1282 static_cast<uint32_t>(table_object->current_length());
1283 if (imported_table_size < table.initial_size) {
1284 thrower_->LinkError("table import %d is smaller than initial %u, got %u",
1285 import_index, table.initial_size, imported_table_size);
1286 return false;
1287 }
1288
1289 if (table.has_maximum_size) {
1290 if (table_object->maximum_length().IsUndefined(isolate_)) {
1291 thrower_->LinkError("table import %d has no maximum length, expected %u",
1292 import_index, table.maximum_size);
1293 return false;
1294 }
1295 int64_t imported_maximum_size = table_object->maximum_length().Number();
1296 if (imported_maximum_size < 0) {
1297 thrower_->LinkError("table import %d has no maximum length, expected %u",
1298 import_index, table.maximum_size);
1299 return false;
1300 }
1301 if (imported_maximum_size > table.maximum_size) {
1302 thrower_->LinkError("table import %d has a larger maximum size %" PRIx64"l" "x"
1303 " than the module's declared maximum %u",
1304 import_index, imported_maximum_size,
1305 table.maximum_size);
1306 return false;
1307 }
1308 }
1309
1310 const WasmModule* table_type_module =
1311 !table_object->instance().IsUndefined()
1312 ? WasmInstanceObject::cast(table_object->instance()).module()
1313 : instance->module();
1314
1315 if (!EquivalentTypes(table.type, table_object->type(), module_,
1316 table_type_module)) {
1317 ReportLinkError("imported table does not match the expected type",
1318 import_index, module_name, import_name);
1319 return false;
1320 }
1321
1322 if (IsSubtypeOf(table.type, kWasmFuncRef, module_) &&
1323 !InitializeImportedIndirectFunctionTable(instance, table_index,
1324 import_index, table_object)) {
1325 return false;
1326 }
1327
1328 instance->tables().set(table_index, *value);
1329 return true;
1330}
1331
1332bool InstanceBuilder::ProcessImportedMemory(Handle<WasmInstanceObject> instance,
1333 int import_index,
1334 Handle<String> module_name,
1335 Handle<String> import_name,
1336 Handle<Object> value) {
1337 if (!value->IsWasmMemoryObject()) {
1338 ReportLinkError("memory import must be a WebAssembly.Memory object",
1339 import_index, module_name, import_name);
1340 return false;
1341 }
1342 auto memory_object = Handle<WasmMemoryObject>::cast(value);
1343
1344 // The imported memory should have been already set up early.
1345 CHECK_EQ(instance->memory_object(), *memory_object)do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(instance->memory_object())
>::type, typename ::v8::base::pass_value_or_ref<decltype
(*memory_object)>::type>((instance->memory_object())
, (*memory_object)); do { if ((__builtin_expect(!!(!(_cmp)), 0
))) { V8_Fatal("Check failed: %s.", "instance->memory_object()"
" " "==" " " "*memory_object"); } } while (false); } while (
false)
;
1346
1347 Handle<JSArrayBuffer> buffer(memory_object_->array_buffer(), isolate_);
1348 // memory_ should have already been assigned in Build().
1349 DCHECK_EQ(*memory_buffer_.ToHandleChecked(), *buffer)((void) 0);
1350 uint32_t imported_cur_pages =
1351 static_cast<uint32_t>(buffer->byte_length() / kWasmPageSize);
1352 if (imported_cur_pages < module_->initial_pages) {
1353 thrower_->LinkError("memory import %d is smaller than initial %u, got %u",
1354 import_index, module_->initial_pages,
1355 imported_cur_pages);
1356 return false;
1357 }
1358 int32_t imported_maximum_pages = memory_object_->maximum_pages();
1359 if (module_->has_maximum_pages) {
1360 if (imported_maximum_pages < 0) {
1361 thrower_->LinkError(
1362 "memory import %d has no maximum limit, expected at most %u",
1363 import_index, imported_maximum_pages);
1364 return false;
1365 }
1366 if (static_cast<uint32_t>(imported_maximum_pages) >
1367 module_->maximum_pages) {
1368 thrower_->LinkError(
1369 "memory import %d has a larger maximum size %u than the "
1370 "module's declared maximum %u",
1371 import_index, imported_maximum_pages, module_->maximum_pages);
1372 return false;
1373 }
1374 }
1375 if (module_->has_shared_memory != buffer->is_shared()) {
1376 thrower_->LinkError(
1377 "mismatch in shared state of memory, declared = %d, imported = %d",
1378 module_->has_shared_memory, buffer->is_shared());
1379 return false;
1380 }
1381
1382 return true;
1383}
1384
1385bool InstanceBuilder::ProcessImportedWasmGlobalObject(
1386 Handle<WasmInstanceObject> instance, int import_index,
1387 Handle<String> module_name, Handle<String> import_name,
1388 const WasmGlobal& global, Handle<WasmGlobalObject> global_object) {
1389 if (static_cast<bool>(global_object->is_mutable()) != global.mutability) {
1390 ReportLinkError("imported global does not match the expected mutability",
1391 import_index, module_name, import_name);
1392 return false;
1393 }
1394
1395 const WasmModule* global_type_module =
1396 !global_object->instance().IsUndefined()
1397 ? WasmInstanceObject::cast(global_object->instance()).module()
1398 : instance->module();
1399
1400 bool valid_type =
1401 global.mutability
1402 ? EquivalentTypes(global_object->type(), global.type,
1403 global_type_module, instance->module())
1404 : IsSubtypeOf(global_object->type(), global.type, global_type_module,
1405 instance->module());
1406
1407 if (!valid_type) {
1408 ReportLinkError("imported global does not match the expected type",
1409 import_index, module_name, import_name);
1410 return false;
1411 }
1412 if (global.mutability) {
1413 DCHECK_LT(global.index, module_->num_imported_mutable_globals)((void) 0);
1414 Handle<Object> buffer;
1415 Address address_or_offset;
1416 if (global.type.is_reference()) {
1417 static_assert(sizeof(global_object->offset()) <= sizeof(Address),
1418 "The offset into the globals buffer does not fit into "
1419 "the imported_mutable_globals array");
1420 buffer = handle(global_object->tagged_buffer(), isolate_);
1421 // For externref globals we use a relative offset, not an absolute
1422 // address.
1423 address_or_offset = static_cast<Address>(global_object->offset());
1424 } else {
1425 buffer = handle(global_object->untagged_buffer(), isolate_);
1426 // It is safe in this case to store the raw pointer to the buffer
1427 // since the backing store of the JSArrayBuffer will not be
1428 // relocated.
1429 address_or_offset = reinterpret_cast<Address>(raw_buffer_ptr(
1430 Handle<JSArrayBuffer>::cast(buffer), global_object->offset()));
1431 }
1432 instance->imported_mutable_globals_buffers().set(global.index, *buffer);
1433 instance->imported_mutable_globals()[global.index] = address_or_offset;
1434 return true;
1435 }
1436
1437 WasmValue value;
1438 switch (global_object->type().kind()) {
1439 case kI32:
1440 value = WasmValue(global_object->GetI32());
1441 break;
1442 case kI64:
1443 value = WasmValue(global_object->GetI64());
1444 break;
1445 case kF32:
1446 value = WasmValue(global_object->GetF32());
1447 break;
1448 case kF64:
1449 value = WasmValue(global_object->GetF64());
1450 break;
1451 case kRtt:
1452 case kRef:
1453 case kOptRef:
1454 value = WasmValue(global_object->GetRef(), global_object->type());
1455 break;
1456 case kVoid:
1457 case kS128:
1458 case kBottom:
1459 case kI8:
1460 case kI16:
1461 UNREACHABLE()V8_Fatal("unreachable code");
1462 }
1463
1464 WriteGlobalValue(global, value);
1465 return true;
1466}
1467
1468bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
1469 int import_index, int global_index,
1470 Handle<String> module_name,
1471 Handle<String> import_name,
1472 Handle<Object> value) {
1473 // Immutable global imports are converted to numbers and written into
1474 // the {untagged_globals_} array buffer.
1475 //
1476 // Mutable global imports instead have their backing array buffers
1477 // referenced by this instance, and store the address of the imported
1478 // global in the {imported_mutable_globals_} array.
1479 const WasmGlobal& global = module_->globals[global_index];
1480
1481 // SIMD proposal allows modules to define an imported v128 global, and only
1482 // supports importing a WebAssembly.Global object for this global, but also
1483 // defines constructing a WebAssembly.Global of v128 to be a TypeError.
1484 // We *should* never hit this case in the JS API, but the module should should
1485 // be allowed to declare such a global (no validation error).
1486 if (global.type == kWasmS128 && !value->IsWasmGlobalObject()) {
1487 ReportLinkError("global import of type v128 must be a WebAssembly.Global",
1488 import_index, module_name, import_name);
1489 return false;
1490 }
1491
1492 if (is_asmjs_module(module_)) {
1493 // Accepting {JSFunction} on top of just primitive values here is a
1494 // workaround to support legacy asm.js code with broken binding. Note
1495 // that using {NaN} (or Smi::zero()) here is what using the observable
1496 // conversion via {ToPrimitive} would produce as well. {LookupImportAsm}
1497 // checked via {HasDefaultToNumberBehaviour} that "valueOf" or friends have
1498 // not been patched.
1499 if (value->IsJSFunction()) value = isolate_->factory()->nan_value();
1500 if (value->IsPrimitive()) {
1501 MaybeHandle<Object> converted = global.type == kWasmI32
1502 ? Object::ToInt32(isolate_, value)
1503 : Object::ToNumber(isolate_, value);
1504 if (!converted.ToHandle(&value)) {
1505 // Conversion is known to fail for Symbols and BigInts.
1506 ReportLinkError("global import must be a number", import_index,
1507 module_name, import_name);
1508 return false;
1509 }
1510 }
1511 }
1512
1513 if (value->IsWasmGlobalObject()) {
1514 auto global_object = Handle<WasmGlobalObject>::cast(value);
1515 return ProcessImportedWasmGlobalObject(instance, import_index, module_name,
1516 import_name, global, global_object);
1517 }
1518
1519 if (global.mutability) {
1520 ReportLinkError(
1521 "imported mutable global must be a WebAssembly.Global object",
1522 import_index, module_name, import_name);
1523 return false;
1524 }
1525
1526 if (global.type.is_reference()) {
1527 const char* error_message;
1528 if (!wasm::TypecheckJSObject(isolate_, module_, value, global.type,
1529 &error_message)) {
1530 ReportLinkError(error_message, global_index, module_name, import_name);
1531 return false;
1532 }
1533 if (IsSubtypeOf(global.type, kWasmFuncRef, module_) && !value->IsNull()) {
1534 value =
1535 WasmInternalFunction::FromExternal(value, isolate_).ToHandleChecked();
1536 }
1537 WriteGlobalValue(global, WasmValue(value, global.type));
1538 return true;
1539 }
1540
1541 if (value->IsNumber() && global.type != kWasmI64) {
1542 double number_value = value->Number();
1543 // The Wasm-BigInt proposal currently says that i64 globals may
1544 // only be initialized with BigInts. See:
1545 // https://github.com/WebAssembly/JS-BigInt-integration/issues/12
1546 WasmValue wasm_value = global.type == kWasmI32
1547 ? WasmValue(DoubleToInt32(number_value))
1548 : global.type == kWasmF32
1549 ? WasmValue(DoubleToFloat32(number_value))
1550 : WasmValue(number_value);
1551 WriteGlobalValue(global, wasm_value);
1552 return true;
1553 }
1554
1555 if (global.type == kWasmI64 && value->IsBigInt()) {
1556 WriteGlobalValue(global, WasmValue(BigInt::cast(*value).AsInt64()));
1557 return true;
1558 }
1559
1560 ReportLinkError(
1561 "global import must be a number, valid Wasm reference, or "
1562 "WebAssembly.Global object",
1563 import_index, module_name, import_name);
1564 return false;
1565}
1566
1567void InstanceBuilder::CompileImportWrappers(
1568 Handle<WasmInstanceObject> instance) {
1569 int num_imports = static_cast<int>(module_->import_table.size());
1570 TRACE_EVENT1("v8.wasm", "wasm.CompileImportWrappers", "num_imports",static v8::base::AtomicWord trace_event_unique_atomic1571 = 0
; const uint8_t* trace_event_unique_category_group_enabled1571
; trace_event_unique_category_group_enabled1571 = reinterpret_cast
<const uint8_t*>(v8::base::Relaxed_Load(&(trace_event_unique_atomic1571
))); if (!trace_event_unique_category_group_enabled1571) { trace_event_unique_category_group_enabled1571
= v8::internal::tracing::TraceEventHelper::GetTracingController
() ->GetCategoryGroupEnabled("v8.wasm"); v8::base::Relaxed_Store
(&(trace_event_unique_atomic1571), (reinterpret_cast<v8
::base::AtomicWord>( trace_event_unique_category_group_enabled1571
))); };; v8::internal::tracing::ScopedTracer trace_event_unique_tracer1571
; if (v8::base::Relaxed_Load(reinterpret_cast<const v8::base
::Atomic8*>( trace_event_unique_category_group_enabled1571
)) & (kEnabledForRecording_CategoryGroupEnabledFlags | kEnabledForEventCallback_CategoryGroupEnabledFlags
)) { uint64_t h = v8::internal::tracing::AddTraceEvent( ('X')
, trace_event_unique_category_group_enabled1571, "wasm.CompileImportWrappers"
, v8::internal::tracing::kGlobalScope, v8::internal::tracing::
kNoId, v8::internal::tracing::kNoId, (static_cast<unsigned
int>(0)), "num_imports", num_imports); trace_event_unique_tracer1571
.Initialize(trace_event_unique_category_group_enabled1571, "wasm.CompileImportWrappers"
, h); }
1571 num_imports)static v8::base::AtomicWord trace_event_unique_atomic1571 = 0
; const uint8_t* trace_event_unique_category_group_enabled1571
; trace_event_unique_category_group_enabled1571 = reinterpret_cast
<const uint8_t*>(v8::base::Relaxed_Load(&(trace_event_unique_atomic1571
))); if (!trace_event_unique_category_group_enabled1571) { trace_event_unique_category_group_enabled1571
= v8::internal::tracing::TraceEventHelper::GetTracingController
() ->GetCategoryGroupEnabled("v8.wasm"); v8::base::Relaxed_Store
(&(trace_event_unique_atomic1571), (reinterpret_cast<v8
::base::AtomicWord>( trace_event_unique_category_group_enabled1571
))); };; v8::internal::tracing::ScopedTracer trace_event_unique_tracer1571
; if (v8::base::Relaxed_Load(reinterpret_cast<const v8::base
::Atomic8*>( trace_event_unique_category_group_enabled1571
)) & (kEnabledForRecording_CategoryGroupEnabledFlags | kEnabledForEventCallback_CategoryGroupEnabledFlags
)) { uint64_t h = v8::internal::tracing::AddTraceEvent( ('X')
, trace_event_unique_category_group_enabled1571, "wasm.CompileImportWrappers"
, v8::internal::tracing::kGlobalScope, v8::internal::tracing::
kNoId, v8::internal::tracing::kNoId, (static_cast<unsigned
int>(0)), "num_imports", num_imports); trace_event_unique_tracer1571
.Initialize(trace_event_unique_category_group_enabled1571, "wasm.CompileImportWrappers"
, h); }
;
1572 NativeModule* native_module = instance->module_object().native_module();
1573 WasmImportWrapperCache::ModificationScope cache_scope(
1574 native_module->import_wrapper_cache());
1575
1576 // Compilation is done in two steps:
1577 // 1) Insert nullptr entries in the cache for wrappers that need to be
1578 // compiled. 2) Compile wrappers in background tasks using the
1579 // ImportWrapperQueue. This way the cache won't invalidate other iterators
1580 // when inserting a new WasmCode, since the key will already be there.
1581 ImportWrapperQueue import_wrapper_queue;
1582 for (int index = 0; index < num_imports; ++index) {
1583 Handle<Object> value = sanitized_imports_[index].value;
1584 if (module_->import_table[index].kind != kExternalFunction ||
1585 !value->IsCallable()) {
1586 continue;
1587 }
1588 auto js_receiver = Handle<JSReceiver>::cast(value);
1589 uint32_t func_index = module_->import_table[index].index;
1590 const FunctionSig* sig = module_->functions[func_index].sig;
1591 auto resolved =
1592 compiler::ResolveWasmImportCall(js_receiver, sig, module_, enabled_);
1593 compiler::WasmImportCallKind kind = resolved.kind;
1594 if (kind == compiler::WasmImportCallKind::kWasmToWasm ||
1595 kind == compiler::WasmImportCallKind::kLinkError ||
1596 kind == compiler::WasmImportCallKind::kWasmToCapi ||
1597 kind == compiler::WasmImportCallKind::kWasmToJSFastApi) {
1598 continue;
1599 }
1600
1601 int expected_arity = static_cast<int>(sig->parameter_count());
1602 if (resolved.kind ==
1603 compiler::WasmImportCallKind::kJSFunctionArityMismatch) {
1604 Handle<JSFunction> function = Handle<JSFunction>::cast(resolved.callable);
1605 SharedFunctionInfo shared = function->shared();
1606 expected_arity =
1607 shared.internal_formal_parameter_count_without_receiver();
1608 }
1609
1610 Suspend suspend =
1611 resolved.suspender.is_null() || resolved.suspender->IsUndefined()
1612 ? kNoSuspend
1613 : kSuspend;
1614 WasmImportWrapperCache::CacheKey key(kind, sig, expected_arity, suspend);
1615 if (cache_scope[key] != nullptr) {
1616 // Cache entry already exists, no need to compile it again.
1617 continue;
1618 }
1619 import_wrapper_queue.insert(key);
1620 }
1621
1622 auto compile_job_task = std::make_unique<CompileImportWrapperJob>(
1623 isolate_->counters(), native_module, &import_wrapper_queue, &cache_scope);
1624 auto compile_job = V8::GetCurrentPlatform()->PostJob(
1625 TaskPriority::kUserVisible, std::move(compile_job_task));
1626
1627 // Wait for the job to finish, while contributing in this thread.
1628 compile_job->Join();
1629}
1630
1631// Process the imports, including functions, tables, globals, and memory, in
1632// order, loading them from the {ffi_} object. Returns the number of imported
1633// functions.
1634int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
1635 int num_imported_functions = 0;
1636 int num_imported_tables = 0;
1637
1638 DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size())((void) 0);
1639
1640 CompileImportWrappers(instance);
1641 int num_imports = static_cast<int>(module_->import_table.size());
1642 for (int index = 0; index < num_imports; ++index) {
1643 const WasmImport& import = module_->import_table[index];
1644
1645 Handle<String> module_name = sanitized_imports_[index].module_name;
1646 Handle<String> import_name = sanitized_imports_[index].import_name;
1647 Handle<Object> value = sanitized_imports_[index].value;
1648
1649 switch (import.kind) {
1650 case kExternalFunction: {
1651 uint32_t func_index = import.index;
1652 DCHECK_EQ(num_imported_functions, func_index)((void) 0);
1653 if (!ProcessImportedFunction(instance, index, func_index, module_name,
1654 import_name, value)) {
1655 return -1;
1656 }
1657 num_imported_functions++;
1658 break;
1659 }
1660 case kExternalTable: {
1661 uint32_t table_index = import.index;
1662 DCHECK_EQ(table_index, num_imported_tables)((void) 0);
1663 if (!ProcessImportedTable(instance, index, table_index, module_name,
1664 import_name, value)) {
1665 return -1;
1666 }
1667 num_imported_tables++;
1668 USE(num_imported_tables)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{num_imported_tables
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
1669 break;
1670 }
1671 case kExternalMemory: {
1672 if (!ProcessImportedMemory(instance, index, module_name, import_name,
1673 value)) {
1674 return -1;
1675 }
1676 break;
1677 }
1678 case kExternalGlobal: {
1679 if (!ProcessImportedGlobal(instance, index, import.index, module_name,
1680 import_name, value)) {
1681 return -1;
1682 }
1683 break;
1684 }
1685 case kExternalTag: {
1686 if (!value->IsWasmTagObject()) {
1687 ReportLinkError("tag import requires a WebAssembly.Tag", index,
1688 module_name, import_name);
1689 return -1;
1690 }
1691 Handle<WasmTagObject> imported_tag = Handle<WasmTagObject>::cast(value);
1692 if (!imported_tag->MatchesSignature(module_->tags[import.index].sig)) {
1693 ReportLinkError("imported tag does not match the expected type",
1694 index, module_name, import_name);
1695 return -1;
1696 }
1697 Object tag = imported_tag->tag();
1698 DCHECK(instance->tags_table().get(import.index).IsUndefined())((void) 0);
1699 instance->tags_table().set(import.index, tag);
1700 tags_wrappers_[import.index] = imported_tag;
1701 break;
1702 }
1703 default:
1704 UNREACHABLE()V8_Fatal("unreachable code");
1705 }
1706 }
1707 return num_imported_functions;
1708}
1709
1710template <typename T>
1711T* InstanceBuilder::GetRawUntaggedGlobalPtr(const WasmGlobal& global) {
1712 return reinterpret_cast<T*>(raw_buffer_ptr(untagged_globals_, global.offset));
1713}
1714
1715// Process initialization of globals.
1716void InstanceBuilder::InitGlobals(Handle<WasmInstanceObject> instance) {
1717 for (const WasmGlobal& global : module_->globals) {
1718 if (global.mutability && global.imported) continue;
1719 // Happens with imported globals.
1720 if (!global.init.is_set()) continue;
1721
1722 WasmValue value =
1723 EvaluateInitExpression(&init_expr_zone_, global.init, global.type,
1724 isolate_, instance, thrower_);
1725 if (thrower_->error()) return;
1726
1727 if (global.type.is_reference()) {
1728 tagged_globals_->set(global.offset, *value.to_ref());
1729 } else {
1730 value.CopyTo(GetRawUntaggedGlobalPtr<byte>(global));
1731 }
1732 }
1733}
1734
1735// Allocate memory for a module instance as a new JSArrayBuffer.
1736bool InstanceBuilder::AllocateMemory() {
1737 int initial_pages = static_cast<int>(module_->initial_pages);
1738 int maximum_pages = module_->has_maximum_pages
1739 ? static_cast<int>(module_->maximum_pages)
1740 : WasmMemoryObject::kNoMaximum;
1741 auto shared = (module_->has_shared_memory && enabled_.has_threads())
1742 ? SharedFlag::kShared
1743 : SharedFlag::kNotShared;
1744
1745 if (!WasmMemoryObject::New(isolate_, initial_pages, maximum_pages, shared)
1746 .ToHandle(&memory_object_)) {
1747 thrower_->RangeError("Out of memory: wasm memory");
1748 return false;
1749 }
1750 memory_buffer_ =
1751 Handle<JSArrayBuffer>(memory_object_->array_buffer(), isolate_);
1752 return true;
1753}
1754
1755// Process the exports, creating wrappers for functions, tables, memories,
1756// globals, and exceptions.
1757void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
1758 std::unordered_map<int, Handle<Object>> imported_globals;
1759
1760 // If an imported WebAssembly function or global gets exported, the export
1761 // has to be identical to to import. Therefore we cache all imported
1762 // WebAssembly functions in the instance, and all imported globals in a map
1763 // here.
1764 for (int index = 0, end = static_cast<int>(module_->import_table.size());
1765 index < end; ++index) {
1766 const WasmImport& import = module_->import_table[index];
1767 if (import.kind == kExternalFunction) {
1768 Handle<Object> value = sanitized_imports_[index].value;
1769 if (WasmExternalFunction::IsWasmExternalFunction(*value)) {
1770 WasmInstanceObject::SetWasmInternalFunction(
1771 isolate_, instance, import.index,
1772 WasmInternalFunction::FromExternal(
1773 Handle<WasmExternalFunction>::cast(value), isolate_)
1774 .ToHandleChecked());
1775 }
1776 } else if (import.kind == kExternalGlobal) {
1777 Handle<Object> value = sanitized_imports_[index].value;
1778 if (value->IsWasmGlobalObject()) {
1779 imported_globals[import.index] = value;
1780 }
1781 }
1782 }
1783
1784 Handle<JSObject> exports_object;
1785 MaybeHandle<String> single_function_name;
1786 bool is_asm_js = is_asmjs_module(module_);
1787 if (is_asm_js) {
1788 Handle<JSFunction> object_function = Handle<JSFunction>(
1789 isolate_->native_context()->object_function(), isolate_);
1790 exports_object = isolate_->factory()->NewJSObject(object_function);
1791 single_function_name =
1792 isolate_->factory()->InternalizeUtf8String(AsmJs::kSingleFunctionName);
1793 } else {
1794 exports_object = isolate_->factory()->NewJSObjectWithNullProto();
1795 }
1796 instance->set_exports_object(*exports_object);
1797
1798 PropertyDescriptor desc;
1799 desc.set_writable(is_asm_js);
1800 desc.set_enumerable(true);
1801 desc.set_configurable(is_asm_js);
1802
1803 // Process each export in the export table.
1804 for (const WasmExport& exp : module_->export_table) {
1805 Handle<String> name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
1806 isolate_, module_object_, exp.name, kInternalize);
1807 Handle<JSObject> export_to = exports_object;
1808 switch (exp.kind) {
1809 case kExternalFunction: {
1810 // Wrap and export the code as a JSFunction.
1811 // TODO(wasm): reduce duplication with LoadElemSegment() further below
1812 Handle<WasmInternalFunction> internal =
1813 WasmInstanceObject::GetOrCreateWasmInternalFunction(
1814 isolate_, instance, exp.index);
1815 Handle<WasmExternalFunction> wasm_external_function =
1816 handle(WasmExternalFunction::cast(internal->external()), isolate_);
1817 desc.set_value(wasm_external_function);
1818
1819 if (is_asm_js &&
1820 String::Equals(isolate_, name,
1821 single_function_name.ToHandleChecked())) {
1822 export_to = instance;
1823 }
1824 break;
1825 }
1826 case kExternalTable: {
1827 desc.set_value(handle(instance->tables().get(exp.index), isolate_));
1828 break;
1829 }
1830 case kExternalMemory: {
1831 // Export the memory as a WebAssembly.Memory object. A WasmMemoryObject
1832 // should already be available if the module has memory, since we always
1833 // create or import it when building an WasmInstanceObject.
1834 DCHECK(instance->has_memory_object())((void) 0);
1835 desc.set_value(
1836 Handle<WasmMemoryObject>(instance->memory_object(), isolate_));
1837 break;
1838 }
1839 case kExternalGlobal: {
1840 const WasmGlobal& global = module_->globals[exp.index];
1841 if (global.imported) {
1842 auto cached_global = imported_globals.find(exp.index);
1843 if (cached_global != imported_globals.end()) {
1844 desc.set_value(cached_global->second);
1845 break;
1846 }
1847 }
1848 Handle<JSArrayBuffer> untagged_buffer;
1849 Handle<FixedArray> tagged_buffer;
1850 uint32_t offset;
1851
1852 if (global.mutability && global.imported) {
1853 Handle<FixedArray> buffers_array(
1854 instance->imported_mutable_globals_buffers(), isolate_);
1855 if (global.type.is_reference()) {
1856 tagged_buffer = handle(
1857 FixedArray::cast(buffers_array->get(global.index)), isolate_);
1858 // For externref globals we store the relative offset in the
1859 // imported_mutable_globals array instead of an absolute address.
1860 Address addr = instance->imported_mutable_globals()[global.index];
1861 DCHECK_LE(addr, static_cast<Address>(((void) 0)
1862 std::numeric_limits<uint32_t>::max()))((void) 0);
1863 offset = static_cast<uint32_t>(addr);
1864 } else {
1865 untagged_buffer =
1866 handle(JSArrayBuffer::cast(buffers_array->get(global.index)),
1867 isolate_);
1868 Address global_addr =
1869 instance->imported_mutable_globals()[global.index];
1870
1871 size_t buffer_size = untagged_buffer->byte_length();
1872 Address backing_store =
1873 reinterpret_cast<Address>(untagged_buffer->backing_store());
1874 CHECK(global_addr >= backing_store &&do { if ((__builtin_expect(!!(!(global_addr >= backing_store
&& global_addr < backing_store + buffer_size)), 0
))) { V8_Fatal("Check failed: %s.", "global_addr >= backing_store && global_addr < backing_store + buffer_size"
); } } while (false)
1875 global_addr < backing_store + buffer_size)do { if ((__builtin_expect(!!(!(global_addr >= backing_store
&& global_addr < backing_store + buffer_size)), 0
))) { V8_Fatal("Check failed: %s.", "global_addr >= backing_store && global_addr < backing_store + buffer_size"
); } } while (false)
;
1876 offset = static_cast<uint32_t>(global_addr - backing_store);
1877 }
1878 } else {
1879 if (global.type.is_reference()) {
1880 tagged_buffer = handle(instance->tagged_globals_buffer(), isolate_);
1881 } else {
1882 untagged_buffer =
1883 handle(instance->untagged_globals_buffer(), isolate_);
1884 }
1885 offset = global.offset;
1886 }
1887
1888 // Since the global's array untagged_buffer is always provided,
1889 // allocation should never fail.
1890 Handle<WasmGlobalObject> global_obj =
1891 WasmGlobalObject::New(isolate_, instance, untagged_buffer,
1892 tagged_buffer, global.type, offset,
1893 global.mutability)
1894 .ToHandleChecked();
1895 desc.set_value(global_obj);
1896 break;
1897 }
1898 case kExternalTag: {
1899 const WasmTag& tag = module_->tags[exp.index];
1900 Handle<WasmTagObject> wrapper = tags_wrappers_[exp.index];
1901 if (wrapper.is_null()) {
1902 Handle<HeapObject> tag_object(
1903 HeapObject::cast(instance->tags_table().get(exp.index)),
1904 isolate_);
1905 wrapper = WasmTagObject::New(isolate_, tag.sig, tag_object);
1906 tags_wrappers_[exp.index] = wrapper;
1907 }
1908 desc.set_value(wrapper);
1909 break;
1910 }
1911 default:
1912 UNREACHABLE()V8_Fatal("unreachable code");
1913 }
1914
1915 v8::Maybe<bool> status = JSReceiver::DefineOwnProperty(
1916 isolate_, export_to, name, &desc, Just(kThrowOnError));
1917 if (!status.IsJust()) {
1918 DisallowGarbageCollection no_gc;
1919 TruncatedUserString<> trunc_name(name->GetCharVector<uint8_t>(no_gc));
1920 thrower_->LinkError("export of %.*s failed.", trunc_name.length(),
1921 trunc_name.start());
1922 return;
1923 }
1924 }
1925
1926 if (module_->origin == kWasmOrigin) {
1927 v8::Maybe<bool> success =
1928 JSReceiver::SetIntegrityLevel(exports_object, FROZEN, kDontThrow);
1929 DCHECK(success.FromMaybe(false))((void) 0);
1930 USE(success)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{success
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
1931 }
1932}
1933
1934namespace {
1935V8_INLINEinline __attribute__((always_inline)) void SetFunctionTablePlaceholder(Isolate* isolate,
1936 Handle<WasmInstanceObject> instance,
1937 Handle<WasmTableObject> table_object,
1938 uint32_t entry_index,
1939 uint32_t func_index) {
1940 const WasmModule* module = instance->module();
1941 const WasmFunction* function = &module->functions[func_index];
1942 MaybeHandle<WasmInternalFunction> wasm_internal_function =
1943 WasmInstanceObject::GetWasmInternalFunction(isolate, instance,
1944 func_index);
1945 if (wasm_internal_function.is_null()) {
1946 // No JSFunction entry yet exists for this function. Create a {Tuple2}
1947 // holding the information to lazily allocate one.
1948 WasmTableObject::SetFunctionTablePlaceholder(
1949 isolate, table_object, entry_index, instance, func_index);
1950 } else {
1951 table_object->entries().set(entry_index,
1952 *wasm_internal_function.ToHandleChecked());
1953 }
1954 WasmTableObject::UpdateDispatchTables(isolate, *table_object, entry_index,
1955 function, *instance);
1956}
1957
1958V8_INLINEinline __attribute__((always_inline)) void SetFunctionTableNullEntry(Isolate* isolate,
1959 Handle<WasmTableObject> table_object,
1960 uint32_t entry_index) {
1961 table_object->entries().set(entry_index, *isolate->factory()->null_value());
1962 WasmTableObject::ClearDispatchTables(isolate, table_object, entry_index);
1963}
1964} // namespace
1965
1966void InstanceBuilder::InitializeNonDefaultableTables(
1967 Handle<WasmInstanceObject> instance) {
1968 for (int table_index = 0;
1969 table_index < static_cast<int>(module_->tables.size()); ++table_index) {
1970 const WasmTable& table = module_->tables[table_index];
1971 if (!table.type.is_defaultable()) {
1972 auto table_object = handle(
1973 WasmTableObject::cast(instance->tables().get(table_index)), isolate_);
1974 bool is_function_table = IsSubtypeOf(table.type, kWasmFuncRef, module_);
1975 if (is_function_table &&
1976 table.initial_value.kind() == ConstantExpression::kRefFunc) {
1977 for (uint32_t entry_index = 0; entry_index < table.initial_size;
1978 entry_index++) {
1979 SetFunctionTablePlaceholder(isolate_, instance, table_object,
1980 entry_index, table.initial_value.index());
1981 }
1982 } else if (is_function_table &&
1983 table.initial_value.kind() == ConstantExpression::kRefNull) {
1984 for (uint32_t entry_index = 0; entry_index < table.initial_size;
1985 entry_index++) {
1986 SetFunctionTableNullEntry(isolate_, table_object, entry_index);
1987 }
1988 } else {
1989 WasmValue value =
1990 EvaluateInitExpression(&init_expr_zone_, table.initial_value,
1991 table.type, isolate_, instance, thrower_);
1992 if (thrower_->error()) return;
1993 for (uint32_t entry_index = 0; entry_index < table.initial_size;
1994 entry_index++) {
1995 WasmTableObject::Set(isolate_, table_object, entry_index,
1996 value.to_ref());
1997 }
1998 }
1999 }
2000}
2001}
2002
2003namespace {
2004bool LoadElemSegmentImpl(Zone* zone, Isolate* isolate,
2005 Handle<WasmInstanceObject> instance,
2006 Handle<WasmTableObject> table_object,
2007 uint32_t table_index, uint32_t segment_index,
2008 uint32_t dst, uint32_t src, size_t count) {
2009 DCHECK_LT(segment_index, instance->module()->elem_segments.size())((void) 0);
2010 auto& elem_segment = instance->module()->elem_segments[segment_index];
2011 // TODO(wasm): Move this functionality into wasm-objects, since it is used
2012 // for both instantiation and in the implementation of the table.init
2013 // instruction.
2014 if (!base::IsInBounds<uint64_t>(dst, count, table_object->current_length()) ||
2015 !base::IsInBounds<uint64_t>(
2016 src, count,
2017 instance->dropped_elem_segments()[segment_index] == 0
2018 ? elem_segment.entries.size()
2019 : 0)) {
2020 return false;
2021 }
2022
2023 bool is_function_table =
2024 IsSubtypeOf(table_object->type(), kWasmFuncRef, instance->module());
2025
2026 ErrorThrower thrower(isolate, "LoadElemSegment");
2027
2028 for (size_t i = 0; i < count; ++i) {
2029 ConstantExpression entry = elem_segment.entries[src + i];
2030 int entry_index = static_cast<int>(dst + i);
2031 if (is_function_table && entry.kind() == ConstantExpression::kRefFunc) {
2032 SetFunctionTablePlaceholder(isolate, instance, table_object, entry_index,
2033 entry.index());
2034 } else if (is_function_table &&
2035 entry.kind() == ConstantExpression::kRefNull) {
2036 SetFunctionTableNullEntry(isolate, table_object, entry_index);
2037 } else {
2038 WasmValue value = EvaluateInitExpression(zone, entry, elem_segment.type,
2039 isolate, instance, &thrower);
2040 if (thrower.error()) return false;
2041 WasmTableObject::Set(isolate, table_object, entry_index, value.to_ref());
2042 }
2043 }
2044 return true;
2045}
2046} // namespace
2047
2048void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
2049 for (uint32_t segment_index = 0;
2050 segment_index < module_->elem_segments.size(); ++segment_index) {
2051 auto& elem_segment = instance->module()->elem_segments[segment_index];
2052 // Passive segments are not copied during instantiation.
2053 if (elem_segment.status != WasmElemSegment::kStatusActive) continue;
2054
2055 uint32_t table_index = elem_segment.table_index;
2056 uint32_t dst =
2057 EvaluateInitExpression(&init_expr_zone_, elem_segment.offset, kWasmI32,
2058 isolate_, instance, thrower_)
2059 .to_u32();
2060 if (thrower_->error()) return;
2061 uint32_t src = 0;
2062 size_t count = elem_segment.entries.size();
2063
2064 bool success = LoadElemSegmentImpl(
2065 &init_expr_zone_, isolate_, instance,
2066 handle(WasmTableObject::cast(
2067 instance->tables().get(elem_segment.table_index)),
2068 isolate_),
2069 table_index, segment_index, dst, src, count);
2070 // Set the active segments to being already dropped, since table.init on
2071 // a dropped passive segment and an active segment have the same behavior.
2072 instance->dropped_elem_segments()[segment_index] = 1;
2073 if (!success) {
2074 thrower_->RuntimeError("table initializer is out of bounds");
2075 return;
2076 }
2077 }
2078}
2079
2080void InstanceBuilder::InitializeTags(Handle<WasmInstanceObject> instance) {
2081 Handle<FixedArray> tags_table(instance->tags_table(), isolate_);
2082 for (int index = 0; index < tags_table->length(); ++index) {
2083 if (!tags_table->get(index).IsUndefined(isolate_)) continue;
2084 Handle<WasmExceptionTag> tag = WasmExceptionTag::New(isolate_, index);
2085 tags_table->set(index, *tag);
2086 }
2087}
2088
2089bool LoadElemSegment(Isolate* isolate, Handle<WasmInstanceObject> instance,
2090 uint32_t table_index, uint32_t segment_index, uint32_t dst,
2091 uint32_t src, uint32_t count) {
2092 AccountingAllocator allocator;
2093 // This {Zone} will be used only by the temporary WasmFullDecoder allocated
2094 // down the line from this call. Therefore it is safe to stack-allocate it
2095 // here.
2096 Zone zone(&allocator, "LoadElemSegment");
2097 return LoadElemSegmentImpl(
2098 &zone, isolate, instance,
2099 handle(WasmTableObject::cast(instance->tables().get(table_index)),
2100 isolate),
2101 table_index, segment_index, dst, src, count);
2102}
2103
2104} // namespace wasm
2105} // namespace internal
2106} // namespace v8
2107
2108#undef TRACE