1// Copyright 2021 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/init-expr-interface.h"
6
7#include "src/execution/isolate.h"
8#include "src/handles/handles-inl.h"
9#include "src/objects/fixed-array-inl.h"
10#include "src/objects/oddball.h"
11#include "src/roots/roots-inl.h"
12#include "src/wasm/decoder.h"
13#include "src/wasm/function-body-decoder-impl.h"
14#include "src/wasm/wasm-objects.h"
15
16namespace v8 {
17namespace internal {
18namespace wasm {
19
20void InitExprInterface::I32Const(FullDecoder* decoder, Value* result,
21                                 int32_t value) {
22  if (generate_result()) result->runtime_value = WasmValue(value);
23}
24
25void InitExprInterface::I64Const(FullDecoder* decoder, Value* result,
26                                 int64_t value) {
27  if (generate_result()) result->runtime_value = WasmValue(value);
28}
29
30void InitExprInterface::F32Const(FullDecoder* decoder, Value* result,
31                                 float value) {
32  if (generate_result()) result->runtime_value = WasmValue(value);
33}
34
35void InitExprInterface::F64Const(FullDecoder* decoder, Value* result,
36                                 double value) {
37  if (generate_result()) result->runtime_value = WasmValue(value);
38}
39
40void InitExprInterface::S128Const(FullDecoder* decoder,
41                                  Simd128Immediate<validate>& imm,
42                                  Value* result) {
43  if (!generate_result()) return;
44  result->runtime_value = WasmValue(imm.value, kWasmS128);
45}
46
47void InitExprInterface::BinOp(FullDecoder* decoder, WasmOpcode opcode,
48                              const Value& lhs, const Value& rhs,
49                              Value* result) {
50  if (!generate_result()) return;
51  switch (opcode) {
52    case kExprI32Add:
53      result->runtime_value =
54          WasmValue(lhs.runtime_value.to_i32() + rhs.runtime_value.to_i32());
55      break;
56    case kExprI32Sub:
57      result->runtime_value =
58          WasmValue(lhs.runtime_value.to_i32() - rhs.runtime_value.to_i32());
59      break;
60    case kExprI32Mul:
61      result->runtime_value =
62          WasmValue(lhs.runtime_value.to_i32() * rhs.runtime_value.to_i32());
63      break;
64    case kExprI64Add:
65      result->runtime_value =
66          WasmValue(lhs.runtime_value.to_i64() + rhs.runtime_value.to_i64());
67      break;
68    case kExprI64Sub:
69      result->runtime_value =
70          WasmValue(lhs.runtime_value.to_i64() - rhs.runtime_value.to_i64());
71      break;
72    case kExprI64Mul:
73      result->runtime_value =
74          WasmValue(lhs.runtime_value.to_i64() * rhs.runtime_value.to_i64());
75      break;
76    default:
77      UNREACHABLE();
78  }
79}
80
81void InitExprInterface::RefNull(FullDecoder* decoder, ValueType type,
82                                Value* result) {
83  if (!generate_result()) return;
84  result->runtime_value = WasmValue(isolate_->factory()->null_value(), type);
85}
86
87void InitExprInterface::RefFunc(FullDecoder* decoder, uint32_t function_index,
88                                Value* result) {
89  if (isolate_ == nullptr) {
90    outer_module_->functions[function_index].declared = true;
91    return;
92  }
93  if (!generate_result()) return;
94  ValueType type = ValueType::Ref(module_->functions[function_index].sig_index,
95                                  kNonNullable);
96  Handle<WasmInternalFunction> internal =
97      WasmInstanceObject::GetOrCreateWasmInternalFunction(isolate_, instance_,
98                                                          function_index);
99  result->runtime_value = WasmValue(internal, type);
100}
101
102void InitExprInterface::GlobalGet(FullDecoder* decoder, Value* result,
103                                  const GlobalIndexImmediate<validate>& imm) {
104  if (!generate_result()) return;
105  const WasmGlobal& global = module_->globals[imm.index];
106  DCHECK(!global.mutability);
107  result->runtime_value =
108      global.type.is_numeric()
109          ? WasmValue(
110                reinterpret_cast<byte*>(
111                    instance_->untagged_globals_buffer().backing_store()) +
112                    global.offset,
113                global.type)
114          : WasmValue(
115                handle(instance_->tagged_globals_buffer().get(global.offset),
116                       isolate_),
117                global.type);
118}
119
120void InitExprInterface::StructNewWithRtt(
121    FullDecoder* decoder, const StructIndexImmediate<validate>& imm,
122    const Value& rtt, const Value args[], Value* result) {
123  if (!generate_result()) return;
124  std::vector<WasmValue> field_values(imm.struct_type->field_count());
125  for (size_t i = 0; i < field_values.size(); i++) {
126    field_values[i] = args[i].runtime_value;
127  }
128  result->runtime_value =
129      WasmValue(isolate_->factory()->NewWasmStruct(
130                    imm.struct_type, field_values.data(),
131                    Handle<Map>::cast(rtt.runtime_value.to_ref())),
132                ValueType::Ref(HeapType(imm.index), kNonNullable));
133}
134
135namespace {
136WasmValue DefaultValueForType(ValueType type, Isolate* isolate) {
137  switch (type.kind()) {
138    case kI32:
139    case kI8:
140    case kI16:
141      return WasmValue(0);
142    case kI64:
143      return WasmValue(int64_t{0});
144    case kF32:
145      return WasmValue(0.0f);
146    case kF64:
147      return WasmValue(0.0);
148    case kS128:
149      return WasmValue(Simd128());
150    case kOptRef:
151      return WasmValue(isolate->factory()->null_value(), type);
152    case kVoid:
153    case kRtt:
154    case kRef:
155    case kBottom:
156      UNREACHABLE();
157  }
158}
159}  // namespace
160
161void InitExprInterface::StructNewDefault(
162    FullDecoder* decoder, const StructIndexImmediate<validate>& imm,
163    const Value& rtt, Value* result) {
164  if (!generate_result()) return;
165  std::vector<WasmValue> field_values(imm.struct_type->field_count());
166  for (uint32_t i = 0; i < field_values.size(); i++) {
167    field_values[i] = DefaultValueForType(imm.struct_type->field(i), isolate_);
168  }
169  result->runtime_value =
170      WasmValue(isolate_->factory()->NewWasmStruct(
171                    imm.struct_type, field_values.data(),
172                    Handle<Map>::cast(rtt.runtime_value.to_ref())),
173                ValueType::Ref(HeapType(imm.index), kNonNullable));
174}
175
176void InitExprInterface::ArrayInit(FullDecoder* decoder,
177                                  const ArrayIndexImmediate<validate>& imm,
178                                  const base::Vector<Value>& elements,
179                                  const Value& rtt, Value* result) {
180  if (!generate_result()) return;
181  std::vector<WasmValue> element_values;
182  for (Value elem : elements) element_values.push_back(elem.runtime_value);
183  result->runtime_value =
184      WasmValue(isolate_->factory()->NewWasmArrayFromElements(
185                    imm.array_type, element_values,
186                    Handle<Map>::cast(rtt.runtime_value.to_ref())),
187                ValueType::Ref(HeapType(imm.index), kNonNullable));
188}
189
190void InitExprInterface::ArrayInitFromData(
191    FullDecoder* decoder, const ArrayIndexImmediate<validate>& array_imm,
192    const IndexImmediate<validate>& data_segment_imm, const Value& offset_value,
193    const Value& length_value, const Value& rtt, Value* result) {
194  if (!generate_result()) return;
195
196  uint32_t length = length_value.runtime_value.to_u32();
197  uint32_t offset = offset_value.runtime_value.to_u32();
198  const WasmDataSegment& data_segment =
199      module_->data_segments[data_segment_imm.index];
200  uint32_t length_in_bytes =
201      length * array_imm.array_type->element_type().value_kind_size();
202
203  // Error handling.
204  if (length >
205      static_cast<uint32_t>(WasmArray::MaxLength(array_imm.array_type))) {
206    error_ = "length for array.init_from_data too large";
207    return;
208  }
209  if (!base::IsInBounds<uint32_t>(offset, length_in_bytes,
210                                  data_segment.source.length())) {
211    error_ = "data segment is out of bounds";
212    return;
213  }
214
215  Address source =
216      instance_->data_segment_starts()[data_segment_imm.index] + offset;
217  Handle<WasmArray> array_value = isolate_->factory()->NewWasmArrayFromMemory(
218      length, Handle<Map>::cast(rtt.runtime_value.to_ref()), source);
219  result->runtime_value = WasmValue(
220      array_value, ValueType::Ref(HeapType(array_imm.index), kNonNullable));
221}
222
223void InitExprInterface::RttCanon(FullDecoder* decoder, uint32_t type_index,
224                                 Value* result) {
225  if (!generate_result()) return;
226  result->runtime_value = WasmValue(
227      handle(instance_->managed_object_maps().get(type_index), isolate_),
228      ValueType::Rtt(type_index));
229}
230
231void InitExprInterface::DoReturn(FullDecoder* decoder,
232                                 uint32_t /*drop_values*/) {
233  end_found_ = true;
234  // End decoding on "end".
235  decoder->set_end(decoder->pc() + 1);
236  if (generate_result()) result_ = decoder->stack_value(1)->runtime_value;
237}
238
239}  // namespace wasm
240}  // namespace internal
241}  // namespace v8
242