mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-24 08:07:30 +09:00
Issue #3049 - Add property-wrapper fast path to minimal LoongArch JIT
This commit is contained in:
parent
a48c1edbde
commit
1466d0a2fa
3 changed files with 174 additions and 1 deletions
|
|
@ -23,3 +23,13 @@ for (var i = 0; i < 100; i++) {
|
||||||
|
|
||||||
assertEq(overflow(2147483647, 1), 2147483648);
|
assertEq(overflow(2147483647, 1), 2147483648);
|
||||||
assertEq(unsupported(2, 3), 5.5);
|
assertEq(unsupported(2, 3), 5.5);
|
||||||
|
|
||||||
|
(function testPropertyWrappers() {
|
||||||
|
function getX(obj) { return obj.x; }
|
||||||
|
function setX(obj, value) { return obj.x = value; }
|
||||||
|
|
||||||
|
var obj = { x: 7 };
|
||||||
|
assertEq(getX(obj), 7);
|
||||||
|
assertEq(setX(obj, 42), 42);
|
||||||
|
assertEq(obj.x, 42);
|
||||||
|
})();
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include "jsopcode.h"
|
#include "jsopcode.h"
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
#include "vm/Interpreter.h"
|
#include "vm/Interpreter.h"
|
||||||
|
#include "vm/NativeObject-inl.h"
|
||||||
#include "vm/Stack.h"
|
#include "vm/Stack.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
|
@ -55,6 +56,13 @@ static constexpr LoongArchReg NarrowScratch = t8;
|
||||||
|
|
||||||
using TinyLoongArchJitCode = bool (*)(int32_t arg0, int32_t arg1, int32_t* out);
|
using TinyLoongArchJitCode = bool (*)(int32_t arg0, int32_t arg1, int32_t* out);
|
||||||
|
|
||||||
|
enum MinimalFastPathKind : uint8_t {
|
||||||
|
MinimalFastPathUninitialized = 0,
|
||||||
|
MinimalFastPathNone = 1,
|
||||||
|
MinimalFastPathGetter = 2,
|
||||||
|
MinimalFastPathSetter = 3
|
||||||
|
};
|
||||||
|
|
||||||
static inline uint32_t
|
static inline uint32_t
|
||||||
EncodeThreeReg(uint32_t opcode, LoongArchReg rd, LoongArchReg rj, LoongArchReg rk)
|
EncodeThreeReg(uint32_t opcode, LoongArchReg rd, LoongArchReg rj, LoongArchReg rk)
|
||||||
{
|
{
|
||||||
|
|
@ -563,6 +571,124 @@ CanDirectCallMinimalJit(JSContext* cx, HandleFunction fun, JSScript* script, con
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
PreparePropertyFastPath(JSScript* script)
|
||||||
|
{
|
||||||
|
if (script->loongArchMinimalFastPathKind() != MinimalFastPathUninitialized)
|
||||||
|
return script->loongArchMinimalFastPathKind() != MinimalFastPathNone;
|
||||||
|
|
||||||
|
uint8_t objectArg = 0;
|
||||||
|
uint8_t valueArg = 0;
|
||||||
|
uint32_t propOffset = 0;
|
||||||
|
enum State { Start, SawObject, SawValue, SawProp } state = Start;
|
||||||
|
|
||||||
|
for (jsbytecode* pc = script->code(); pc < script->codeEnd(); pc += GetBytecodeLength(pc)) {
|
||||||
|
switch (JSOp(*pc)) {
|
||||||
|
case JSOP_JUMPTARGET:
|
||||||
|
case JSOP_NOP:
|
||||||
|
continue;
|
||||||
|
case JSOP_GETARG: {
|
||||||
|
uint32_t arg = GET_ARGNO(pc);
|
||||||
|
if (state == Start) {
|
||||||
|
objectArg = uint8_t(arg);
|
||||||
|
state = SawObject;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (state == SawObject) {
|
||||||
|
valueArg = uint8_t(arg);
|
||||||
|
state = SawValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
script->setLoongArchMinimalFastPath(MinimalFastPathNone, 0, 0, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case JSOP_GETPROP:
|
||||||
|
if (state == SawObject) {
|
||||||
|
propOffset = uint32_t(pc - script->code());
|
||||||
|
state = SawProp;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JSOP_SETPROP:
|
||||||
|
case JSOP_STRICTSETPROP:
|
||||||
|
if (state == SawValue) {
|
||||||
|
propOffset = uint32_t(pc - script->code());
|
||||||
|
script->setLoongArchMinimalFastPath(MinimalFastPathSetter, objectArg, valueArg, propOffset);
|
||||||
|
state = SawProp;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JSOP_RETURN:
|
||||||
|
if (state == SawProp) {
|
||||||
|
uint8_t kind = script->loongArchMinimalFastPathKind();
|
||||||
|
if (kind == MinimalFastPathSetter)
|
||||||
|
return true;
|
||||||
|
script->setLoongArchMinimalFastPath(MinimalFastPathGetter, objectArg, 0, propOffset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
script->setLoongArchMinimalFastPath(MinimalFastPathNone, 0, 0, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
script->setLoongArchMinimalFastPath(MinimalFastPathNone, 0, 0, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
TryFastPropertyPath(JSContext* cx, JSScript* script, const CallArgs& args, bool* handled)
|
||||||
|
{
|
||||||
|
*handled = false;
|
||||||
|
|
||||||
|
if (!PreparePropertyFastPath(script))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
uint8_t kind = script->loongArchMinimalFastPathKind();
|
||||||
|
uint8_t objectArg = script->loongArchMinimalFastPathObjectArg();
|
||||||
|
if (args.length() <= objectArg || !args[objectArg].isObject())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
RootedObject obj(cx, &args[objectArg].toObject());
|
||||||
|
if (!obj->is<NativeObject>())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
jsbytecode* pc = script->code() + script->loongArchMinimalFastPathOffset();
|
||||||
|
RootedPropertyName name(cx, script->getName(pc));
|
||||||
|
RootedShape shape(cx, obj->as<NativeObject>().lookupPure(name));
|
||||||
|
if (!shape || !shape->hasSlot())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (kind == MinimalFastPathGetter) {
|
||||||
|
if (!shape->hasDefaultGetter())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Value result = obj->as<NativeObject>().getSlot(shape->slot());
|
||||||
|
if (result.isMagic())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
args.rval().set(result);
|
||||||
|
*handled = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kind == MinimalFastPathSetter) {
|
||||||
|
uint8_t valueArg = script->loongArchMinimalFastPathValueArg();
|
||||||
|
if (args.length() <= valueArg || !shape->hasDefaultSetter() || !shape->writable())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
obj->as<NativeObject>().setSlotWithType(cx, shape, args[valueArg]);
|
||||||
|
args.rval().set(args[valueArg]);
|
||||||
|
*handled = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
CanUseMinimalJit(RunState& state, InvokeState& invoke)
|
CanUseMinimalJit(RunState& state, InvokeState& invoke)
|
||||||
{
|
{
|
||||||
|
|
@ -606,6 +732,12 @@ TryCallLoongArchMinimalJit(JSContext* cx, HandleFunction fun, const CallArgs& ar
|
||||||
*handled = false;
|
*handled = false;
|
||||||
|
|
||||||
JSScript* script = fun ? fun->nonLazyScript() : nullptr;
|
JSScript* script = fun ? fun->nonLazyScript() : nullptr;
|
||||||
|
if (!script)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!TryFastPropertyPath(cx, script, args, handled) || *handled)
|
||||||
|
return !cx->isExceptionPending();
|
||||||
|
|
||||||
if (!CanDirectCallMinimalJit(cx, fun, script, args))
|
if (!CanDirectCallMinimalJit(cx, fun, script, args))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
@ -631,6 +763,14 @@ TryEnterLoongArchMinimalJit(JSContext* cx, RunState& state)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
InvokeState& invoke = *state.asInvoke();
|
InvokeState& invoke = *state.asInvoke();
|
||||||
|
bool handled = false;
|
||||||
|
if (!TryFastPropertyPath(cx, state.script(), invoke.args(), &handled))
|
||||||
|
return false;
|
||||||
|
if (handled) {
|
||||||
|
state.setReturnValue(invoke.args().rval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!CanUseMinimalJit(state, invoke))
|
if (!CanUseMinimalJit(state, invoke))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -923,10 +923,15 @@ class JSScript : public js::gc::TenuredCell
|
||||||
uint8_t* baselineOrIonSkipArgCheck;
|
uint8_t* baselineOrIonSkipArgCheck;
|
||||||
uint8_t* loongArchMinimalJitCode_;
|
uint8_t* loongArchMinimalJitCode_;
|
||||||
|
|
||||||
|
uint8_t loongArchMinimalFastPathKind_;
|
||||||
|
uint8_t loongArchMinimalFastPathObjectArg_;
|
||||||
|
uint8_t loongArchMinimalFastPathValueArg_;
|
||||||
|
uint8_t loongArchMinimalFastPathReserved_;
|
||||||
|
|
||||||
// 32-bit fields.
|
// 32-bit fields.
|
||||||
|
|
||||||
uint32_t loongArchMinimalJitCodeSize_;
|
uint32_t loongArchMinimalJitCodeSize_;
|
||||||
|
uint32_t loongArchMinimalFastPathOffset_;
|
||||||
|
|
||||||
uint32_t dataSize_; /* size of the used part of the data array */
|
uint32_t dataSize_; /* size of the used part of the data array */
|
||||||
|
|
||||||
|
|
@ -1605,6 +1610,24 @@ class JSScript : public js::gc::TenuredCell
|
||||||
loongArchMinimalJitCode_ = code;
|
loongArchMinimalJitCode_ = code;
|
||||||
loongArchMinimalJitCodeSize_ = size;
|
loongArchMinimalJitCodeSize_ = size;
|
||||||
}
|
}
|
||||||
|
uint8_t loongArchMinimalFastPathKind() const {
|
||||||
|
return loongArchMinimalFastPathKind_;
|
||||||
|
}
|
||||||
|
uint8_t loongArchMinimalFastPathObjectArg() const {
|
||||||
|
return loongArchMinimalFastPathObjectArg_;
|
||||||
|
}
|
||||||
|
uint8_t loongArchMinimalFastPathValueArg() const {
|
||||||
|
return loongArchMinimalFastPathValueArg_;
|
||||||
|
}
|
||||||
|
uint32_t loongArchMinimalFastPathOffset() const {
|
||||||
|
return loongArchMinimalFastPathOffset_;
|
||||||
|
}
|
||||||
|
void setLoongArchMinimalFastPath(uint8_t kind, uint8_t objectArg, uint8_t valueArg, uint32_t offset) {
|
||||||
|
loongArchMinimalFastPathKind_ = kind;
|
||||||
|
loongArchMinimalFastPathObjectArg_ = objectArg;
|
||||||
|
loongArchMinimalFastPathValueArg_ = valueArg;
|
||||||
|
loongArchMinimalFastPathOffset_ = offset;
|
||||||
|
}
|
||||||
|
|
||||||
bool isRelazifiable() const {
|
bool isRelazifiable() const {
|
||||||
return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ &&
|
return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ &&
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue