move more instructions as intrinsics

This commit is contained in:
TopchetoEU 2025-01-22 03:57:32 +02:00
parent 582753440b
commit 343684f9ce
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
9 changed files with 59 additions and 97 deletions

View File

@ -51,9 +51,6 @@ public class Instruction {
STORE_MEMBER_INT(0x4A),
STORE_MEMBER_STR(0x4B),
DEF_PROP(0x50),
DEF_FIELD(0x51),
KEYS(0x52),
TYPEOF(0x53),
OPERATION(0x54),
@ -307,8 +304,8 @@ public class Instruction {
return new Instruction(Type.DUP, count, offset);
}
public static Instruction storeVar(int i, boolean keep, boolean initialize) {
return new Instruction(Type.STORE_VAR, i, keep, initialize);
public static Instruction storeVar(int i, boolean keep) {
return new Instruction(Type.STORE_VAR, i, keep);
}
public static Instruction storeMember() {
@ -343,17 +340,6 @@ public class Instruction {
return new Instruction(Type.TYPEOF, varName);
}
public static Instruction keys(boolean own, boolean onlyEnumerable) {
return new Instruction(Type.KEYS, own, onlyEnumerable);
}
public static Instruction defProp(boolean setter) {
return new Instruction(Type.DEF_PROP, setter);
}
public static Instruction defField() {
return new Instruction(Type.DEF_FIELD);
}
public static Instruction operation(Operation op) {
return new Instruction(Type.OPERATION, op);
}

View File

@ -31,13 +31,18 @@ public class ForInNode extends Node {
body.compileFunctions(target);
}
@Override public void compile(CompileResult target, boolean pollute) {
target.add(Instruction.loadIntrinsics("keys"));
object.compile(target, true, BreakpointType.STEP_OVER);
target.add(Instruction.keys(false, true));
target.add(Instruction.pushValue(false));
target.add(Instruction.pushValue(true));
target.add(Instruction.call(3, false));
int start = target.size();
target.add(Instruction.dup());
target.add(Instruction.call(0, false));
target.add(Instruction.dup());
target.add(Instruction.loadMember("done"));
int mid = target.temp();
target.add(Instruction.loadMember("value")).setLocation(binding.loc());
target.add(VariableNode.toSet(target, loc(), binding.name, false, true)).setLocation(binding.loc());
@ -52,7 +57,7 @@ public class ForInNode extends Node {
target.add(Instruction.jmp(start - endI));
target.add(Instruction.discard());
target.set(mid, Instruction.jmpIfNot(endI - mid + 1));
target.set(mid, Instruction.jmpIf(endI - mid + 1));
end.set(endI + 1);
LabelContext.popLoop(target.env, label);

View File

@ -38,11 +38,20 @@ public final class PropertyMemberNode extends FunctionNode implements Member {
}
@Override public void compile(CompileResult target, boolean pollute, String name, BreakpointType bp) {
if (pollute) target.add(Instruction.dup());
key.compile(target, true);
if (isGetter()) {
target.add(Instruction.loadIntrinsics("defGetter"));
}
else {
target.add(Instruction.loadIntrinsics("defSetter"));
}
target.add(Instruction.dup(1, 1));
key.compile(target, true);
target.add(Instruction.loadFunc(target.childrenIndices.get(this), name(name), captures(target))).setLocation(loc());
target.add(Instruction.defProp(isSetter()));
target.add(Instruction.call(3, false));
target.add(Instruction.discard());
if (!pollute) target.add(Instruction.discard());
}
public PropertyMemberNode(Location loc, Location end, Node key, VariableNode argument, CompoundNode body) {

View File

@ -39,9 +39,9 @@ public final class VariableIndex {
}
public final Instruction toSet(boolean keep) {
switch (type) {
case CAPTURES: return Instruction.storeVar(~index, keep, false);
case CAPTURABLES: return Instruction.storeVar(index, keep, false);
case LOCALS: return Instruction.storeVar(index, keep, false);
case CAPTURES: return Instruction.storeVar(~index, keep);
case CAPTURABLES: return Instruction.storeVar(index, keep);
case LOCALS: return Instruction.storeVar(index, keep);
default: throw new UnsupportedOperationException("Unknown index type " + type);
}
}

View File

@ -88,4 +88,19 @@ setGlobalPrototypes({
uint8: Uint8Array.prototype,
int32: Int32Array.prototype,
});
setIntrinsic("regex", RegExp);
setIntrinsic("regex", RegExp);
setIntrinsic("keys", (obj: object, own: boolean, onlyEnumerable: boolean) => {
const members = object.getMembers(obj, own, onlyEnumerable);
let i = 0;
return () => {
if (i >= members.length) return { done: true };
else return { value: members[i++] };
};
});
setIntrinsic("defGetter", (obj: object, key: any, func: Function) => {
object.defineProperty(obj, key, { g: func, e: true, c: true });
});
setIntrinsic("defSetter", (obj: object, key: any, func: Function) => {
object.defineProperty(obj, key, { s: func, e: true, c: true });
});

View File

@ -39,8 +39,8 @@ export interface ObjectPrimordials {
defineProperty(obj: object, key: string | number | symbol, conf: { g?: Function, s?: Function, e?: boolean, c?: boolean }): boolean;
defineField(obj: object, key: string | number | symbol, conf: { v?: any, e?: boolean, c?: boolean, w?: boolean }): boolean;
getOwnMember(obj: object, key: any): PropertyDescriptor | undefined;
getOwnMembers(obj: object, onlyEnumerable: boolean): string[];
getOwnSymbolMembers(obj: object, onlyEnumerable: boolean): symbol[];
getMembers(obj: object, own: boolean, onlyEnumerable: boolean): string[];
getSymbolMembers(obj: object, own: boolean, onlyEnumerable: boolean): symbol[];
getPrototype(obj: object): object | undefined;
setPrototype(obj: object, proto?: object): object;
preventExt(obj: object): void;

View File

@ -55,10 +55,10 @@ export const Object = (() => {
return object.getOwnMember(obj, key);
}
public static getOwnPropertyNames(obj: object): string[] {
return object.getOwnMembers(obj, false);
return object.getMembers(obj, true, false);
}
public static getOwnPropertySymbols(obj: object): symbol[] {
return object.getOwnSymbolMembers(obj, false);
return object.getSymbolMembers(obj, true, false);
}
public static defineProperty(obj: object, key: string | symbol, desc: PropertyDescriptor) {
@ -98,8 +98,8 @@ export const Object = (() => {
return obj;
}
public static defineProperties(obj: object, desc: PropertyDescriptorMap) {
const keys = object.getOwnMembers(desc, true) as ((keyof typeof obj) & string)[];
const symbols = object.getOwnSymbolMembers(desc, true) as ((keyof typeof obj) & symbol)[];
const keys = object.getMembers(desc, true, true) as ((keyof typeof obj) & string)[];
const symbols = object.getSymbolMembers(desc, true, true) as ((keyof typeof obj) & symbol)[];
for (let i = 0; i < keys.length; i++) {
Object.defineProperty(obj, keys[i], desc[keys[i]]);
@ -119,8 +119,8 @@ export const Object = (() => {
public static assign(target: any) {
for (let i = 1; i < arguments.length; i++) {
const obj = arguments[i];
const keys = object.getOwnMembers(obj, false);
const symbols = object.getOwnSymbolMembers(obj, false);
const keys = object.getMembers(obj, true, false);
const symbols = object.getSymbolMembers(obj, true, false);
for (let j = 0; j < keys.length; j++) {
target[keys[j]] = obj[keys[j]];
@ -142,8 +142,8 @@ export const Object = (() => {
public static keys(obj: any) {
const res: any[] = [];
const keys = object.getOwnMembers(obj, true);
const symbols = object.getOwnSymbolMembers(obj, true);
const keys = object.getMembers(obj, true, true);
const symbols = object.getSymbolMembers(obj, true, true);
for (let i = 0; i < keys.length; i++) {
res[res.length] = keys[i];
@ -156,8 +156,8 @@ export const Object = (() => {
}
public static values(obj: any) {
const res: any[] = [];
const keys = object.getOwnMembers(obj, true);
const symbols = object.getOwnSymbolMembers(obj, true);
const keys = object.getMembers(obj, true, true);
const symbols = object.getSymbolMembers(obj, true, true);
for (let i = 0; i < keys.length; i++) {
res[res.length] = obj[keys[i]];
@ -170,8 +170,8 @@ export const Object = (() => {
}
public static entries(obj: any) {
const res: [any, any][] = [];
const keys = object.getOwnMembers(obj, true);
const symbols = object.getOwnSymbolMembers(obj, true);
const keys = object.getMembers(obj, true, true);
const symbols = object.getSymbolMembers(obj, true, true);
for (let i = 0; i < keys.length; i++) {
res[res.length] = [keys[i], obj[keys[i]]];

View File

@ -545,17 +545,17 @@ public class SimpleRepl {
args.get(0).setPrototype(env, proto);
return args.get(0);
}));
res.defineOwnField(env, "getOwnMembers", new NativeFunction(args -> {
res.defineOwnField(env, "getMembers", new NativeFunction(args -> {
var val = new ArrayValue();
for (var key : args.get(0).getOwnMembers(env, args.get(1).toBoolean())) {
for (var key : args.get(0).getMembers(env, args.get(1).toBoolean(), args.get(2).toBoolean())) {
val.set(args.env, val.size(), StringValue.of(key));
}
return val;
}));
res.defineOwnField(env, "getOwnSymbolMembers", new NativeFunction(args -> {
return ArrayValue.of(args.get(0).getOwnSymbolMembers(env, args.get(1).toBoolean()));
res.defineOwnField(env, "getSymbolMembers", new NativeFunction(args -> {
return ArrayValue.of(args.get(0).getSymbolMembers(env, args.get(1).toBoolean(), args.get(2).toBoolean()));
}));
res.defineOwnField(env, "getOwnMember", new NativeFunction(args -> {
var obj = args.get(0);

View File

@ -1,16 +1,11 @@
package me.topchetoeu.j2s.runtime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Optional;
import me.topchetoeu.j2s.common.Environment;
import me.topchetoeu.j2s.common.Instruction;
import me.topchetoeu.j2s.common.Operation;
import me.topchetoeu.j2s.runtime.exceptions.EngineException;
import me.topchetoeu.j2s.runtime.values.Value;
import me.topchetoeu.j2s.runtime.values.functions.CodeFunction;
import me.topchetoeu.j2s.runtime.values.functions.FunctionValue;
import me.topchetoeu.j2s.runtime.values.objects.ArrayValue;
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
import me.topchetoeu.j2s.runtime.values.primitives.BoolValue;
@ -48,51 +43,6 @@ public class InstructionRunner {
return null;
}
private static Value execDefProp(Environment env, Instruction instr, Frame frame) {
var val = frame.pop();
var key = frame.pop();
var obj = frame.pop();
FunctionValue accessor;
if (val == Value.UNDEFINED) accessor = null;
else if (val instanceof FunctionValue func) accessor = func;
else throw EngineException.ofType("Getter must be a function or undefined");
if ((boolean)instr.get(0)) obj.defineOwnProperty(env, key, null, Optional.of(accessor), true, true);
else obj.defineOwnProperty(env, key, Optional.of(accessor), null, true, true);
frame.codePtr++;
return null;
}
private static Value execDefField(Environment env, Instruction instr, Frame frame) {
var val = frame.pop();
var key = frame.pop();
var obj = frame.pop();
obj.defineOwnField(env, key, val, true, true, true);
frame.codePtr++;
return null;
}
private static Value execKeys(Environment env, Instruction instr, Frame frame) {
var val = frame.pop();
var members = new ArrayList<>(val.getMembers(env, instr.get(0), instr.get(1)));
Collections.reverse(members);
frame.push(Value.UNDEFINED);
for (var el : members) {
var obj = new ObjectValue();
obj.defineOwnField(env, "value", StringValue.of(el));
frame.push(obj);
}
frame.codePtr++;
return null;
}
private static Value execTryStart(Environment env, Instruction instr, Frame frame) {
int start = frame.codePtr + 1;
int catchStart = (int)instr.get(0);
@ -531,9 +481,6 @@ public class InstructionRunner {
case STORE_MEMBER_INT: return execStoreMemberInt(env, instr, frame);
case STORE_VAR: return execStoreVar(env, instr, frame);
case KEYS: return execKeys(env, instr, frame);
case DEF_PROP: return execDefProp(env, instr, frame);
case DEF_FIELD: return execDefField(env, instr, frame);
case TYPEOF: return execTypeof(env, instr, frame);
case DELETE: return execDelete(env, instr, frame);