Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5ba8177
commit ddfe11e
Showing
10 changed files
with
483 additions
and
8 deletions.
There are no files selected for viewing
200 changes: 200 additions & 0 deletions
200
integration-tests/js-compute/fixtures/performance/bin/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
/// <reference path="../../../../../types/index.d.ts" /> | ||
/* eslint-env serviceworker */ | ||
|
||
import { routes } from "../../../test-harness.js"; | ||
import { pass, assert, assertThrows } from "../../../assertions.js"; | ||
|
||
let error; | ||
routes.set("/Performance/interface", () => { | ||
let actual = Reflect.ownKeys(Performance) | ||
let expected = ["prototype","length","name"] | ||
error = assert(actual, expected, `Reflect.ownKeys(Performance)`) | ||
if (error) { return error } | ||
|
||
// Check the prototype descriptors are correct | ||
{ | ||
actual = Reflect.getOwnPropertyDescriptor(Performance, 'prototype') | ||
expected = { | ||
"value": Performance.prototype, | ||
"writable": false, | ||
"enumerable": false, | ||
"configurable": false | ||
} | ||
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Performance, 'prototype')`) | ||
if (error) { return error } | ||
} | ||
|
||
// Check the constructor function's defined parameter length is correct | ||
{ | ||
actual = Reflect.getOwnPropertyDescriptor(Performance, 'length') | ||
expected = { | ||
"value": 0, | ||
"writable": false, | ||
"enumerable": false, | ||
"configurable": true | ||
} | ||
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Performance, 'length')`) | ||
if (error) { return error } | ||
} | ||
|
||
// Check the constructor function's name is correct | ||
{ | ||
actual = Reflect.getOwnPropertyDescriptor(Performance, 'name') | ||
expected = { | ||
"value": "Performance", | ||
"writable": false, | ||
"enumerable": false, | ||
"configurable": true | ||
} | ||
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Performance, 'name')`) | ||
if (error) { return error } | ||
} | ||
|
||
// Check the prototype has the correct keys | ||
{ | ||
actual = Reflect.ownKeys(Performance.prototype) | ||
expected = ["constructor","timeOrigin","now", Symbol.toStringTag] | ||
error = assert(actual, expected, `Reflect.ownKeys(Performance.prototype)`) | ||
if (error) { return error } | ||
} | ||
|
||
// Check the constructor on the prototype is correct | ||
{ | ||
actual = Reflect.getOwnPropertyDescriptor(Performance.prototype, 'constructor') | ||
expected = { "writable": true, "enumerable": false, "configurable": true, value: Performance.prototype.constructor } | ||
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Performance.prototype, 'constructor')`) | ||
if (error) { return error } | ||
|
||
error = assert(typeof Performance.prototype.constructor, 'function', `typeof Performance.prototype.constructor`) | ||
if (error) { return error } | ||
|
||
actual = Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'length') | ||
expected = { | ||
"value": 0, | ||
"writable": false, | ||
"enumerable": false, | ||
"configurable": true | ||
} | ||
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'length')`) | ||
if (error) { return error } | ||
|
||
actual = Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'name') | ||
expected = { | ||
"value": "Performance", | ||
"writable": false, | ||
"enumerable": false, | ||
"configurable": true | ||
} | ||
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'name')`) | ||
if (error) { return error } | ||
} | ||
|
||
// Check the Symbol.toStringTag on the prototype is correct | ||
{ | ||
actual = Reflect.getOwnPropertyDescriptor(Performance.prototype, Symbol.toStringTag) | ||
expected = {"value":"performance","writable":false,"enumerable":false,"configurable":true} | ||
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Performance.prototype, [Symbol.toStringTag])`) | ||
if (error) { return error } | ||
|
||
error = assert(typeof Performance.prototype[Symbol.toStringTag], 'string', `typeof Performance.prototype[Symbol.toStringTag]`) | ||
if (error) { return error } | ||
} | ||
|
||
|
||
// Check the timeOrigin property is correct | ||
{ | ||
const descriptors = Reflect.getOwnPropertyDescriptor(Performance.prototype, 'timeOrigin') | ||
expected = { "enumerable": true, "configurable": true } | ||
error = assert(descriptors.enumerable, true, `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').enumerable`) | ||
error = assert(descriptors.configurable, true, `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').configurable`) | ||
error = assert(descriptors.value, undefined, `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').value`) | ||
error = assert(descriptors.set, undefined, `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').set`) | ||
error = assert(typeof descriptors.get, 'function', `typeof Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').get`) | ||
if (error) { return error } | ||
|
||
error = assert(typeof Performance.prototype.timeOrigin, 'number', `typeof Performance.prototype.timeOrigin`) | ||
if (error) { return error } | ||
} | ||
|
||
// Check the now property is correct | ||
{ | ||
actual = Reflect.getOwnPropertyDescriptor(Performance.prototype, 'now') | ||
expected = { "writable": true, "enumerable": true, "configurable": true, value: Performance.prototype.now } | ||
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Performance, 'now')`) | ||
if (error) { return error } | ||
|
||
error = assert(typeof Performance.prototype.now, 'function', `typeof Performance.prototype.now`) | ||
if (error) { return error } | ||
|
||
actual = Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'length') | ||
expected = { | ||
"value": 0, | ||
"writable": false, | ||
"enumerable": false, | ||
"configurable": true | ||
} | ||
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'length')`) | ||
if (error) { return error } | ||
|
||
actual = Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'name') | ||
expected = { | ||
"value": "now", | ||
"writable": false, | ||
"enumerable": false, | ||
"configurable": true | ||
} | ||
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'name')`) | ||
if (error) { return error } | ||
} | ||
|
||
return pass('ok') | ||
}); | ||
|
||
routes.set("/globalThis.performance", () => { | ||
error = assert(globalThis.performance instanceof Performance, true, `globalThis.performance instanceof Performance`) | ||
if (error) { return error } | ||
|
||
return pass('ok') | ||
}); | ||
|
||
routes.set("/globalThis.performance/now", () => { | ||
error = assertThrows(() => new performance.now()) | ||
if (error) { return error } | ||
|
||
error = assert(typeof performance.now(), 'number') | ||
if (error) { return error } | ||
|
||
error = assert(performance.now() > 0, true) | ||
if (error) { return error } | ||
|
||
error = assert(Number.isNaN(performance.now()), false) | ||
if (error) { return error } | ||
|
||
error = assert(Number.isFinite(performance.now()), true) | ||
if (error) { return error } | ||
|
||
error = assert(performance.now() < Date.now(), true) | ||
if (error) { return error } | ||
|
||
return pass('ok') | ||
}); | ||
|
||
routes.set("/globalThis.performance/timeOrigin", () => { | ||
error = assert(typeof performance.timeOrigin, 'number') | ||
if (error) { return error } | ||
|
||
error = assert(performance.timeOrigin > 0, true) | ||
if (error) { return error } | ||
|
||
error = assert(Number.isNaN(performance.timeOrigin), false) | ||
if (error) { return error } | ||
|
||
error = assert(Number.isFinite(performance.timeOrigin), true) | ||
if (error) { return error } | ||
|
||
|
||
error = assert(performance.timeOrigin < Date.now(), true) | ||
if (error) { return error } | ||
|
||
return pass('ok') | ||
}); |
46 changes: 46 additions & 0 deletions
46
integration-tests/js-compute/fixtures/performance/tests.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
{ | ||
"GET /Performance/interface": { | ||
"environments": [ "viceroy" ], | ||
"downstream_request": { | ||
"method": "GET", | ||
"pathname": "/Performance/interface" | ||
}, | ||
"downstream_response": { | ||
"status": 200, | ||
"body": "ok" | ||
} | ||
}, | ||
"GET /globalThis.performance": { | ||
"environments": [ "viceroy" ], | ||
"downstream_request": { | ||
"method": "GET", | ||
"pathname": "/globalThis.performance" | ||
}, | ||
"downstream_response": { | ||
"status": 200, | ||
"body": "ok" | ||
} | ||
}, | ||
"GET /globalThis.performance/now": { | ||
"environments": [ "viceroy" ], | ||
"downstream_request": { | ||
"method": "GET", | ||
"pathname": "/globalThis.performance/now" | ||
}, | ||
"downstream_response": { | ||
"status": 200, | ||
"body": "ok" | ||
} | ||
}, | ||
"GET /globalThis.performance/timeOrigin": { | ||
"environments": [ "viceroy" ], | ||
"downstream_request": { | ||
"method": "GET", | ||
"pathname": "/globalThis.performance/timeOrigin" | ||
}, | ||
"downstream_response": { | ||
"status": 200, | ||
"body": "ok" | ||
} | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
runtime/js-compute-runtime/builtins/shared/performance.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#include "performance.h" | ||
#include "builtin.h" | ||
#include <chrono> | ||
|
||
namespace { | ||
using FpMilliseconds = std::chrono::duration<float, std::chrono::milliseconds::period>; | ||
} // namespace | ||
|
||
namespace builtins { | ||
|
||
std::optional<std::chrono::steady_clock::time_point> Performance::timeOrigin; | ||
|
||
// https://w3c.github.io/hr-time/#dom-performance-now | ||
bool Performance::now(JSContext *cx, unsigned argc, JS::Value *vp) { | ||
METHOD_HEADER(0); | ||
MOZ_ASSERT(builtins::Performance::timeOrigin.has_value()); | ||
|
||
auto finish = std::chrono::high_resolution_clock::now(); | ||
auto duration = FpMilliseconds(finish - builtins::Performance::timeOrigin.value()).count(); | ||
|
||
JS::RootedValue elapsed(cx, JS::Float32Value(duration)); | ||
args.rval().set(elapsed); | ||
return true; | ||
} | ||
|
||
bool Performance::timeOrigin_get(JSContext *cx, unsigned argc, JS::Value *vp) { | ||
MOZ_ASSERT(builtins::Performance::timeOrigin.has_value()); | ||
METHOD_HEADER(0); | ||
auto time = FpMilliseconds(builtins::Performance::timeOrigin.value().time_since_epoch()).count(); | ||
JS::RootedValue elapsed(cx, JS::Float32Value(time)); | ||
args.rval().set(elapsed); | ||
return true; | ||
} | ||
|
||
const JSFunctionSpec Performance::methods[] = {JS_FN("now", now, 0, JSPROP_ENUMERATE), JS_FS_END}; | ||
|
||
const JSPropertySpec Performance::properties[] = { | ||
JS_PSG("timeOrigin", timeOrigin_get, JSPROP_ENUMERATE), | ||
JS_STRING_SYM_PS(toStringTag, "performance", JSPROP_READONLY), JS_PS_END}; | ||
|
||
const JSFunctionSpec Performance::static_methods[] = {JS_FS_END}; | ||
const JSPropertySpec Performance::static_properties[] = {JS_PS_END}; | ||
|
||
bool Performance::create(JSContext *cx, JS::HandleObject global) { | ||
JS::RootedObject performance(cx, JS_NewObjectWithGivenProto(cx, &builtins::Performance::class_, | ||
builtins::Performance::proto_obj)); | ||
if (!performance) { | ||
return false; | ||
} | ||
if (!JS_DefineProperty(cx, global, "performance", performance, 0)) { | ||
return false; | ||
} | ||
if (!JS_DefineProperties(cx, performance, properties)) { | ||
return false; | ||
} | ||
return JS_DefineFunctions(cx, performance, methods); | ||
} | ||
|
||
bool Performance::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { | ||
JS_ReportErrorUTF8(cx, "%s can't be instantiated directly", class_name); | ||
return false; | ||
} | ||
|
||
bool Performance::init_class(JSContext *cx, JS::HandleObject global) { | ||
return init_class_impl(cx, global); | ||
} | ||
} // namespace builtins |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#ifndef JS_COMPUTE_RUNTIME_BUILTIN_PERFORMANCE_H | ||
#define JS_COMPUTE_RUNTIME_BUILTIN_PERFORMANCE_H | ||
|
||
#include "builtin.h" | ||
|
||
namespace builtins { | ||
|
||
class Performance : public BuiltinImpl<Performance> { | ||
private: | ||
public: | ||
static constexpr const char *class_name = "Performance"; | ||
static const int ctor_length = 0; | ||
enum Slots { Count }; | ||
static const JSFunctionSpec methods[]; | ||
static const JSFunctionSpec static_methods[]; | ||
static const JSPropertySpec properties[]; | ||
static const JSPropertySpec static_properties[]; | ||
static std::optional<std::chrono::steady_clock::time_point> timeOrigin; | ||
|
||
static bool now(JSContext *cx, unsigned argc, JS::Value *vp); | ||
static bool timeOrigin_get(JSContext *cx, unsigned argc, JS::Value *vp); | ||
|
||
static bool create(JSContext *cx, JS::HandleObject global); | ||
static bool constructor(JSContext *cx, unsigned argc, JS::Value *vp); | ||
static bool init_class(JSContext *cx, JS::HandleObject global); | ||
}; | ||
|
||
} // namespace builtins | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.