diff --git a/API/hermes/TraceInterpreter.cpp b/API/hermes/TraceInterpreter.cpp index 393508aa927..7ab130ff8c4 100644 --- a/API/hermes/TraceInterpreter.cpp +++ b/API/hermes/TraceInterpreter.cpp @@ -456,6 +456,14 @@ Function TraceInterpreter::createHostFunction( const Value *args, size_t count) mutable -> Value { try { + // Javascript execution has invoked this host function, + // expecting the trace to contain records for the execution of + // the function. If the trace is truncated, those records + // may not exist -- return early in that case. + if (nextExecIndex_ >= trace_.records().size()) { + return Value::undefined(); + } + const auto &rec = trace_.records()[nextExecIndex_]; const auto &ctnr = record_cast(*rec); @@ -494,6 +502,15 @@ Object TraceInterpreter::createHostObject(ObjectID objID) { Value get(Runtime &rt, const PropNameID &name) override { try { + // Javascript execution has invoked this host object getter, + // expecting the trace to contain records for the execution of + // the function. If the trace is truncated, those records + // may not exist -- return early in that case. + if (interpreter_.nextExecIndex_ >= + interpreter_.trace_.records().size()) { + return Value::undefined(); + } + const auto &rec = interpreter_.trace_.records()[interpreter_.nextExecIndex_]; const auto &gpnr = @@ -517,6 +534,15 @@ Object TraceInterpreter::createHostObject(ObjectID objID) { void set(Runtime &rt, const PropNameID &name, const Value &value) override { try { + // Javascript execution has invoked this host object setter, + // expecting the trace to contain records for the execution of + // the function. If the trace is truncated, those records + // may not exist -- return early in that case. + if (interpreter_.nextExecIndex_ >= + interpreter_.trace_.records().size()) { + return; + } + const auto &rec = interpreter_.trace_.records()[interpreter_.nextExecIndex_]; const auto &spnr = diff --git a/API/hermes/synthtest/tests/TestFunctions.h b/API/hermes/synthtest/tests/TestFunctions.h index 4bd7ba5cbf4..48099473123 100644 --- a/API/hermes/synthtest/tests/TestFunctions.h +++ b/API/hermes/synthtest/tests/TestFunctions.h @@ -27,6 +27,9 @@ F(nativePropertyNames) \ F(nativeSetsConstant) \ F(parseGCConfig) \ + F(partialTraceHostFunction) \ + F(partialTraceHostObjectGet) \ + F(partialTraceHostObjectSet) \ F(surrogatePairString) #define TEST_FUNC_FORWARD_DECL(name) \ diff --git a/API/hermes/synthtest/tests/partial_trace_host_function.cpp b/API/hermes/synthtest/tests/partial_trace_host_function.cpp new file mode 100644 index 00000000000..dff53153351 --- /dev/null +++ b/API/hermes/synthtest/tests/partial_trace_host_function.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TestFunctions.h" + +namespace facebook { +namespace hermes { +namespace synthtest { + +const char *partialTraceHostFunctionTrace() { + return R"###( +{ + "globalObjID": 1, + "trace": [ + { + "type": "BeginExecJSRecord", + "time": 0 + }, + { + "type": "EndExecJSRecord", + "retval": "undefined:", + "time": 0 + }, + { + "type": "CreatePropNameRecord", + "objID": 2, + "encoding": "ASCII", + "chars": "f" + }, + { + "type": "GetPropertyRecord", + "time": 0, + "objID": 1, + "propID": "propIDTag:2", + "propName": "f", + }, + { + "type": "ReturnToNativeRecord", + "time": 0, + "retval": "object:10" + }, + { + "type": "CreatePropNameIDRecord", + "objID": 40, + "encoding": "ASCII", + "chars": "HostFunction1" + }, + { + "type": "CreateHostFunctionRecord", + "time": 0, + "objID": 11, + "propNameID": 40, + "functionName": "HostFunction1" + }, + { + "type": "CallFromNativeRecord", + "time": 0, + "functionID": 10, + "thisArg": "undefined:", + "args": ["object:11"] + } + ] +} +)###"; +} + +const char *partialTraceHostFunctionSource() { + return R"###( +'use strict'; + +(function(global) { + // callbacks execute f + // read the zeroth element of the return result, + // execute that as a function with no args, + // read the zeroth element of the return value and expect it to be false. + global.f = function(nativeFunc) { + nativeFunc(); + }; +})(this); +)###"; +} + +} // namespace synthtest +} // namespace hermes +} // namespace facebook diff --git a/API/hermes/synthtest/tests/partial_trace_host_object_get.cpp b/API/hermes/synthtest/tests/partial_trace_host_object_get.cpp new file mode 100644 index 00000000000..69c9e1b30e6 --- /dev/null +++ b/API/hermes/synthtest/tests/partial_trace_host_object_get.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TestFunctions.h" + +namespace facebook { +namespace hermes { +namespace synthtest { + +const char *partialTraceHostObjectGetTrace() { + return R"###( +{ + "globalObjID": 1, + "trace": [ + { + "type": "BeginExecJSRecord", + "time": 0 + }, + { + "type": "EndExecJSRecord", + "retval": "undefined:", + "time": 0 + }, + { + "type": "CreatePropNameRecord", + "objID": 2, + "encoding": "ASCII", + "chars": "f" + }, + { + "type": "GetPropertyRecord", + "time": 0, + "objID": 1, + "propID": "propIDTag:2", + "propName": "f", + }, + { + "type": "ReturnToNativeRecord", + "time": 0, + "retval": "object:10" + }, + { + "type": "CreatePropNameIDRecord", + "objID": 40, + "encoding": "ASCII", + "chars": "HostFunction1" + }, + { + "type": "CreateHostObjectRecord", + "time": 0, + "objID": 11, + }, + { + "type": "CallFromNativeRecord", + "time": 0, + "functionID": 10, + "thisArg": "undefined:", + "args": ["object:11"] + } + ] +} +)###"; +} + +const char *partialTraceHostObjectGetSource() { + return R"###( +'use strict'; + +(function(global) { + // callbacks execute f + // read the zeroth element of the return result, + // execute that as a function with no args, + // read the zeroth element of the return value and expect it to be false. + global.f = function(hostObject) { + return hostObject.a; + }; +})(this); +)###"; +} + +} // namespace synthtest +} // namespace hermes +} // namespace facebook diff --git a/API/hermes/synthtest/tests/partial_trace_host_object_set.cpp b/API/hermes/synthtest/tests/partial_trace_host_object_set.cpp new file mode 100644 index 00000000000..a83864fdfaf --- /dev/null +++ b/API/hermes/synthtest/tests/partial_trace_host_object_set.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TestFunctions.h" + +namespace facebook { +namespace hermes { +namespace synthtest { + +const char *partialTraceHostObjectSetTrace() { + return R"###( +{ + "globalObjID": 1, + "trace": [ + { + "type": "BeginExecJSRecord", + "time": 0 + }, + { + "type": "EndExecJSRecord", + "retval": "undefined:", + "time": 0 + }, + { + "type": "CreatePropNameRecord", + "objID": 2, + "encoding": "ASCII", + "chars": "f" + }, + { + "type": "GetPropertyRecord", + "time": 0, + "objID": 1, + "propID": "propIDTag:2", + "propName": "f", + }, + { + "type": "ReturnToNativeRecord", + "time": 0, + "retval": "object:10" + }, + { + "type": "CreatePropNameIDRecord", + "objID": 40, + "encoding": "ASCII", + "chars": "HostFunction1" + }, + { + "type": "CreateHostObjectRecord", + "time": 0, + "objID": 11, + }, + { + "type": "CallFromNativeRecord", + "time": 0, + "functionID": 10, + "thisArg": "undefined:", + "args": ["object:11"] + } + ] +} +)###"; +} + +const char *partialTraceHostObjectSetSource() { + return R"###( +'use strict'; + +(function(global) { + // callbacks execute f + // read the zeroth element of the return result, + // execute that as a function with no args, + // read the zeroth element of the return value and expect it to be false. + global.f = function(hostObject) { + hostObject.a = 7; + }; +})(this); +)###"; +} + +} // namespace synthtest +} // namespace hermes +} // namespace facebook