move more instructions as intrinsics
This commit is contained in:
parent
582753440b
commit
343684f9ce
@ -51,9 +51,6 @@ public class Instruction {
|
|||||||
STORE_MEMBER_INT(0x4A),
|
STORE_MEMBER_INT(0x4A),
|
||||||
STORE_MEMBER_STR(0x4B),
|
STORE_MEMBER_STR(0x4B),
|
||||||
|
|
||||||
DEF_PROP(0x50),
|
|
||||||
DEF_FIELD(0x51),
|
|
||||||
KEYS(0x52),
|
|
||||||
TYPEOF(0x53),
|
TYPEOF(0x53),
|
||||||
OPERATION(0x54),
|
OPERATION(0x54),
|
||||||
|
|
||||||
@ -307,8 +304,8 @@ public class Instruction {
|
|||||||
return new Instruction(Type.DUP, count, offset);
|
return new Instruction(Type.DUP, count, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Instruction storeVar(int i, boolean keep, boolean initialize) {
|
public static Instruction storeVar(int i, boolean keep) {
|
||||||
return new Instruction(Type.STORE_VAR, i, keep, initialize);
|
return new Instruction(Type.STORE_VAR, i, keep);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Instruction storeMember() {
|
public static Instruction storeMember() {
|
||||||
@ -343,17 +340,6 @@ public class Instruction {
|
|||||||
return new Instruction(Type.TYPEOF, varName);
|
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) {
|
public static Instruction operation(Operation op) {
|
||||||
return new Instruction(Type.OPERATION, op);
|
return new Instruction(Type.OPERATION, op);
|
||||||
}
|
}
|
||||||
|
@ -31,13 +31,18 @@ public class ForInNode extends Node {
|
|||||||
body.compileFunctions(target);
|
body.compileFunctions(target);
|
||||||
}
|
}
|
||||||
@Override public void compile(CompileResult target, boolean pollute) {
|
@Override public void compile(CompileResult target, boolean pollute) {
|
||||||
|
target.add(Instruction.loadIntrinsics("keys"));
|
||||||
object.compile(target, true, BreakpointType.STEP_OVER);
|
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();
|
int start = target.size();
|
||||||
target.add(Instruction.dup());
|
target.add(Instruction.dup());
|
||||||
|
target.add(Instruction.call(0, false));
|
||||||
|
target.add(Instruction.dup());
|
||||||
|
target.add(Instruction.loadMember("done"));
|
||||||
int mid = target.temp();
|
int mid = target.temp();
|
||||||
|
|
||||||
target.add(Instruction.loadMember("value")).setLocation(binding.loc());
|
target.add(Instruction.loadMember("value")).setLocation(binding.loc());
|
||||||
target.add(VariableNode.toSet(target, loc(), binding.name, false, true)).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.jmp(start - endI));
|
||||||
target.add(Instruction.discard());
|
target.add(Instruction.discard());
|
||||||
target.set(mid, Instruction.jmpIfNot(endI - mid + 1));
|
target.set(mid, Instruction.jmpIf(endI - mid + 1));
|
||||||
|
|
||||||
end.set(endI + 1);
|
end.set(endI + 1);
|
||||||
LabelContext.popLoop(target.env, label);
|
LabelContext.popLoop(target.env, label);
|
||||||
|
@ -38,11 +38,20 @@ public final class PropertyMemberNode extends FunctionNode implements Member {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public void compile(CompileResult target, boolean pollute, String name, BreakpointType bp) {
|
@Override public void compile(CompileResult target, boolean pollute, String name, BreakpointType bp) {
|
||||||
if (pollute) target.add(Instruction.dup());
|
if (isGetter()) {
|
||||||
key.compile(target, true);
|
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.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) {
|
public PropertyMemberNode(Location loc, Location end, Node key, VariableNode argument, CompoundNode body) {
|
||||||
|
@ -39,9 +39,9 @@ public final class VariableIndex {
|
|||||||
}
|
}
|
||||||
public final Instruction toSet(boolean keep) {
|
public final Instruction toSet(boolean keep) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case CAPTURES: return Instruction.storeVar(~index, keep, false);
|
case CAPTURES: return Instruction.storeVar(~index, keep);
|
||||||
case CAPTURABLES: return Instruction.storeVar(index, keep, false);
|
case CAPTURABLES: return Instruction.storeVar(index, keep);
|
||||||
case LOCALS: return Instruction.storeVar(index, keep, false);
|
case LOCALS: return Instruction.storeVar(index, keep);
|
||||||
default: throw new UnsupportedOperationException("Unknown index type " + type);
|
default: throw new UnsupportedOperationException("Unknown index type " + type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,4 +88,19 @@ setGlobalPrototypes({
|
|||||||
uint8: Uint8Array.prototype,
|
uint8: Uint8Array.prototype,
|
||||||
int32: Int32Array.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 });
|
||||||
|
});
|
@ -39,8 +39,8 @@ export interface ObjectPrimordials {
|
|||||||
defineProperty(obj: object, key: string | number | symbol, conf: { g?: Function, s?: Function, e?: boolean, c?: boolean }): boolean;
|
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;
|
defineField(obj: object, key: string | number | symbol, conf: { v?: any, e?: boolean, c?: boolean, w?: boolean }): boolean;
|
||||||
getOwnMember(obj: object, key: any): PropertyDescriptor | undefined;
|
getOwnMember(obj: object, key: any): PropertyDescriptor | undefined;
|
||||||
getOwnMembers(obj: object, onlyEnumerable: boolean): string[];
|
getMembers(obj: object, own: boolean, onlyEnumerable: boolean): string[];
|
||||||
getOwnSymbolMembers(obj: object, onlyEnumerable: boolean): symbol[];
|
getSymbolMembers(obj: object, own: boolean, onlyEnumerable: boolean): symbol[];
|
||||||
getPrototype(obj: object): object | undefined;
|
getPrototype(obj: object): object | undefined;
|
||||||
setPrototype(obj: object, proto?: object): object;
|
setPrototype(obj: object, proto?: object): object;
|
||||||
preventExt(obj: object): void;
|
preventExt(obj: object): void;
|
||||||
|
@ -55,10 +55,10 @@ export const Object = (() => {
|
|||||||
return object.getOwnMember(obj, key);
|
return object.getOwnMember(obj, key);
|
||||||
}
|
}
|
||||||
public static getOwnPropertyNames(obj: object): string[] {
|
public static getOwnPropertyNames(obj: object): string[] {
|
||||||
return object.getOwnMembers(obj, false);
|
return object.getMembers(obj, true, false);
|
||||||
}
|
}
|
||||||
public static getOwnPropertySymbols(obj: object): symbol[] {
|
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) {
|
public static defineProperty(obj: object, key: string | symbol, desc: PropertyDescriptor) {
|
||||||
@ -98,8 +98,8 @@ export const Object = (() => {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
public static defineProperties(obj: object, desc: PropertyDescriptorMap) {
|
public static defineProperties(obj: object, desc: PropertyDescriptorMap) {
|
||||||
const keys = object.getOwnMembers(desc, true) as ((keyof typeof obj) & string)[];
|
const keys = object.getMembers(desc, true, true) as ((keyof typeof obj) & string)[];
|
||||||
const symbols = object.getOwnSymbolMembers(desc, true) as ((keyof typeof obj) & symbol)[];
|
const symbols = object.getSymbolMembers(desc, true, true) as ((keyof typeof obj) & symbol)[];
|
||||||
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
Object.defineProperty(obj, keys[i], desc[keys[i]]);
|
Object.defineProperty(obj, keys[i], desc[keys[i]]);
|
||||||
@ -119,8 +119,8 @@ export const Object = (() => {
|
|||||||
public static assign(target: any) {
|
public static assign(target: any) {
|
||||||
for (let i = 1; i < arguments.length; i++) {
|
for (let i = 1; i < arguments.length; i++) {
|
||||||
const obj = arguments[i];
|
const obj = arguments[i];
|
||||||
const keys = object.getOwnMembers(obj, false);
|
const keys = object.getMembers(obj, true, false);
|
||||||
const symbols = object.getOwnSymbolMembers(obj, false);
|
const symbols = object.getSymbolMembers(obj, true, false);
|
||||||
|
|
||||||
for (let j = 0; j < keys.length; j++) {
|
for (let j = 0; j < keys.length; j++) {
|
||||||
target[keys[j]] = obj[keys[j]];
|
target[keys[j]] = obj[keys[j]];
|
||||||
@ -142,8 +142,8 @@ export const Object = (() => {
|
|||||||
|
|
||||||
public static keys(obj: any) {
|
public static keys(obj: any) {
|
||||||
const res: any[] = [];
|
const res: any[] = [];
|
||||||
const keys = object.getOwnMembers(obj, true);
|
const keys = object.getMembers(obj, true, true);
|
||||||
const symbols = object.getOwnSymbolMembers(obj, true);
|
const symbols = object.getSymbolMembers(obj, true, true);
|
||||||
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
res[res.length] = keys[i];
|
res[res.length] = keys[i];
|
||||||
@ -156,8 +156,8 @@ export const Object = (() => {
|
|||||||
}
|
}
|
||||||
public static values(obj: any) {
|
public static values(obj: any) {
|
||||||
const res: any[] = [];
|
const res: any[] = [];
|
||||||
const keys = object.getOwnMembers(obj, true);
|
const keys = object.getMembers(obj, true, true);
|
||||||
const symbols = object.getOwnSymbolMembers(obj, true);
|
const symbols = object.getSymbolMembers(obj, true, true);
|
||||||
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
res[res.length] = obj[keys[i]];
|
res[res.length] = obj[keys[i]];
|
||||||
@ -170,8 +170,8 @@ export const Object = (() => {
|
|||||||
}
|
}
|
||||||
public static entries(obj: any) {
|
public static entries(obj: any) {
|
||||||
const res: [any, any][] = [];
|
const res: [any, any][] = [];
|
||||||
const keys = object.getOwnMembers(obj, true);
|
const keys = object.getMembers(obj, true, true);
|
||||||
const symbols = object.getOwnSymbolMembers(obj, true);
|
const symbols = object.getSymbolMembers(obj, true, true);
|
||||||
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
res[res.length] = [keys[i], obj[keys[i]]];
|
res[res.length] = [keys[i], obj[keys[i]]];
|
||||||
|
@ -545,17 +545,17 @@ public class SimpleRepl {
|
|||||||
args.get(0).setPrototype(env, proto);
|
args.get(0).setPrototype(env, proto);
|
||||||
return args.get(0);
|
return args.get(0);
|
||||||
}));
|
}));
|
||||||
res.defineOwnField(env, "getOwnMembers", new NativeFunction(args -> {
|
res.defineOwnField(env, "getMembers", new NativeFunction(args -> {
|
||||||
var val = new ArrayValue();
|
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));
|
val.set(args.env, val.size(), StringValue.of(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}));
|
}));
|
||||||
res.defineOwnField(env, "getOwnSymbolMembers", new NativeFunction(args -> {
|
res.defineOwnField(env, "getSymbolMembers", new NativeFunction(args -> {
|
||||||
return ArrayValue.of(args.get(0).getOwnSymbolMembers(env, args.get(1).toBoolean()));
|
return ArrayValue.of(args.get(0).getSymbolMembers(env, args.get(1).toBoolean(), args.get(2).toBoolean()));
|
||||||
}));
|
}));
|
||||||
res.defineOwnField(env, "getOwnMember", new NativeFunction(args -> {
|
res.defineOwnField(env, "getOwnMember", new NativeFunction(args -> {
|
||||||
var obj = args.get(0);
|
var obj = args.get(0);
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
package me.topchetoeu.j2s.runtime;
|
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.Environment;
|
||||||
import me.topchetoeu.j2s.common.Instruction;
|
import me.topchetoeu.j2s.common.Instruction;
|
||||||
import me.topchetoeu.j2s.common.Operation;
|
import me.topchetoeu.j2s.common.Operation;
|
||||||
import me.topchetoeu.j2s.runtime.exceptions.EngineException;
|
import me.topchetoeu.j2s.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.j2s.runtime.values.Value;
|
import me.topchetoeu.j2s.runtime.values.Value;
|
||||||
import me.topchetoeu.j2s.runtime.values.functions.CodeFunction;
|
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.ArrayValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.BoolValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.BoolValue;
|
||||||
@ -48,51 +43,6 @@ public class InstructionRunner {
|
|||||||
return null;
|
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) {
|
private static Value execTryStart(Environment env, Instruction instr, Frame frame) {
|
||||||
int start = frame.codePtr + 1;
|
int start = frame.codePtr + 1;
|
||||||
int catchStart = (int)instr.get(0);
|
int catchStart = (int)instr.get(0);
|
||||||
@ -531,9 +481,6 @@ public class InstructionRunner {
|
|||||||
case STORE_MEMBER_INT: return execStoreMemberInt(env, instr, frame);
|
case STORE_MEMBER_INT: return execStoreMemberInt(env, instr, frame);
|
||||||
case STORE_VAR: return execStoreVar(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 TYPEOF: return execTypeof(env, instr, frame);
|
||||||
case DELETE: return execDelete(env, instr, frame);
|
case DELETE: return execDelete(env, instr, frame);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user