Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(449)

Side by Side Diff: runtime/lib/typeddata.cc

Issue 14426006: Rename dart:typeddata to dart:typed_data. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/lib/typed_data_sources.gypi ('k') | runtime/lib/typeddata.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "vm/bootstrap_natives.h"
6
7 #include "include/dart_api.h"
8
9 #include "vm/bigint_operations.h"
10 #include "vm/exceptions.h"
11 #include "vm/native_entry.h"
12 #include "vm/object.h"
13
14 namespace dart {
15
16 // TypedData.
17
18 // Checks to see if offset_in_bytes is in the range.
19 static bool RangeCheck(intptr_t offset_in_bytes, intptr_t length_in_bytes) {
20 return ((offset_in_bytes >= 0) &&
21 (length_in_bytes > 0) &&
22 (offset_in_bytes < length_in_bytes));
23 }
24
25
26 // Checks to see if offsetInBytes + num_bytes is in the range.
27 static void SetRangeCheck(intptr_t offset_in_bytes,
28 intptr_t num_bytes,
29 intptr_t length_in_bytes,
30 intptr_t element_size_in_bytes) {
31 if (!Utils::RangeCheck(offset_in_bytes, num_bytes, length_in_bytes)) {
32 const String& error = String::Handle(String::NewFormatted(
33 "index (%"Pd") must be in the range [0..%"Pd")",
34 (offset_in_bytes / element_size_in_bytes),
35 (length_in_bytes / element_size_in_bytes)));
36 const Array& args = Array::Handle(Array::New(1));
37 args.SetAt(0, error);
38 Exceptions::ThrowByType(Exceptions::kRange, args);
39 }
40 }
41
42
43 // Checks to see if a length will not result in an OOM error.
44 static void LengthCheck(intptr_t len, intptr_t max) {
45 ASSERT(len >= 0);
46 if (len > max) {
47 const String& error = String::Handle(String::NewFormatted(
48 "insufficient memory to allocate a TypedData object of length (%"Pd")",
49 len));
50 const Array& args = Array::Handle(Array::New(1));
51 args.SetAt(0, error);
52 Exceptions::ThrowByType(Exceptions::kOutOfMemory, args);
53 }
54 }
55
56
57 static void PeerFinalizer(Dart_Handle handle, void* peer) {
58 Dart_DeletePersistentHandle(handle);
59 OS::AlignedFree(peer);
60 }
61
62
63 DEFINE_NATIVE_ENTRY(TypedData_length, 1) {
64 GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
65 if (instance.IsTypedData()) {
66 const TypedData& array = TypedData::Cast(instance);
67 return Smi::New(array.Length());
68 }
69 if (instance.IsExternalTypedData()) {
70 const ExternalTypedData& array = ExternalTypedData::Cast(instance);
71 return Smi::New(array.Length());
72 }
73 const String& error = String::Handle(String::NewFormatted(
74 "Expected a TypedData object but found %s", instance.ToCString()));
75 const Array& args = Array::Handle(Array::New(1));
76 args.SetAt(0, error);
77 Exceptions::ThrowByType(Exceptions::kArgument, args);
78 return Integer::null();
79 }
80
81 template <typename DstType, typename SrcType>
82 static RawBool* CopyData(const Instance& dst, const Instance& src,
83 const Smi& dst_start, const Smi& src_start,
84 const Smi& length) {
85 const DstType& dst_array = DstType::Cast(dst);
86 const SrcType& src_array = SrcType::Cast(src);
87 intptr_t element_size_in_bytes = dst_array.ElementSizeInBytes();
88 intptr_t dst_offset_in_bytes = dst_start.Value() * element_size_in_bytes;
89 intptr_t src_offset_in_bytes = src_start.Value() * element_size_in_bytes;
90 intptr_t length_in_bytes = length.Value() * element_size_in_bytes;
91 if (dst_array.ElementType() != src_array.ElementType()) {
92 return Bool::False().raw();
93 }
94 SetRangeCheck(src_offset_in_bytes,
95 length_in_bytes,
96 src_array.LengthInBytes(),
97 element_size_in_bytes);
98 SetRangeCheck(dst_offset_in_bytes,
99 length_in_bytes,
100 dst_array.LengthInBytes(),
101 element_size_in_bytes);
102 TypedData::Copy<DstType, SrcType>(dst_array, dst_offset_in_bytes,
103 src_array, src_offset_in_bytes,
104 length_in_bytes);
105 return Bool::True().raw();
106 }
107
108 DEFINE_NATIVE_ENTRY(TypedData_setRange, 5) {
109 GET_NON_NULL_NATIVE_ARGUMENT(Instance, dst, arguments->NativeArgAt(0));
110 GET_NON_NULL_NATIVE_ARGUMENT(Smi, dst_start, arguments->NativeArgAt(1));
111 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(2));
112 GET_NON_NULL_NATIVE_ARGUMENT(Instance, src, arguments->NativeArgAt(3));
113 GET_NON_NULL_NATIVE_ARGUMENT(Smi, src_start, arguments->NativeArgAt(4));
114
115 if (length.Value() < 0) {
116 const String& error = String::Handle(String::NewFormatted(
117 "length (%"Pd") must be non-negative", length.Value()));
118 const Array& args = Array::Handle(Array::New(1));
119 args.SetAt(0, error);
120 Exceptions::ThrowByType(Exceptions::kArgument, args);
121 }
122 if (dst.IsTypedData()) {
123 if (src.IsTypedData()) {
124 return CopyData<TypedData, TypedData>(
125 dst, src, dst_start, src_start, length);
126 } else if (src.IsExternalTypedData()) {
127 return CopyData<TypedData, ExternalTypedData>(
128 dst, src, dst_start, src_start, length);
129 }
130 } else if (dst.IsExternalTypedData()) {
131 if (src.IsTypedData()) {
132 return CopyData<ExternalTypedData, TypedData>(
133 dst, src, dst_start, src_start, length);
134 } else if (src.IsExternalTypedData()) {
135 return CopyData<ExternalTypedData, ExternalTypedData>(
136 dst, src, dst_start, src_start, length);
137 }
138 }
139 return Bool::False().raw();
140 }
141
142
143 // We check the length parameter against a possible maximum length for the
144 // array based on available physical addressable memory on the system. The
145 // maximum possible length is a scaled value of kSmiMax which is set up based
146 // on whether the underlying architecture is 32-bit or 64-bit.
147 #define TYPED_DATA_NEW(name) \
148 DEFINE_NATIVE_ENTRY(TypedData_##name##_new, 1) { \
149 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(0)); \
150 intptr_t cid = kTypedData##name##Cid; \
151 intptr_t len = length.Value(); \
152 intptr_t max = TypedData::MaxElements(cid); \
153 LengthCheck(len, max); \
154 return TypedData::New(cid, len); \
155 } \
156
157
158 // We check the length parameter against a possible maximum length for the
159 // array based on available physical addressable memory on the system. The
160 // maximum possible length is a scaled value of kSmiMax which is set up based
161 // on whether the underlying architecture is 32-bit or 64-bit.
162 #define EXT_TYPED_DATA_NEW(name) \
163 DEFINE_NATIVE_ENTRY(ExternalTypedData_##name##_new, 1) { \
164 const int kAlignment = 16; \
165 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(0)); \
166 intptr_t cid = kExternalTypedData##name##Cid; \
167 intptr_t len = length.Value(); \
168 intptr_t max = ExternalTypedData::MaxElements(cid); \
169 LengthCheck(len, max); \
170 intptr_t len_bytes = len * ExternalTypedData::ElementSizeInBytes(cid); \
171 uint8_t* data = OS::AllocateAlignedArray<uint8_t>(len_bytes, kAlignment); \
172 const ExternalTypedData& obj = \
173 ExternalTypedData::Handle(ExternalTypedData::New(cid, data, len)); \
174 obj.AddFinalizer(data, PeerFinalizer); \
175 return obj.raw(); \
176 } \
177
178
179 #define TYPED_DATA_NEW_NATIVE(name) \
180 TYPED_DATA_NEW(name) \
181 EXT_TYPED_DATA_NEW(name) \
182
183
184 CLASS_LIST_TYPED_DATA(TYPED_DATA_NEW_NATIVE)
185
186 #define TYPED_DATA_GETTER(getter, object) \
187 DEFINE_NATIVE_ENTRY(TypedData_##getter, 2) { \
188 GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
189 GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
190 if (instance.IsTypedData()) { \
191 const TypedData& array = TypedData::Cast(instance); \
192 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
193 return object::New(array.getter(offsetInBytes.Value())); \
194 } \
195 if (instance.IsExternalTypedData()) { \
196 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
197 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
198 return object::New(array.getter(offsetInBytes.Value())); \
199 } \
200 const String& error = String::Handle(String::NewFormatted( \
201 "Expected a TypedData object but found %s", instance.ToCString())); \
202 const Array& args = Array::Handle(Array::New(1)); \
203 args.SetAt(0, error); \
204 Exceptions::ThrowByType(Exceptions::kArgument, args); \
205 return object::null(); \
206 } \
207
208
209 #define TYPED_DATA_SETTER(setter, object, get_object_value) \
210 DEFINE_NATIVE_ENTRY(TypedData_##setter, 3) { \
211 GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
212 GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
213 GET_NON_NULL_NATIVE_ARGUMENT(object, value, arguments->NativeArgAt(2)); \
214 if (instance.IsTypedData()) { \
215 const TypedData& array = TypedData::Cast(instance); \
216 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
217 array.setter(offsetInBytes.Value(), value.get_object_value()); \
218 } else if (instance.IsExternalTypedData()) { \
219 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
220 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
221 array.setter(offsetInBytes.Value(), value.get_object_value()); \
222 } else { \
223 const String& error = String::Handle(String::NewFormatted( \
224 "Expected a TypedData object but found %s", instance.ToCString())); \
225 const Array& args = Array::Handle(Array::New(1)); \
226 args.SetAt(0, error); \
227 Exceptions::ThrowByType(Exceptions::kArgument, args); \
228 } \
229 return Object::null(); \
230 }
231
232
233 #define TYPED_DATA_UINT64_GETTER(getter, object) \
234 DEFINE_NATIVE_ENTRY(TypedData_##getter, 2) { \
235 GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
236 GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
237 uint64_t value = 0; \
238 if (instance.IsTypedData()) { \
239 const TypedData& array = TypedData::Cast(instance); \
240 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
241 value = array.getter(offsetInBytes.Value()); \
242 } else if (instance.IsExternalTypedData()) { \
243 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
244 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
245 value = array.getter(offsetInBytes.Value()); \
246 } else { \
247 const String& error = String::Handle(String::NewFormatted( \
248 "Expected a TypedData object but found %s", instance.ToCString())); \
249 const Array& args = Array::Handle(Array::New(1)); \
250 args.SetAt(0, error); \
251 Exceptions::ThrowByType(Exceptions::kArgument, args); \
252 } \
253 Integer& result = Integer::Handle(); \
254 if (value > static_cast<uint64_t>(Mint::kMaxValue)) { \
255 result = BigintOperations::NewFromUint64(value); \
256 } else if (value > static_cast<uint64_t>(Smi::kMaxValue)) { \
257 result = Mint::New(value); \
258 } else { \
259 result = Smi::New(value); \
260 } \
261 return result.raw(); \
262 } \
263
264
265 // TODO(asiva): Consider truncating the bigint value if it does not fit into
266 // a uint64_t value (see ASSERT(BigintOperations::FitsIntoUint64(bigint))).
267 #define TYPED_DATA_UINT64_SETTER(setter, object) \
268 DEFINE_NATIVE_ENTRY(TypedData_##setter, 3) { \
269 GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
270 GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
271 GET_NON_NULL_NATIVE_ARGUMENT(object, value, arguments->NativeArgAt(2)); \
272 uint64_t object_value; \
273 if (value.IsBigint()) { \
274 const Bigint& bigint = Bigint::Cast(value); \
275 ASSERT(BigintOperations::FitsIntoUint64(bigint)); \
276 object_value = BigintOperations::AbsToUint64(bigint); \
277 } else { \
278 ASSERT(value.IsMint() || value.IsSmi()); \
279 object_value = value.AsInt64Value(); \
280 } \
281 if (instance.IsTypedData()) { \
282 const TypedData& array = TypedData::Cast(instance); \
283 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
284 array.setter(offsetInBytes.Value(), object_value); \
285 } else if (instance.IsExternalTypedData()) { \
286 const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
287 ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
288 array.setter(offsetInBytes.Value(), object_value); \
289 } else { \
290 const String& error = String::Handle(String::NewFormatted( \
291 "Expected a TypedData object but found %s", instance.ToCString())); \
292 const Array& args = Array::Handle(Array::New(1)); \
293 args.SetAt(0, error); \
294 Exceptions::ThrowByType(Exceptions::kArgument, args); \
295 } \
296 return Object::null(); \
297 }
298
299
300 #define TYPED_DATA_NATIVES(getter, setter, object, get_object_value) \
301 TYPED_DATA_GETTER(getter, object) \
302 TYPED_DATA_SETTER(setter, object, get_object_value) \
303
304
305 #define TYPED_DATA_UINT64_NATIVES(getter, setter, object) \
306 TYPED_DATA_UINT64_GETTER(getter, object) \
307 TYPED_DATA_UINT64_SETTER(setter, object) \
308
309
310 TYPED_DATA_NATIVES(GetInt8, SetInt8, Smi, Value)
311 TYPED_DATA_NATIVES(GetUint8, SetUint8, Smi, Value)
312 TYPED_DATA_NATIVES(GetInt16, SetInt16, Smi, Value)
313 TYPED_DATA_NATIVES(GetUint16, SetUint16, Smi, Value)
314 TYPED_DATA_NATIVES(GetInt32, SetInt32, Integer, AsInt64Value)
315 TYPED_DATA_NATIVES(GetUint32, SetUint32, Integer, AsInt64Value)
316 TYPED_DATA_NATIVES(GetInt64, SetInt64, Integer, AsInt64Value)
317 TYPED_DATA_UINT64_NATIVES(GetUint64, SetUint64, Integer)
318 TYPED_DATA_NATIVES(GetFloat32, SetFloat32, Double, value)
319 TYPED_DATA_NATIVES(GetFloat64, SetFloat64, Double, value)
320 TYPED_DATA_NATIVES(GetFloat32x4, SetFloat32x4, Float32x4, value)
321
322
323 DEFINE_NATIVE_ENTRY(ByteData_ToEndianInt16, 2) {
324 GET_NON_NULL_NATIVE_ARGUMENT(Smi, host_value, arguments->NativeArgAt(0));
325 GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
326 int16_t value = host_value.Value();
327 if (little_endian.value()) {
328 value = Utils::HostToLittleEndian16(value);
329 } else {
330 value = Utils::HostToBigEndian16(value);
331 }
332 return Smi::New(value);
333 }
334
335
336 DEFINE_NATIVE_ENTRY(ByteData_ToEndianUint16, 2) {
337 GET_NON_NULL_NATIVE_ARGUMENT(Smi, host_value, arguments->NativeArgAt(0));
338 GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
339 uint16_t value = host_value.Value();
340 if (little_endian.value()) {
341 return Smi::New(Utils::HostToLittleEndian16(value));
342 }
343 return Smi::New(Utils::HostToBigEndian16(value));
344 }
345
346
347 DEFINE_NATIVE_ENTRY(ByteData_ToEndianInt32, 2) {
348 GET_NON_NULL_NATIVE_ARGUMENT(Integer, host_value, arguments->NativeArgAt(0));
349 GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
350 ASSERT(host_value.AsInt64Value() <= kMaxInt32);
351 int32_t value = host_value.AsInt64Value();
352 if (little_endian.value()) {
353 value = Utils::HostToLittleEndian32(value);
354 } else {
355 value = Utils::HostToBigEndian32(value);
356 }
357 return Integer::New(value);
358 }
359
360
361 DEFINE_NATIVE_ENTRY(ByteData_ToEndianUint32, 2) {
362 GET_NON_NULL_NATIVE_ARGUMENT(Integer, host_value, arguments->NativeArgAt(0));
363 GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
364 ASSERT(host_value.AsInt64Value() <= kMaxUint32);
365 uint32_t value = host_value.AsInt64Value();
366 if (little_endian.value()) {
367 value = Utils::HostToLittleEndian32(value);
368 } else {
369 value = Utils::HostToBigEndian32(value);
370 }
371 return Integer::New(value);
372 }
373
374
375 DEFINE_NATIVE_ENTRY(ByteData_ToEndianInt64, 2) {
376 GET_NON_NULL_NATIVE_ARGUMENT(Integer, host_value, arguments->NativeArgAt(0));
377 GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
378 int64_t value = host_value.AsInt64Value();
379 if (little_endian.value()) {
380 value = Utils::HostToLittleEndian64(value);
381 } else {
382 value = Utils::HostToBigEndian64(value);
383 }
384 return Integer::New(value);
385 }
386
387
388 DEFINE_NATIVE_ENTRY(ByteData_ToEndianUint64, 2) {
389 GET_NON_NULL_NATIVE_ARGUMENT(Integer, host_value, arguments->NativeArgAt(0));
390 GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
391 uint64_t value;
392 if (host_value.IsBigint()) {
393 const Bigint& bigint = Bigint::Cast(host_value);
394 ASSERT(BigintOperations::FitsIntoUint64(bigint));
395 value = BigintOperations::AbsToUint64(bigint);
396 } else {
397 ASSERT(host_value.IsMint() || host_value.IsSmi());
398 value = host_value.AsInt64Value();
399 }
400 if (little_endian.value()) {
401 value = Utils::HostToLittleEndian64(value);
402 } else {
403 value = Utils::HostToBigEndian64(value);
404 }
405 if (value > static_cast<uint64_t>(Mint::kMaxValue)) {
406 return BigintOperations::NewFromUint64(value);
407 } else if (value > static_cast<uint64_t>(Smi::kMaxValue)) {
408 return Mint::New(value);
409 }
410 return Smi::New(value);
411 }
412
413
414 DEFINE_NATIVE_ENTRY(ByteData_ToEndianFloat32, 2) {
415 GET_NON_NULL_NATIVE_ARGUMENT(Double, host_value, arguments->NativeArgAt(0));
416 GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
417 float value = host_value.value();
418 if (little_endian.value()) {
419 value = bit_cast<float>(
420 Utils::HostToLittleEndian32(bit_cast<uint32_t>(value)));
421 } else {
422 value = bit_cast<float>(
423 Utils::HostToBigEndian32(bit_cast<uint32_t>(value)));
424 }
425 return Double::New(value);
426 }
427
428
429 DEFINE_NATIVE_ENTRY(ByteData_ToEndianFloat64, 2) {
430 GET_NON_NULL_NATIVE_ARGUMENT(Double, host_value, arguments->NativeArgAt(0));
431 GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
432 double value = host_value.value();
433 if (little_endian.value()) {
434 value = bit_cast<double>(
435 Utils::HostToLittleEndian64(bit_cast<uint64_t>(value)));
436 } else {
437 value = bit_cast<double>(
438 Utils::HostToBigEndian64(bit_cast<uint64_t>(value)));
439 }
440 return Double::New(value);
441 }
442
443 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/lib/typed_data_sources.gypi ('k') | runtime/lib/typeddata.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698