this repo has no description
at trunk 444 lines 16 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "array-module.h" 3 4#include "builtins.h" 5#include "handles.h" 6#include "modules.h" 7#include "objects.h" 8#include "runtime.h" 9#include "symbols.h" 10#include "thread.h" 11#include "type-builtins.h" 12 13namespace py { 14 15static word itemSize(byte typecode) { 16 switch (typecode) { 17 case 'b': 18 case 'B': 19 return kByteSize; 20 case 'u': 21 return kWcharSize; 22 case 'h': 23 case 'H': 24 return kShortSize; 25 case 'i': 26 case 'I': 27 return kIntSize; 28 case 'l': 29 case 'L': 30 return kLongSize; 31 case 'q': 32 case 'Q': 33 return kLongLongSize; 34 case 'f': 35 return kFloatSize; 36 case 'd': 37 return kDoubleSize; 38 default: 39 return -1; 40 } 41} 42 43word arrayByteLength(RawArray array) { 44 byte typecode = SmallStr::cast(array.typecode()).byteAt(0); 45 word item_size = itemSize(typecode); 46 return array.length() * item_size; 47} 48 49RawObject FUNC(array, _array_check)(Thread* thread, Arguments args) { 50 return Bool::fromBool(thread->runtime()->isInstanceOfArray(args.get(0))); 51} 52 53RawObject FUNC(array, _array_new)(Thread* thread, Arguments args) { 54 HandleScope scope(thread); 55 Str typecode_str(&scope, strUnderlying(args.get(1))); 56 DCHECK(typecode_str.length() == 1, "typecode must be a single-char str"); 57 byte typecode = typecode_str.byteAt(0); 58 word item_size = itemSize(typecode); 59 if (item_size == -1) { 60 return thread->raiseWithFmt( 61 LayoutId::kValueError, 62 "bad typecode (must be b, B, u, h, H, i, I, l, L, q, Q, f or d)"); 63 } 64 word len = SmallInt::cast(args.get(2)).value() * item_size; 65 Runtime* runtime = thread->runtime(); 66 67 Type array_type(&scope, args.get(0)); 68 Layout layout(&scope, array_type.instanceLayout()); 69 Array result(&scope, runtime->newInstance(layout)); 70 result.setTypecode(*typecode_str); 71 result.setLength(0); 72 result.setBuffer(runtime->mutableBytesWith(len, 0)); 73 return *result; 74} 75 76static bool isIntTypecode(char typecode) { 77 switch (typecode) { 78 case 'f': 79 FALLTHROUGH; 80 case 'd': 81 FALLTHROUGH; 82 case 'u': 83 return false; 84 default: 85 return true; 86 } 87} 88 89static RawObject raiseOverflowError(Thread* thread, CastError error) { 90 if (error == CastError::Underflow) { 91 return thread->raiseWithFmt(LayoutId::kOverflowError, "less than minimum"); 92 } 93 DCHECK(error == CastError::Overflow, "Only two forms of CastErrors"); 94 return thread->raiseWithFmt(LayoutId::kOverflowError, "greater than maximum"); 95} 96 97// TODO(T67799743): Abstract out integer cases to int-builtins.cpp for reuse 98// with memoryviews 99static RawObject packObject(Thread* thread, uword address, char typecode, 100 word index, RawObject value) { 101 byte* dst = reinterpret_cast<byte*>(address + index); 102 if (isIntTypecode(typecode)) { 103 if (!value.isInt()) return Unbound::object(); 104 switch (typecode) { 105 case 'b': { 106 OptInt<char> opt_val = RawInt::cast(value).asInt<char>(); 107 if (opt_val.error != CastError::None) { 108 return raiseOverflowError(thread, opt_val.error); 109 } 110 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 111 break; 112 } 113 case 'h': { 114 OptInt<short> opt_val = RawInt::cast(value).asInt<short>(); 115 if (opt_val.error != CastError::None) { 116 return raiseOverflowError(thread, opt_val.error); 117 } 118 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 119 break; 120 } 121 case 'i': { 122 OptInt<int> opt_val = RawInt::cast(value).asInt<int>(); 123 if (opt_val.error != CastError::None) { 124 return raiseOverflowError(thread, opt_val.error); 125 } 126 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 127 break; 128 } 129 case 'l': { 130 OptInt<long> opt_val = RawInt::cast(value).asInt<long>(); 131 if (opt_val.error != CastError::None) { 132 return raiseOverflowError(thread, opt_val.error); 133 } 134 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 135 break; 136 } 137 case 'B': { 138 OptInt<unsigned char> opt_val = 139 RawInt::cast(value).asInt<unsigned char>(); 140 if (opt_val.error != CastError::None) { 141 return raiseOverflowError(thread, opt_val.error); 142 } 143 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 144 break; 145 } 146 case 'H': { 147 OptInt<unsigned short> opt_val = 148 RawInt::cast(value).asInt<unsigned short>(); 149 if (opt_val.error != CastError::None) { 150 return raiseOverflowError(thread, opt_val.error); 151 } 152 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 153 break; 154 } 155 case 'I': { 156 OptInt<unsigned int> opt_val = 157 RawInt::cast(value).asInt<unsigned int>(); 158 if (opt_val.error != CastError::None) { 159 return raiseOverflowError(thread, opt_val.error); 160 } 161 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 162 break; 163 } 164 case 'L': { 165 OptInt<unsigned long> opt_val = 166 RawInt::cast(value).asInt<unsigned long>(); 167 if (opt_val.error != CastError::None) { 168 return raiseOverflowError(thread, opt_val.error); 169 } 170 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 171 break; 172 } 173 case 'q': { 174 OptInt<long long> opt_val = RawInt::cast(value).asInt<long long>(); 175 if (opt_val.error != CastError::None) { 176 return raiseOverflowError(thread, opt_val.error); 177 } 178 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 179 break; 180 } 181 case 'Q': { 182 OptInt<unsigned long long> opt_val = 183 RawInt::cast(value).asInt<unsigned long long>(); 184 if (opt_val.error != CastError::None) { 185 return raiseOverflowError(thread, opt_val.error); 186 } 187 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 188 break; 189 } 190 } 191 return NoneType::object(); 192 } 193 194 Runtime* runtime = thread->runtime(); 195 switch (typecode) { 196 case 'f': { 197 if (!runtime->isInstanceOfFloat(value)) return Unbound::object(); 198 float value_float = Float::cast(floatUnderlying(value)).value(); 199 std::memcpy(dst, &value_float, sizeof(value_float)); 200 return NoneType::object(); 201 } 202 203 case 'd': { 204 if (!runtime->isInstanceOfFloat(value)) return Unbound::object(); 205 double value_double = Float::cast(floatUnderlying(value)).value(); 206 std::memcpy(dst, &value_double, sizeof(value_double)); 207 return NoneType::object(); 208 } 209 210 case 'u': 211 UNIMPLEMENTED("array.__setitem__ with unicode is unimplemented"); 212 default: 213 UNREACHABLE("invalid typecode"); 214 } 215 return NoneType::object(); 216} 217 218// TODO(T67799743): Abstract out integer cases to int-builtins.cpp for reuse 219// with memoryviews 220static RawObject unpackObject(Thread* thread, uword address, char format, 221 word index) { 222 Runtime* runtime = thread->runtime(); 223 byte* src = reinterpret_cast<byte*>(address + index); 224 switch (format) { 225 case 'b': 226 return RawSmallInt::fromWord(Utils::readBytes<signed char>(src)); 227 case 'B': 228 return RawSmallInt::fromWord(Utils::readBytes<unsigned char>(src)); 229 case 'h': 230 return RawSmallInt::fromWord(Utils::readBytes<short>(src)); 231 case 'H': 232 return RawSmallInt::fromWord(Utils::readBytes<unsigned short>(src)); 233 case 'i': 234 return runtime->newInt(Utils::readBytes<int>(src)); 235 case 'I': 236 return runtime->newInt(Utils::readBytes<unsigned int>(src)); 237 case 'l': 238 return runtime->newInt(Utils::readBytes<long>(src)); 239 case 'L': 240 return runtime->newIntFromUnsigned(Utils::readBytes<unsigned long>(src)); 241 case 'q': 242 return runtime->newInt(Utils::readBytes<long long>(src)); 243 case 'Q': 244 return runtime->newIntFromUnsigned( 245 Utils::readBytes<unsigned long long>(src)); 246 case 'f': 247 return runtime->newFloat(Utils::readBytes<float>(src)); 248 case 'd': 249 return runtime->newFloat(Utils::readBytes<double>(src)); 250 case 'u': 251 UNIMPLEMENTED("array.__getitem__ with unicode is unimplemented"); 252 default: 253 UNREACHABLE("invalid format"); 254 } 255} 256 257RawObject FUNC(array, _array_getitem)(Thread* thread, Arguments args) { 258 HandleScope scope(thread); 259 Runtime* runtime = thread->runtime(); 260 Object self_obj(&scope, args.get(0)); 261 if (!runtime->isInstanceOfArray(*self_obj)) { 262 return thread->raiseRequiresType(self_obj, ID(array)); 263 } 264 Array array(&scope, *self_obj); 265 266 Object index_obj(&scope, args.get(1)); 267 if (!runtime->isInstanceOfInt(*index_obj)) { 268 return Unbound::object(); 269 } 270 word index = intUnderlying(*index_obj).asWordSaturated(); 271 if (!SmallInt::isValid(index)) { 272 return thread->raiseWithFmt(LayoutId::kIndexError, 273 "cannot fit '%T' into an index-sized integer", 274 &index_obj); 275 } 276 word length = array.length(); 277 if (index < 0) { 278 index = length - index; 279 } 280 if (index < 0 || index >= length) { 281 return thread->raiseWithFmt(LayoutId::kIndexError, 282 "array index out of range"); 283 } 284 char typecode = Str::cast(array.typecode()).byteAt(0); 285 word item_size = itemSize(typecode); 286 word byte_index; 287 if (__builtin_mul_overflow(index, item_size, &byte_index)) { 288 return thread->raiseWithFmt(LayoutId::kIndexError, 289 "array index out of range"); 290 } 291 return unpackObject(thread, MutableBytes::cast(array.buffer()).address(), 292 typecode, byte_index); 293} 294 295RawObject FUNC(array, _array_setitem)(Thread* thread, Arguments args) { 296 HandleScope scope(thread); 297 Runtime* runtime = thread->runtime(); 298 Object self_obj(&scope, args.get(0)); 299 if (!runtime->isInstanceOfArray(*self_obj)) { 300 return thread->raiseRequiresType(self_obj, ID(array)); 301 } 302 Array array(&scope, *self_obj); 303 304 Object index_obj(&scope, args.get(1)); 305 if (!runtime->isInstanceOfInt(*index_obj)) { 306 return Unbound::object(); 307 } 308 word index = intUnderlying(*index_obj).asWordSaturated(); 309 if (!SmallInt::isValid(index)) { 310 return thread->raiseWithFmt(LayoutId::kIndexError, 311 "cannot fit '%T' into an index-sized integer", 312 &index_obj); 313 } 314 word length = array.length(); 315 if (index < 0) { 316 index = length - index; 317 } 318 if (index < 0 || index >= length) { 319 return thread->raiseWithFmt(LayoutId::kIndexError, 320 "array assignment index out of range"); 321 } 322 char typecode = Str::cast(array.typecode()).byteAt(0); 323 word item_size = itemSize(typecode); 324 word byte_index; 325 if (__builtin_mul_overflow(index, item_size, &byte_index)) { 326 return thread->raiseWithFmt(LayoutId::kIndexError, 327 "array assignment index out of range"); 328 } 329 return packObject(thread, MutableBytes::cast(array.buffer()).address(), 330 typecode, byte_index, args.get(2)); 331} 332 333static void arrayEnsureCapacity(Thread* thread, const Array& array, 334 word min_length) { 335 DCHECK_BOUND(min_length, SmallInt::kMaxValue); 336 HandleScope scope(thread); 337 MutableBytes buffer(&scope, array.buffer()); 338 word curr_length = buffer.length(); 339 if (min_length <= curr_length) return; 340 word new_length = Runtime::newCapacity(curr_length, min_length); 341 MutableBytes new_buffer( 342 &scope, thread->runtime()->newMutableBytesUninitialized(new_length)); 343 new_buffer.replaceFromWith(0, *buffer, curr_length); 344 new_buffer.replaceFromWithByte(curr_length, 0, new_length - curr_length); 345 array.setBuffer(*new_buffer); 346} 347 348RawObject FUNC(array, _array_reserve)(Thread* thread, Arguments args) { 349 HandleScope scope(thread); 350 Runtime* runtime = thread->runtime(); 351 Object array_obj(&scope, args.get(0)); 352 if (!runtime->isInstanceOfArray(*array_obj)) { 353 return thread->raiseRequiresType(array_obj, ID(array)); 354 } 355 Array array(&scope, *array_obj); 356 word item_size = itemSize(Str::cast(array.typecode()).byteAt(0)); 357 word size = intUnderlying(args.get(1)).asWord() * item_size; 358 arrayEnsureCapacity(thread, array, size); 359 return NoneType::object(); 360} 361 362RawObject FUNC(array, _array_append)(Thread* thread, Arguments args) { 363 HandleScope scope(thread); 364 Runtime* runtime = thread->runtime(); 365 Object self_obj(&scope, args.get(0)); 366 if (!runtime->isInstanceOfArray(*self_obj)) { 367 return thread->raiseRequiresType(self_obj, ID(array)); 368 } 369 Array array(&scope, *self_obj); 370 char typecode = Str::cast(array.typecode()).byteAt(0); 371 word item_size = itemSize(typecode); 372 word length = array.length(); 373 // This shouldn't overflow, since length is limited to a SmallInt 374 word new_length = length + 1; 375 word new_capacity; 376 if (__builtin_mul_overflow(new_length, item_size, &new_capacity)) { 377 return thread->raiseWithFmt(LayoutId::kIndexError, 378 "array assignment index out of range"); 379 } 380 381 arrayEnsureCapacity(thread, array, new_capacity); 382 MutableBytes buffer(&scope, array.buffer()); 383 Object result(&scope, packObject(thread, buffer.address(), typecode, 384 new_capacity - item_size, args.get(1))); 385 if (!result.isErrorException() && !result.isUnbound()) { 386 array.setLength(new_length); 387 } 388 return *result; 389} 390 391RawObject FUNC(array, _array_repeat)(Thread* thread, Arguments args) { 392 HandleScope scope(thread); 393 Runtime* runtime = thread->runtime(); 394 Object self_obj(&scope, args.get(0)); 395 if (!runtime->isInstanceOfArray(*self_obj)) { 396 return thread->raiseRequiresType(self_obj, ID(array)); 397 } 398 Array self(&scope, args.get(0)); 399 Object count_obj(&scope, args.get(1)); 400 if (!runtime->isInstanceOfInt(*count_obj)) { 401 return Unbound::object(); 402 } 403 word count = intUnderlying(*count_obj).asWordSaturated(); 404 word byte_length = arrayByteLength(*self); 405 word new_capacity; 406 if (__builtin_mul_overflow(byte_length, count, &new_capacity) || 407 !SmallInt::isValid(new_capacity)) { 408 return thread->raiseWithFmt(LayoutId::kMemoryError, 409 "repeated array is too long"); 410 } 411 Bytes buffer(&scope, self.buffer()); 412 MutableBytes new_buffer( 413 &scope, runtime->bytesRepeat(thread, buffer, byte_length, count)); 414 Layout layout(&scope, runtime->layoutAt(LayoutId::kArray)); 415 Array result(&scope, runtime->newInstance(layout)); 416 result.setTypecode(self.typecode()); 417 result.setBuffer(*new_buffer); 418 result.setLength(self.length() * count); 419 return *result; 420} 421 422RawObject METH(array, __len__)(Thread* thread, Arguments args) { 423 HandleScope scope(thread); 424 Object self_obj(&scope, args.get(0)); 425 if (!thread->runtime()->isInstanceOfArray(*self_obj)) { 426 return thread->raiseRequiresType(self_obj, ID(array)); 427 } 428 Array self(&scope, args.get(0)); 429 return SmallInt::fromWord(self.length()); 430} 431 432static const BuiltinAttribute kArrayAttributes[] = { 433 {ID(_array__buffer), RawArray::kBufferOffset, AttributeFlags::kHidden}, 434 {ID(_array__length), RawArray::kLengthOffset, AttributeFlags::kHidden}, 435 {ID(typecode), RawArray::kTypecodeOffset, AttributeFlags::kReadOnly}, 436}; 437 438void initializeArrayType(Thread* thread) { 439 addBuiltinType(thread, ID(array), LayoutId::kArray, 440 /*superclass_id=*/LayoutId::kObject, kArrayAttributes, 441 Array::kSize, /*basetype=*/true); 442} 443 444} // namespace py