com.oracle.truffle.js.builtins.DebugBuiltins Maven / Gradle / Ivy
/*
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to any
* person obtaining a copy of this software, associated documentation and/or
* data (collectively the "Software"), free of charge and under any and all
* copyright rights in the Software, and any and all patent rights owned or
* freely licensable by each licensor hereunder covering either (i) the
* unmodified Software as contributed to or provided by such licensor, or (ii)
* the Larger Works (as defined below), to deal in both
*
* (a) the Software, and
*
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
* one is included with the Software each a "Larger Work" to which the Software
* is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy, create
* derivative works of, display, perform, and distribute the Software and make,
* use, sell, offer for sale, import, export, have made, and have sold the
* Software and the Larger Work(s), and to sublicense the foregoing rights on
* either these or other terms.
*
* This license is subject to the following condition:
*
* The above copyright notice and either this complete permission notice or at a
* minimum a reference to the UPL must be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.oracle.truffle.js.builtins;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.oracle.js.parser.ir.Module.ModuleRequest;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.profiles.ConditionProfile;
import com.oracle.truffle.api.profiles.ValueProfile;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.api.strings.TruffleStringBuilderUTF16;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugArrayTypeNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugAssertIntNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugClassNameNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugClassNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugContinueInInterpreterNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugCreateSafeIntegerNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugDumpCountersNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugDumpFunctionTreeNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugHeapDumpNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugIsHolesArrayNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugJSStackNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugLoadModuleNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugNeverPartOfCompilationNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugPrintObjectNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugPrintSourceAttributionNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugShapeNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugStringCompareNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugSystemPropertiesNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugSystemPropertyNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugToJavaStringNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugTypedArrayDetachBufferNodeGen;
import com.oracle.truffle.js.builtins.helper.GCNodeGen;
import com.oracle.truffle.js.builtins.helper.HeapDump;
import com.oracle.truffle.js.lang.JavaScriptLanguage;
import com.oracle.truffle.js.nodes.JSGuards;
import com.oracle.truffle.js.nodes.ScriptNode;
import com.oracle.truffle.js.nodes.cast.JSToObjectNode;
import com.oracle.truffle.js.nodes.function.JSBuiltin;
import com.oracle.truffle.js.nodes.function.JSBuiltinNode;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.Evaluator;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.JSErrorType;
import com.oracle.truffle.js.runtime.JSException;
import com.oracle.truffle.js.runtime.JSRealm;
import com.oracle.truffle.js.runtime.JSRuntime;
import com.oracle.truffle.js.runtime.SafeInteger;
import com.oracle.truffle.js.runtime.Strings;
import com.oracle.truffle.js.runtime.Symbol;
import com.oracle.truffle.js.runtime.builtins.BuiltinEnum;
import com.oracle.truffle.js.runtime.builtins.JSArray;
import com.oracle.truffle.js.runtime.builtins.JSArrayBuffer;
import com.oracle.truffle.js.runtime.builtins.JSArrayBufferObject;
import com.oracle.truffle.js.runtime.builtins.JSAsyncGeneratorObject;
import com.oracle.truffle.js.runtime.builtins.JSFunction;
import com.oracle.truffle.js.runtime.builtins.JSFunctionObject;
import com.oracle.truffle.js.runtime.builtins.JSGeneratorObject;
import com.oracle.truffle.js.runtime.builtins.JSGlobal;
import com.oracle.truffle.js.runtime.builtins.JSOrdinary;
import com.oracle.truffle.js.runtime.builtins.JSProxy;
import com.oracle.truffle.js.runtime.objects.JSDynamicObject;
import com.oracle.truffle.js.runtime.objects.JSModuleData;
import com.oracle.truffle.js.runtime.objects.JSModuleLoader;
import com.oracle.truffle.js.runtime.objects.JSModuleRecord;
import com.oracle.truffle.js.runtime.objects.JSObject;
import com.oracle.truffle.js.runtime.objects.Null;
import com.oracle.truffle.js.runtime.objects.PropertyDescriptor;
import com.oracle.truffle.js.runtime.objects.ScriptOrModule;
import com.oracle.truffle.js.runtime.objects.Undefined;
/**
* Contains builtins for {@code Debug} object.
*/
public final class DebugBuiltins extends JSBuiltinsContainer.SwitchEnum {
public static final TruffleString NOT_AN_ARRAY = Strings.constant("NOT_AN_ARRAY");
public static final TruffleString NOT_AN_OBJECT = Strings.constant("not_an_object");
public static final JSBuiltinsContainer BUILTINS = new DebugBuiltins();
protected DebugBuiltins() {
super(JSRealm.DEBUG_CLASS_NAME, Debug.class);
}
public enum Debug implements BuiltinEnum {
class_(1),
getClass(1),
className(1),
shape(1),
dumpCounters(0),
dumpFunctionTree(1),
printObject(1),
toJavaString(1),
srcattr(1),
arraytype(1),
assertInt(2),
continueInInterpreter(0),
stringCompare(2),
isHolesArray(1),
jsStack(0),
loadModule(2),
createSafeInteger(1),
typedArrayDetachBuffer(1),
systemGC(0),
systemProperty(1),
systemProperties(0),
neverPartOfCompilation(0),
dumpHeap(2);
private final int length;
Debug(int length) {
this.length = length;
}
@Override
public int getLength() {
return length;
}
}
@Override
protected Object createNode(JSContext context, JSBuiltin builtin, boolean construct, boolean newTarget, Debug builtinEnum) {
switch (builtinEnum) {
case class_:
return DebugClassNodeGen.create(context, builtin, true, args().fixedArgs(1).createArgumentNodes(context));
case getClass:
return DebugClassNodeGen.create(context, builtin, false, args().fixedArgs(1).createArgumentNodes(context));
case className:
return DebugClassNameNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case shape:
return DebugShapeNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case dumpCounters:
return DebugDumpCountersNodeGen.create(context, builtin, args().createArgumentNodes(context));
case dumpFunctionTree:
return DebugDumpFunctionTreeNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case printObject:
return DebugPrintObjectNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
case toJavaString:
return DebugToJavaStringNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case srcattr:
return DebugPrintSourceAttributionNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case arraytype:
return DebugArrayTypeNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case assertInt:
return DebugAssertIntNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
case continueInInterpreter:
return DebugContinueInInterpreterNodeGen.create(context, builtin, false, args().createArgumentNodes(context));
case stringCompare:
return DebugStringCompareNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
case isHolesArray:
return DebugIsHolesArrayNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case jsStack:
return DebugJSStackNodeGen.create(context, builtin, args().createArgumentNodes(context));
case loadModule:
return DebugLoadModuleNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
case systemGC:
return GCNodeGen.create(context, builtin, args().createArgumentNodes(context));
case systemProperty:
return DebugSystemPropertyNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case systemProperties:
return DebugSystemPropertiesNodeGen.create(context, builtin, args().createArgumentNodes(context));
case neverPartOfCompilation:
return DebugNeverPartOfCompilationNodeGen.create(context, builtin, args().createArgumentNodes(context));
case typedArrayDetachBuffer:
return DebugTypedArrayDetachBufferNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case createSafeInteger:
return DebugCreateSafeIntegerNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case dumpHeap:
return DebugHeapDumpNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
}
return null;
}
public abstract static class DebugContinueInInterpreter extends JSBuiltinNode {
private final boolean invalidate;
public DebugContinueInInterpreter(JSContext context, JSBuiltin builtin, boolean invalidate) {
super(context, builtin);
this.invalidate = invalidate;
}
@Specialization
protected Object continueInInterpreter() {
if (invalidate) {
CompilerDirectives.transferToInterpreterAndInvalidate();
} else {
CompilerDirectives.transferToInterpreter();
}
return Undefined.instance;
}
}
public abstract static class DebugClassNode extends JSBuiltinNode {
private final boolean getName;
public DebugClassNode(JSContext context, JSBuiltin builtin, boolean getName) {
super(context, builtin);
this.getName = getName;
}
@Specialization
protected Object clazz(Object obj) {
if (obj == null) {
return Null.instance;
}
if (getName) {
return Strings.fromJavaString(obj.getClass().getName());
} else {
return getRealm().getEnv().asGuestValue(obj.getClass());
}
}
}
public abstract static class DebugClassNameNode extends JSBuiltinNode {
public DebugClassNameNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@Specialization
@TruffleBoundary
protected static Object clazz(Object obj) {
if (obj instanceof Symbol) {
return Null.instance;
} else if (JSDynamicObject.isJSDynamicObject(obj)) {
JSDynamicObject jsObj = (JSDynamicObject) obj;
if (jsObj instanceof JSGeneratorObject) {
return JSFunction.GENERATOR_NAME;
} else if (jsObj instanceof JSAsyncGeneratorObject) {
return JSFunction.ASYNC_GENERATOR_NAME;
} else if (JSProxy.isJSProxy(jsObj)) {
return clazz(JSProxy.getTarget(jsObj));
}
return JSObject.getClassName(jsObj);
} else {
return NOT_AN_OBJECT;
}
}
}
public abstract static class DebugShapeNode extends JSBuiltinNode {
public DebugShapeNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected static Object shape(Object obj) {
if (obj instanceof JSDynamicObject) {
return Strings.fromJavaString(((JSDynamicObject) obj).getShape().toString());
}
return Undefined.instance;
}
}
public abstract static class DebugDumpCountersNode extends JSBuiltinNode {
public DebugDumpCountersNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected static Object dumpCounters() {
com.oracle.truffle.object.DebugCounter.dumpCounters();
com.oracle.truffle.js.runtime.util.DebugCounter.dumpCounters();
return Undefined.instance;
}
}
public abstract static class DebugDumpFunctionTreeNode extends JSBuiltinNode {
public DebugDumpFunctionTreeNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected Object dumpFunctionTree(Object functionObj) {
if (JSFunction.isJSFunction(functionObj)) {
CallTarget target = JSFunction.getCallTarget((JSFunctionObject) functionObj);
if (target instanceof RootCallTarget) {
NodeUtil.printTree(getRealm().getOutputWriter(), ((RootCallTarget) target).getRootNode());
return Undefined.instance;
} else {
throw Errors.shouldNotReachHere();
}
}
return Undefined.instance;
}
}
public abstract static class DebugPrintObjectNode extends JSBuiltinNode {
public DebugPrintObjectNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected Object printObject(JSDynamicObject object, Object level0) {
int level = level0 == Undefined.instance ? 1 : JSRuntime.toInt32(level0);
getRealm().getOutputWriter().println(debugPrint(object, 0, level));
return Undefined.instance;
}
@TruffleBoundary
protected TruffleString debugPrint(JSDynamicObject object, int level, int levelStop) {
List properties = JSObject.enumerableOwnNames(object);
var sb = Strings.builderCreate(properties.size() * 10);
Strings.builderAppend(sb, "{\n");
for (TruffleString key : properties) {
indent(sb, level + 1);
PropertyDescriptor desc = JSObject.getOwnProperty(object, key);
// must not invoke accessor functions here
Strings.builderAppend(sb, key);
if (desc.isDataDescriptor()) {
Object value = JSObject.get(object, key);
if (JSDynamicObject.isJSDynamicObject(value)) {
if ((JSGuards.isJSOrdinaryObject(value) || JSGlobal.isJSGlobalObject(value)) && !key.equals(JSObject.CONSTRUCTOR)) {
if (level < levelStop && !key.equals(JSObject.CONSTRUCTOR)) {
value = debugPrint((JSDynamicObject) value, level + 1, levelStop);
} else {
value = Strings.EMPTY_OBJECT_DOTS;
}
} else {
value = JSObject.getJSClass((JSDynamicObject) value);
}
}
Strings.builderAppend(sb, Strings.COLON_SPACE);
Strings.builderAppend(sb, Strings.fromObject(value));
}
if (!key.equals(properties.get(properties.size() - 1))) {
Strings.builderAppend(sb, ',');
}
Strings.builderAppend(sb, '\n');
}
indent(sb, level);
Strings.builderAppend(sb, '}');
return Strings.builderToString(sb);
}
private static void indent(TruffleStringBuilderUTF16 sb, int level) {
for (int i = 0; i < level; i++) {
Strings.builderAppend(sb, ' ');
}
}
}
public abstract static class DebugToJavaStringNode extends JSBuiltinNode {
public DebugToJavaStringNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected static Object toJavaString(Object thing) {
return Strings.fromJavaString(String.valueOf(thing));
}
}
public abstract static class DebugPrintSourceAttribution extends JSBuiltinNode {
public DebugPrintSourceAttribution(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected Object printSourceAttribution(JSFunctionObject function) {
CallTarget callTarget = JSFunction.getCallTarget(function);
if (callTarget instanceof RootCallTarget) {
return Strings.fromJavaString(NodeUtil.printSourceAttributionTree(((RootCallTarget) callTarget).getRootNode()));
}
return Undefined.instance;
}
@TruffleBoundary
@Specialization
protected Object printSourceAttribution(TruffleString code) {
ScriptNode scriptNode = getContext().getEvaluator().evalCompile(getContext(), Strings.toJavaString(code), "");
return Strings.fromJavaString(NodeUtil.printSourceAttributionTree(scriptNode.getRootNode()));
}
@TruffleBoundary
@Fallback
protected Object illegalArgument(@SuppressWarnings("unused") Object unused) {
throw Errors.createTypeError("argument must be a function or a string");
}
}
public abstract static class DebugArrayTypeNode extends JSBuiltinNode {
public DebugArrayTypeNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected TruffleString arraytype(Object array) {
if (!(JSDynamicObject.isJSDynamicObject(array)) || !(JSObject.hasArray(array))) {
return NOT_AN_ARRAY;
}
return Strings.fromJavaString(JSObject.getArray((JSDynamicObject) array).getClass().getSimpleName());
}
}
public abstract static class DebugAssertIntNode extends JSBuiltinNode {
public DebugAssertIntNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected Object assertInt(Object value, Object message) {
if (!(value instanceof Integer)) {
throw Errors.createTypeError("assert: expected integer here, got " + value.getClass().getSimpleName() + ", message: " + JSRuntime.toString(message));
}
return Undefined.instance;
}
}
public abstract static class DebugHeapDumpNode extends JSBuiltinNode {
public DebugHeapDumpNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected TruffleString heapDump(Object fileName0, Object live0) {
String fileName = fileName0 == Undefined.instance ? HeapDump.defaultDumpName() : Strings.toJavaString(JSRuntime.toString(fileName0));
boolean live = live0 == Undefined.instance || JSRuntime.toBoolean(live0);
try {
HeapDump.dump(fileName, live);
} catch (IOException e) {
throw JSException.create(JSErrorType.Error, e.getMessage(), e, this);
} catch (IllegalArgumentException e) {
throw JSException.create(JSErrorType.Error, getBuiltin().getFullName() + " unsupported", e, this);
}
return Strings.fromJavaString(fileName);
}
}
/**
* Used by testV8!
*/
public abstract static class DebugStringCompareNode extends JSBuiltinNode {
public DebugStringCompareNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@Specialization
protected int stringCompare(Object a, Object b,
@Cached TruffleString.CompareCharsUTF16Node compareNode) {
TruffleString str1 = JSRuntime.toString(a);
TruffleString str2 = JSRuntime.toString(b);
return Strings.compareTo(compareNode, str1, str2);
}
}
/**
* Exposes the "holes" property of arrays. Used e.g. by V8HasFastHoleyElements.
*/
public abstract static class DebugIsHolesArrayNode extends JSBuiltinNode {
@Child private JSToObjectNode toObjectNode;
private final ValueProfile arrayType;
private final ConditionProfile isArray;
public DebugIsHolesArrayNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
this.toObjectNode = JSToObjectNode.create();
this.arrayType = ValueProfile.createClassProfile();
this.isArray = ConditionProfile.create();
}
@Specialization
protected boolean isHolesArray(Object arr) {
Object obj = toObjectNode.execute(arr);
if (isArray.profile(JSArray.isJSArray(obj))) {
JSDynamicObject dynObj = (JSDynamicObject) obj;
return arrayType.profile(JSObject.getArray(dynObj)).hasHoles(dynObj);
} else {
return false;
}
}
}
/**
* Prints the current JS stack.
*/
public abstract static class DebugJSStackNode extends JSBuiltinNode {
public DebugJSStackNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@Specialization
protected Object printJSStack() {
JSException.printJSStackTrace(getParent());
return Undefined.instance;
}
}
public abstract static class DebugLoadModuleNode extends JSBuiltinNode {
public DebugLoadModuleNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected TruffleString loadModule(Object nameObj, Object modulesSourceMapObj) {
TruffleString name = JSRuntime.toString(nameObj);
JSDynamicObject modulesSourceMap = (JSDynamicObject) modulesSourceMapObj;
Evaluator evaluator = getContext().getEvaluator();
JSModuleLoader moduleLoader = new JSModuleLoader() {
private final Map moduleMap = new HashMap<>();
private Source resolveModuleSource(@SuppressWarnings("unused") ScriptOrModule referencingModule, TruffleString specifier) {
Object moduleEntry = JSObject.get(modulesSourceMap, specifier);
if (moduleEntry == Undefined.instance) {
throw Errors.createSyntaxError(String.format("Could not find imported module %s", specifier));
}
String code = JSRuntime.toJavaString(moduleEntry);
return Source.newBuilder(JavaScriptLanguage.ID, code, Strings.toJavaString(name)).mimeType(JavaScriptLanguage.MODULE_MIME_TYPE).build();
}
@Override
public JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, ModuleRequest moduleRequest) {
return moduleMap.computeIfAbsent(moduleRequest.getSpecifier(),
(key) -> new JSModuleRecord(evaluator.envParseModule(JSRealm.get(null), resolveModuleSource(referencingModule, key)), this));
}
@Override
public JSModuleRecord loadModule(Source moduleSource, JSModuleData moduleData) {
throw new UnsupportedOperationException();
}
};
JSModuleRecord module = moduleLoader.resolveImportedModule(null, ModuleRequest.create(name));
JSRealm realm = getRealm();
evaluator.moduleLinking(realm, module);
evaluator.moduleEvaluation(realm, module);
return Strings.fromJavaString(String.valueOf(module));
}
}
public abstract static class DebugSystemProperties extends JSBuiltinNode {
public DebugSystemProperties(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected Object systemProperties() {
JSDynamicObject result = JSOrdinary.create(getContext(), getRealm());
for (Map.Entry
© 2015 - 2025 Weber Informatics LLC | Privacy Policy