Emit code for boxing a value of given type. Generate a simple assignment if no boxing is needed. The source reference count is stolen for the result (no need to decref afterwards).
(
self, src: str, dest: str, typ: RType, declare_dest: bool = False, can_borrow: bool = False
)
| 1198 | return None |
| 1199 | |
| 1200 | def emit_box( |
| 1201 | self, src: str, dest: str, typ: RType, declare_dest: bool = False, can_borrow: bool = False |
| 1202 | ) -> None: |
| 1203 | """Emit code for boxing a value of given type. |
| 1204 | |
| 1205 | Generate a simple assignment if no boxing is needed. |
| 1206 | |
| 1207 | The source reference count is stolen for the result (no need to decref afterwards). |
| 1208 | """ |
| 1209 | # TODO: Always generate a new reference (if a reference type) |
| 1210 | if declare_dest: |
| 1211 | declaration = "PyObject *" |
| 1212 | else: |
| 1213 | declaration = "" |
| 1214 | if is_int_rprimitive(typ) or is_short_int_rprimitive(typ): |
| 1215 | # Steal the existing reference if it exists. |
| 1216 | self.emit_line(f"{declaration}{dest} = CPyTagged_StealAsObject({src});") |
| 1217 | elif is_bool_or_bit_rprimitive(typ): |
| 1218 | # N.B: bool is special cased to produce a borrowed value |
| 1219 | # after boxing, so we don't need to increment the refcount |
| 1220 | # when this comes directly from a Box op. |
| 1221 | self.emit_lines(f"{declaration}{dest} = {src} ? Py_True : Py_False;") |
| 1222 | if not can_borrow: |
| 1223 | self.emit_inc_ref(dest, object_rprimitive) |
| 1224 | elif is_none_rprimitive(typ): |
| 1225 | # N.B: None is special cased to produce a borrowed value |
| 1226 | # after boxing, so we don't need to increment the refcount |
| 1227 | # when this comes directly from a Box op. |
| 1228 | self.emit_lines(f"{declaration}{dest} = Py_None;") |
| 1229 | if not can_borrow: |
| 1230 | self.emit_inc_ref(dest, object_rprimitive) |
| 1231 | elif is_int32_rprimitive(typ) or is_int16_rprimitive(typ) or is_uint8_rprimitive(typ): |
| 1232 | self.emit_line(f"{declaration}{dest} = PyLong_FromLong({src});") |
| 1233 | elif is_int64_rprimitive(typ): |
| 1234 | self.emit_line(f"{declaration}{dest} = PyLong_FromLongLong({src});") |
| 1235 | elif is_float_rprimitive(typ): |
| 1236 | self.emit_line(f"{declaration}{dest} = PyFloat_FromDouble({src});") |
| 1237 | elif isinstance(typ, RTuple): |
| 1238 | self.declare_tuple_struct(typ) |
| 1239 | if not typ.types: |
| 1240 | self.emit_line(f"{declaration}{dest} = CPyTuple_LoadEmptyTupleConstant();") |
| 1241 | else: |
| 1242 | self.emit_line(f"{declaration}{dest} = PyTuple_New({len(typ.types)});") |
| 1243 | self.emit_line(f"if (unlikely({dest} == NULL))") |
| 1244 | self.emit_line(" CPyError_OutOfMemory();") |
| 1245 | |
| 1246 | # TODO: Fail if dest is None |
| 1247 | for i in range(len(typ.types)): |
| 1248 | if not typ.is_unboxed: |
| 1249 | self.emit_line(f"PyTuple_SET_ITEM({dest}, {i}, {src}.f{i}") |
| 1250 | else: |
| 1251 | inner_name = self.temp_name() |
| 1252 | self.emit_box(f"{src}.f{i}", inner_name, typ.types[i], declare_dest=True) |
| 1253 | self.emit_line(f"PyTuple_SET_ITEM({dest}, {i}, {inner_name});") |
| 1254 | elif isinstance(typ, RVec): |
| 1255 | specialized_api_name = vec_api_by_item_type.get(typ.item_type) |
| 1256 | if specialized_api_name is not None: |
| 1257 | api = specialized_api_name |
no test coverage detected