Skip to content

Commit

Permalink
Trace Date using the new mechanism
Browse files Browse the repository at this point in the history
Summary: Convert Date to use the new, JS based tracing mechanism.

Reviewed By: fbmal7

Differential Revision: D38969994

fbshipit-source-id: f845dd1dac6360a5e5e26fa017dd172e090f2786
  • Loading branch information
neildhar authored and facebook-github-bot committed Aug 30, 2022
1 parent d0c6ba7 commit f60dd18
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 134 deletions.
138 changes: 18 additions & 120 deletions API/hermes/TracingRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,139 +71,37 @@ void TracingRuntime::replaceNondeterministicFuncs() {
WeakRef.prototype.deref = function deref() { return callUntraced(derefReal.bind(this)); };
globalThis.WeakRef = WeakRef;
}
});
)";
global()
.getPropertyAsFunction(*this, "eval")
.call(*this, code)
.asObject(*this)
.asFunction(*this)
.call(*this, {std::move(callUntraced)});

setupDate();

numPreambleRecords_ = trace_.records().size();
}

void TracingRuntime::insertHostForwarder(
const std::vector<const char *> &propertyPath) {
auto lenProp = walkPropertyPath(*runtime_, propertyPath)
.getProperty(*runtime_, "length")
.asNumber();
jsi::Function *funcPtr = saveFunction(propertyPath);

jsi::Function funcReplacement = jsi::Function::createFromHostFunction(
*this,
jsi::PropNameID::forAscii(*this, propertyPath.back()),
lenProp,
[this, funcPtr](
Runtime &rt,
const jsi::Value &thisVal,
const jsi::Value *args,
size_t count) {
return thisVal.isObject()
? funcPtr->callWithThis(
*runtime_, thisVal.asObject(*runtime_), args, count)
: funcPtr->call(*runtime_, args, count);
});

walkPropertyPath(*this, propertyPath, 1)
.setProperty(*this, propertyPath.back(), funcReplacement);
}

void TracingRuntime::setupDate() {
auto lenProp = walkPropertyPath(*runtime_, {"Date"})
.getProperty(*runtime_, "length")
.asNumber();
jsi::Function *origDateFunc = saveFunction({"Date"});
// We can't effectively trace objects, so we instead trace the value of
// Date.now(), and use that to deterministically reconstruct the Date object
// during replay.
jsi::Function nativeDateNow = jsi::Function::createFromHostFunction(
*this,
jsi::PropNameID::forAscii(*this, "Date"),
lenProp,
[this, origDateFunc](
Runtime &rt,
const jsi::Value &thisVal,
const jsi::Value *args,
size_t count) {
return origDateFunc->getPropertyAsFunction(*runtime_, "now")
.call(*runtime_);
});

jsi::Function nativeDateFunc = jsi::Function::createFromHostFunction(
*this,
jsi::PropNameID::forAscii(*this, "Date"),
lenProp,
[this, origDateFunc](
Runtime &rt,
const jsi::Value &thisVal,
const jsi::Value *args,
size_t count) {
auto ret = origDateFunc->call(*runtime_, args, count);
std::string retStr = ret.asString(*runtime_).utf8(*runtime_);
// If we just returned the string directly from the above call, the
// trace would not be valid because we would be using a string that has
// never been defined before. Therefore, we must copy the string in the
// tracing runtime to get this string to show up and be defined in the
// trace.
return jsi::String::createFromAscii(*this, retStr);
});

auto code = R"(
(function(nativeDateNow, nativeDateFunc){
var DateReal = Date;
function DateJSReplacement(...args){
if (new.target){
if (arguments.length == 0){
return new DateReal(nativeDateNow());
} else {
// calling new Date with arguments is deterministic
return new DateReal(...args);
}
} else {
return nativeDateFunc(...args);
var DateReal = globalThis.Date;
var dateNowReal = DateReal.now;
var nativeDateNow = function now() { return callUntraced(dateNowReal); };
function Date(...args){
// Convert non-deterministic calls like `Date()` and `new Date()` into the
// deterministic form `new Date(Date.now())`, so they can be traced.
if(!new.target){
return new DateReal(nativeDateNow()).toString();
}
if (arguments.length == 0){
return new DateReal(nativeDateNow());
}
return new DateReal(...args);
}
// Cannot use Object.assign because Date methods are not enumerable
for (p of Object.getOwnPropertyNames(DateReal)){
DateJSReplacement[p] = DateReal[p];
Date[p] = DateReal[p];
}
globalThis.Date = DateJSReplacement;
Date.now = nativeDateNow;
globalThis.Date = Date;
});
)";
global()
.getPropertyAsFunction(*this, "eval")
.call(*this, code)
.asObject(*this)
.asFunction(*this)
.call(*this, {std::move(nativeDateNow), std::move(nativeDateFunc)});
insertHostForwarder({"Date", "now"});
}

jsi::Function *TracingRuntime::saveFunction(
const std::vector<const char *> &propertyPath) {
jsi::Function origFunc =
walkPropertyPath(*runtime_, propertyPath).asFunction(*runtime_);
savedFunctions.push_back(std::move(origFunc));
return &savedFunctions.back();
}

jsi::Object TracingRuntime::walkPropertyPath(
jsi::Runtime &runtime,
const std::vector<const char *> &propertyPath,
size_t skipLastAmt) {
assert(
skipLastAmt <= propertyPath.size() &&
"skipLastAmt cannot be larger than length of property path");
jsi::Object obj = runtime.global();
for (auto e = propertyPath.begin(); e != propertyPath.end() - skipLastAmt;
e++) {
obj = obj.getPropertyAsObject(runtime, *e);
}
return obj;
.call(*this, {std::move(callUntraced)});

numPreambleRecords_ = trace_.records().size();
}

jsi::Value TracingRuntime::evaluateJavaScript(
Expand Down
14 changes: 0 additions & 14 deletions API/hermes/TracingRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,20 +152,6 @@ class TracingRuntime : public jsi::RuntimeDecorator<jsi::Runtime> {

SynthTrace::TimeSinceStart getTimeSinceStart() const;

void insertHostForwarder(const std::vector<const char *> &propertyPath);

jsi::Function *saveFunction(const std::vector<const char *> &propertyChain);

void setupDate();

// This function will traverse the properties defined in propertyPath,
// starting from the global object in the given runtime. This function can
// optionally skip the last \p skipLastAmt of properties in the given path.
static jsi::Object walkPropertyPath(
jsi::Runtime &runtime,
const std::vector<const char *> &propertyPath,
size_t skipLastAmt = 0);

std::unique_ptr<jsi::Runtime> runtime_;
SynthTrace trace_;
std::deque<jsi::Function> savedFunctions;
Expand Down

0 comments on commit f60dd18

Please sign in to comment.