Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions core/libs/prx/libSceJson2/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <iterator>
#include <list>
#include <mutex>
#include <stdexcept>
Expand Down Expand Up @@ -906,9 +907,22 @@ int APS5_VABI _ZN3sce4Json6Object4PairD1Ev() {
return 0;
}

int APS5_VABI _ZN3sce4Json6Object6insertERKNS1_4PairE() {
NotImplemented_nid_no_patch(__func__);
return 0;
ObjectIterator* APS5_VABI _ZN3sce4Json6Object6insertERKNS1_4PairE(ObjectIterator* result, Object* self, const Pair* pair) {
if (pair == nullptr) throw std::invalid_argument("sce::Json::Object::insert: null pair");
for (const auto& existing : *self->items)
if (*existing.key.text == *pair->key.text) throw std::runtime_error("sce::Json::Object::insert: duplicate key; the console's behaviour is unknown");
Pair copy{};
Construct(copy.key, *pair->key.text);
try {
CopyInto(copy.value, pair->value);
} catch (...) {
Destroy(copy.key);
Destroy(copy.value);
throw;
}
self->items->push_back(copy);
result->it = std::prev(self->items->end());
return result;
}

int APS5_VABI _ZN3sce4Json5Array8iteratorppEi() {
Expand Down
40 changes: 40 additions & 0 deletions core/libs/tests/GuestJson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Pair* APS5_VABI _ZNK3sce4Json6Object8iteratorptEv(const Iterator*);
Iterator* APS5_VABI _ZNK3sce4Json6Object4findERKNS0_6StringE(Iterator*, const Object*, const String*);
int APS5_VABI _ZNK3sce4Json6String7compareEPKc(const String*, const char*);
bool APS5_VABI _ZNK3sce4Json6Object8iteratorneERKS2_(const Iterator*, const Iterator*);
Iterator* APS5_VABI _ZN3sce4Json6Object6insertERKNS1_4PairE(Iterator*, Object*, const Pair*);
void APS5_VABI _ZN3sce4Json5ValueC1Ev(Value*);
void APS5_VABI _ZN3sce4Json5ValueC1Eb(Value*, bool);
void APS5_VABI _ZN3sce4Json5ValueC1Ed(Value*, double);
Expand Down Expand Up @@ -596,6 +597,44 @@ static int APS5_VABI ReadNext(char& ch, void* context) {
return 0;
}

static void ObjectInsert() {
Object object{};
_ZN3sce4Json6ObjectC1Ev(&object);
Pair first{};
_ZN3sce4Json6StringC1EPKc(&first.key, "k");
_ZN3sce4Json5ValueC1Ev(&first.value);
Require(_ZN3sce4Json5Value3setEl(&first.value, 7) == 0);
Iterator inserted{};
Require(_ZN3sce4Json6Object6insertERKNS1_4PairE(&inserted, &object, &first) == &inserted);
const Pair* stored = _ZNK3sce4Json6Object8iteratordeEv(&inserted);
Require(stored != &first && stored->value.node != first.value.node);
Require(std::strcmp(_ZNK3sce4Json6String5c_strEv(&stored->key), "k") == 0);
Require(_ZN3sce4Json5Value3setEl(&first.value, 8) == 0);
Require(*_ZNK3sce4Json5Value10getIntegerEv(&stored->value) == 7);
Pair second{};
_ZN3sce4Json6StringC1EPKc(&second.key, "j");
_ZN3sce4Json5ValueC1Ev(&second.value);
Require(_ZN3sce4Json5Value3setEPKc(&second.value, "s") == 0);
Iterator next{};
_ZN3sce4Json6Object6insertERKNS1_4PairE(&next, &object, &second);
Require(std::strcmp(_ZNK3sce4Json6String5c_strEv(&_ZNK3sce4Json6Object8iteratordeEv(&next)->key), "j") == 0);
Require(_ZNK3sce4Json6Object4sizeEv(&object) == 2);
bool threw = false;
try { _ZN3sce4Json6Object6insertERKNS1_4PairE(&next, &object, &first); } catch (const std::runtime_error&) { threw = true; }
Require(threw && _ZNK3sce4Json6Object4sizeEv(&object) == 2);
Value wrapped{};
_ZN3sce4Json5ValueC1ERKNS0_6ObjectE(&wrapped, &object);
Require(Serialize(wrapped) == "{\"k\":7,\"j\":\"s\"}");
_ZN3sce4Json5ValueD1Ev(&wrapped);
_ZN3sce4Json6Object8iteratorD1Ev(&inserted);
_ZN3sce4Json6Object8iteratorD1Ev(&next);
_ZN3sce4Json6StringD1Ev(&first.key);
_ZN3sce4Json5ValueD1Ev(&first.value);
_ZN3sce4Json6StringD1Ev(&second.key);
_ZN3sce4Json5ValueD1Ev(&second.value);
_ZN3sce4Json6ObjectD1Ev(&object);
}

static void StreamParse() {
Value root{};
_ZN3sce4Json5ValueC1Ev(&root);
Expand All @@ -615,6 +654,7 @@ int main() {
NestingDepth();
ObjectsAndArrays();
ObjectFind();
ObjectInsert();
NullAccess(_ZN3sce4Json11Initializer27setGlobalNullAccessCallBackEPFRKNS0_5ValueENS0_9ValueTypeEPS3_PvES7_);
NullAccess(_ZN3sce4Json11Initializer27setGlobalNullAccessCallbackEPFRKNS0_5ValueENS0_9ValueTypeEPS3_PvES7_);
ValueAccess();
Expand Down
3 changes: 2 additions & 1 deletion docs/dev/TechnicalDebt.md
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,8 @@ Throughout the project, every function at every stage either **does exactly what
- [pthread_kill](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) returns the error number like FreeBSD's `pthread_kill`: `EINVAL` for signals outside 0 to 128 and `ESRCH` for a null thread. Signal 0 reports any other thread handle as existing, without checking that the thread is still alive. A signal to the calling thread goes through `raise`, so it shares `raise`'s limits; a signal to another thread throws, since guest signals are not delivered to a chosen thread
- [select](../../core/libs/prx/libkernel/Socket/src/Socket.cpp) (libkernel) validates `tv_usec` but saturates a valid timeout beyond the remaining `steady_clock` range at `time_point::max()`, so the wait can continue effectively indefinitely. The console's behavior for a valid timeout outside the host clock's range is unknown.
- [AJM](../../core/libs/prx/libSceAjm.native/src/Ajm.cpp), [APR](../../core/libs/prx/libkernel/Apr/src/Apr.cpp) and [NGS2](../../core/libs/prx/libSceNgs2.native/src/System.cpp) state is allocated with `new` and never freed on purpose: title threads still call into these libraries while `std::exit` runs static destructors, so ordinary statics would be destroyed under them. Keep them leaked; `guest_ajm_teardown` covers the AJM case on Unix.
- PPSA30601 imports declared without parameters, signatures unknown, added without an implementation because the title fails to load without them: [six sce::Json::Object::Pair, sce::Json::Object and sce::Json::Array::iterator members](../../core/libs/prx/libSceJson2/Export.cpp) (libSceJson2), [sceAmprAmmGetUsageStatsData](../../core/libs/prx/libSceAmpr/Export.cpp) (libSceAmpr), [sceMouseResetAbsolutePosition](../../core/libs/prx/libSceMouse/Export.cpp) (libSceMouse) and [sceSaveDataDirNameSearch2](../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native)
- PPSA30601 imports declared without parameters, signatures unknown, added without an implementation because the title fails to load without them: [five sce::Json::Object::Pair and sce::Json::Array::iterator members](../../core/libs/prx/libSceJson2/Export.cpp) (libSceJson2), [sceAmprAmmGetUsageStatsData](../../core/libs/prx/libSceAmpr/Export.cpp) (libSceAmpr), [sceMouseResetAbsolutePosition](../../core/libs/prx/libSceMouse/Export.cpp) (libSceMouse) and [sceSaveDataDirNameSearch2](../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native)
- [sce::Json::Object::insert](../../core/libs/prx/libSceJson2/Export.cpp) (libSceJson2) - imported by PPSA30601. The `insert(const Pair&)` signature and its iterator to the inserted pair follow the PS Vita `sce::Json` declaration in [vitasdk](https://github.com/vitasdk/vita-headers/blob/master/include/psp2/json.h); the PS5 behaviour is not confirmed on a title. The pair is copied to the end of the object, so iteration and serialization keep insertion order as `operator[]` does. Inserting a key the object already has throws, because whether the console replaces, keeps or duplicates the pair is unknown
- PPSA07411 imports declared without parameters, signatures unknown, added without an implementation because the title fails to load without them: [sceSslCreateConnection, sceSslDeleteConnection, sceSslEnableVerifyOption, sceSslConnect, sceSslRead, sceSslWrite](../../core/libs/prx/libSceSsl/Export.cpp) (libSceSsl), [four sce::Json::Value members (setElementAccessFailureHandler, setSpecialFloatHandler, setTypeMismatchHandler, operator bool)](../../core/libs/prx/libSceJson2/Export.cpp) (libSceJson2), [sceConvertKeycodeGetCharacter](../../core/libs/prx/libSceConvertKeycode/Export.cpp) (libSceConvertKeycode) and [sceNpSessionSignalingGetGroupFromSessionId](../../core/libs/prx/libSceNpSessionSignaling/Export.cpp) (libSceNpSessionSignaling)
- [Comparison-sampled R32 float and R16 unorm textures](../../core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp) (libSceAgcDriver) whose surface a storage image holds are sampled from a D32_SFLOAT or D16_UNORM image that the GPU refills from the storage image whenever its version moves, because Vulkan compares only depth formats. Only surfaces of at least 1 MiB (`APS5_DEPTH_COPY_MIN_KIB`) that are not 3D take the copy; smaller ones stay CPU snapshots compared against guest memory. With copies of small surfaces, one title hit an intermittent boot-time crash that was not explained.
- [Null vertex buffer V#](../../core/libs/prx/libSceAgcDriver/Graphics/include/VertexInput.hpp) (libSceAgcDriver) - a V# whose four dwords are all zero is bound to a zeroed vertex buffer of the attribute's size with stride 0, so every component of its attribute reads 0. This follows the V# fields in the [AMD RDNA2 ISA](https://gpuopen.com/download/rdna2-shader-instruction-set-architecture.pdf) (`NUM_RECORDS` 0, `DST_SEL` 0 selects 0), not measured on hardware.
Expand Down
Loading