Skip to content

Commit 7ee469a

Browse files
committed
[GR-44779] Switch incoming TruffleStrings to UTF-16; avoid using uncached nodes.
PullRequest: js/2747
2 parents b2291ca + 1b227bc commit 7ee469a

33 files changed

+262
-315
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
6+
*/
7+
8+
/**
9+
* Test regexp-legacy-features behavior.
10+
*/
11+
12+
load("assert.js");
13+
14+
class MyRegExp extends RegExp {}
15+
16+
// TypeError: RegExp.prototype.compile cannot be used on subclasses of RegExp.
17+
assertThrows(() => new MyRegExp(/foo/).compile('pattern', ''), TypeError);
18+
assertThrows(() => new MyRegExp('foo').compile('pattern', ''), TypeError);

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,8 +1435,8 @@ protected JSDynamicObject constructRegExp(JSDynamicObject newTarget, Object patt
14351435
boolean legacyFeaturesEnabled;
14361436
if (isCall) {
14371437
// we are in the "call" case, i.e. NewTarget is undefined (before)
1438-
if (callIsRegExpProfile.profile(node, hasMatchSymbol && flags == Undefined.instance && JSDynamicObject.isJSDynamicObject(pattern))) {
1439-
JSDynamicObject patternObj = (JSDynamicObject) pattern;
1438+
if (callIsRegExpProfile.profile(node, hasMatchSymbol && flags == Undefined.instance && pattern instanceof JSObject)) {
1439+
JSObject patternObj = (JSObject) pattern;
14401440
Object patternConstructor = getConstructor(patternObj);
14411441
if (constructorEquivalentProfile.profile(node, patternConstructor == getRealm().getRegExpConstructor())) {
14421442
return patternObj;
@@ -1465,17 +1465,16 @@ protected JSRegExpObject constructRegExpImpl(Object patternObj, Object flags, bo
14651465
if (isJSRegExp) {
14661466
regexpObject.enter(node);
14671467
Object compiledRegex = JSRegExp.getCompiledRegex((JSDynamicObject) patternObj);
1468-
if (flags == Undefined.instance) {
1469-
return getCreateRegExpNode().createRegExp(compiledRegex);
1470-
} else {
1468+
if (flags != Undefined.instance) {
1469+
regexpObjectNewFlagsBranch.enter(node);
14711470
if (getContext().getEcmaScriptVersion() < 6) {
14721471
throw Errors.createTypeError("Cannot supply flags when constructing one RegExp from another");
14731472
}
14741473
Object flagsStr = flagsToString(flags);
1475-
regexpObjectNewFlagsBranch.enter(node);
1476-
Object newCompiledRegex = getCompileRegexNode().compile(readPattern.execute(node, compiledRegex, TRegexUtil.Props.CompiledRegex.PATTERN), flagsStr);
1477-
return getCreateRegExpNode().createRegExp(newCompiledRegex);
1474+
TruffleString patternStr = readPattern.execute(node, compiledRegex, TRegexUtil.Props.CompiledRegex.PATTERN);
1475+
compiledRegex = getCompileRegexNode().compile(patternStr, flagsStr);
14781476
}
1477+
return getCreateRegExpNode().createRegExp(compiledRegex, legacyFeaturesEnabled);
14791478
} else if (hasMatchSymbol) {
14801479
regexpMatcherObject.enter(node);
14811480
JSDynamicObject patternJSObj = (JSDynamicObject) patternObj;
@@ -1538,23 +1537,23 @@ private Object flagsToString(Object f) {
15381537
private Object getConstructor(JSDynamicObject obj) {
15391538
if (getConstructorNode == null) {
15401539
CompilerDirectives.transferToInterpreterAndInvalidate();
1541-
getConstructorNode = insert(PropertyGetNode.create(JSObject.CONSTRUCTOR, false, getContext()));
1540+
getConstructorNode = insert(PropertyGetNode.create(JSObject.CONSTRUCTOR, getContext()));
15421541
}
15431542
return getConstructorNode.getValue(obj);
15441543
}
15451544

15461545
private Object getSource(JSDynamicObject obj) {
15471546
if (getSourceNode == null) {
15481547
CompilerDirectives.transferToInterpreterAndInvalidate();
1549-
getSourceNode = insert(PropertyGetNode.create(JSRegExp.SOURCE, false, getContext()));
1548+
getSourceNode = insert(PropertyGetNode.create(JSRegExp.SOURCE, getContext()));
15501549
}
15511550
return getSourceNode.getValue(obj);
15521551
}
15531552

15541553
private Object getFlags(JSDynamicObject obj) {
15551554
if (getFlagsNode == null) {
15561555
CompilerDirectives.transferToInterpreterAndInvalidate();
1557-
getFlagsNode = insert(PropertyGetNode.create(JSRegExp.FLAGS, false, getContext()));
1556+
getFlagsNode = insert(PropertyGetNode.create(JSRegExp.FLAGS, getContext()));
15581557
}
15591558
return getFlagsNode.getValue(obj);
15601559
}

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ErrorPrototypeBuiltins.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,22 +132,19 @@ public ErrorPrototypeToStringNode(JSContext context, JSBuiltin builtin) {
132132
super(context, builtin);
133133
}
134134

135+
@TruffleBoundary
135136
@Specialization(guards = "!isObjectNode.executeBoolean(thisObj)", limit = "1")
136-
protected Object toStringNonObject(Object thisObj,
137-
@Cached @Shared @SuppressWarnings("unused") IsObjectNode isObjectNode,
138-
@Cached @Shared JSToStringNode toStringNode,
139-
@Cached TruffleString.ConcatNode concatNode) {
140-
TruffleString name = toStringNode.executeString(thisObj);
141-
String message = Strings.toJavaString(Strings.concat(concatNode, Strings.METHOD_ERROR_PROTOTYPE_TO_STRING_CALLED_ON_INCOMPATIBLE_RECEIVER, name));
142-
throw Errors.createTypeError(message, this);
137+
protected final Object toStringNonObject(Object thisObj,
138+
@Cached @Shared @SuppressWarnings("unused") IsObjectNode isObjectNode) {
139+
throw Errors.createTypeErrorIncompatibleReceiver(getBuiltin().getFullName(), thisObj);
143140
}
144141

145142
@Specialization(guards = "isObjectNode.executeBoolean(errorObj)", limit = "1")
146-
protected Object toStringObject(Object errorObj,
143+
protected static Object toStringObject(Object errorObj,
147144
@Cached @Shared @SuppressWarnings("unused") IsObjectNode isObjectNode,
148145
@Cached("create(NAME, false, getContext())") PropertyGetNode getNameNode,
149146
@Cached("create(MESSAGE, false, getContext())") PropertyGetNode getMessageNode,
150-
@Cached @Shared JSToStringNode toStringNode) {
147+
@Cached JSToStringNode toStringNode) {
151148
Object objName = getNameNode.getValue(errorObj);
152149
TruffleString strName = (objName == Undefined.instance) ? Strings.UC_ERROR : toStringNode.executeString(objName);
153150
Object objMessage = getMessageNode.getValue(errorObj);

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/FunctionPrototypeBuiltins.java

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,16 @@
4343
import com.oracle.truffle.api.CallTarget;
4444
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
4545
import com.oracle.truffle.api.RootCallTarget;
46-
import com.oracle.truffle.api.dsl.Bind;
4746
import com.oracle.truffle.api.dsl.Cached;
48-
import com.oracle.truffle.api.dsl.Idempotent;
47+
import com.oracle.truffle.api.dsl.Cached.Exclusive;
4948
import com.oracle.truffle.api.dsl.Cached.Shared;
49+
import com.oracle.truffle.api.dsl.Idempotent;
50+
import com.oracle.truffle.api.dsl.ImportStatic;
5051
import com.oracle.truffle.api.dsl.NeverDefault;
5152
import com.oracle.truffle.api.dsl.Specialization;
5253
import com.oracle.truffle.api.interop.InteropLibrary;
5354
import com.oracle.truffle.api.interop.UnsupportedMessageException;
5455
import com.oracle.truffle.api.library.CachedLibrary;
55-
import com.oracle.truffle.api.nodes.Node;
5656
import com.oracle.truffle.api.nodes.RootNode;
5757
import com.oracle.truffle.api.object.DynamicObjectLibrary;
5858
import com.oracle.truffle.api.profiles.ConditionProfile;
@@ -300,11 +300,11 @@ public JSBindNode(JSContext context, JSBuiltin builtin) {
300300
}
301301

302302
@Specialization
303-
protected JSDynamicObject bindJSFunction(JSFunctionObject thisFnObj, Object thisArg, Object[] args,
303+
protected final JSDynamicObject bindJSFunction(JSFunctionObject thisFnObj, Object thisArg, Object[] args,
304304
@Cached @Shared GetPrototypeNode getPrototypeNode,
305305
@Cached("create(getContext())") @Shared CopyFunctionNameAndLengthNode copyNameAndLengthNode,
306306
@Cached @Shared("isConstructorProf") InlinedConditionProfile isConstructorProfile,
307-
@Cached InlinedConditionProfile isAsyncProfile,
307+
@Cached @Exclusive InlinedConditionProfile isAsyncProfile,
308308
@Cached @Shared("setProtoProf") InlinedConditionProfile setProtoProfile) {
309309
JSDynamicObject proto = getPrototypeNode.execute(thisFnObj);
310310

@@ -316,20 +316,19 @@ protected JSDynamicObject bindJSFunction(JSFunctionObject thisFnObj, Object this
316316
return boundFunction;
317317
}
318318

319-
@Specialization(guards = {"!isJSFunction(thisObj)", "isCallableNode.executeBoolean(thisObj)"})
320-
protected JSDynamicObject bindOther(Object thisObj, Object thisArg, Object[] args,
321-
@Bind("this") Node node,
319+
@Specialization(guards = {"!isJSFunction(thisObj)", "isCallableNode.executeBoolean(thisObj)"}, limit = "1")
320+
protected final JSDynamicObject bindOther(Object thisObj, Object thisArg, Object[] args,
322321
@SuppressWarnings("unused") @Cached @Shared IsCallableNode isCallableNode,
323322
@Cached @Shared GetPrototypeNode getPrototypeNode,
324323
@Cached ForeignObjectPrototypeNode foreignPrototypeNode,
325324
@Cached IsConstructorNode isConstructorNode,
326325
@Cached("create(getContext())") @Shared CopyFunctionNameAndLengthNode copyNameAndLengthNode,
327-
@Cached InlinedConditionProfile isProxyProfile,
326+
@Cached @Exclusive InlinedConditionProfile isProxyProfile,
328327
@Cached @Shared("isConstructorProf") InlinedConditionProfile isConstructorProfile,
329328
@Cached @Shared("setProtoProf") InlinedConditionProfile setProtoProfile) {
330329
JSRealm realm = JSRuntime.getFunctionRealm(thisObj, JSRealm.get(this));
331330
JSDynamicObject proto;
332-
if (isProxyProfile.profile(node, JSProxy.isJSProxy(thisObj))) {
331+
if (isProxyProfile.profile(this, JSProxy.isJSProxy(thisObj))) {
333332
proto = getPrototypeNode.execute(thisObj);
334333
} else {
335334
assert JSRuntime.isCallableForeign(thisObj);
@@ -341,12 +340,12 @@ protected JSDynamicObject bindOther(Object thisObj, Object thisArg, Object[] arg
341340
}
342341

343342
JSContext context = getContext();
344-
boolean constructor = isConstructorProfile.profile(node, isConstructorNode.executeBoolean(thisObj));
343+
boolean constructor = isConstructorProfile.profile(this, isConstructorNode.executeBoolean(thisObj));
345344
JSFunctionData boundFunctionData = context.getBoundFunctionData(constructor, false);
346345
JSFunctionObject boundFunction = JSFunction.createBound(context, realm, boundFunctionData, thisObj, thisArg, args);
347346

348347
boolean needSetProto = proto != realm.getFunctionPrototype();
349-
if (setProtoProfile.profile(node, needSetProto)) {
348+
if (setProtoProfile.profile(this, needSetProto)) {
350349
JSObject.setPrototype(boundFunction, proto);
351350
}
352351

@@ -356,13 +355,14 @@ protected JSDynamicObject bindOther(Object thisObj, Object thisArg, Object[] arg
356355
}
357356

358357
@SuppressWarnings("unused")
359-
@Specialization(guards = {"!isCallableNode.executeBoolean(thisObj)"})
360-
protected JSDynamicObject bindError(Object thisObj, Object thisArg, Object[] arg,
358+
@Specialization(guards = {"!isCallableNode.executeBoolean(thisObj)"}, limit = "1")
359+
protected static JSDynamicObject bindError(Object thisObj, Object thisArg, Object[] arg,
361360
@SuppressWarnings("unused") @Cached @Shared IsCallableNode isCallableNode) {
362361
throw Errors.createTypeErrorNotAFunction(thisObj);
363362
}
364363
}
365364

365+
@ImportStatic(JSConfig.class)
366366
public abstract static class JSFunctionToStringNode extends JSBuiltinNode {
367367

368368
public JSFunctionToStringNode(JSContext context, JSBuiltin builtin) {
@@ -397,28 +397,29 @@ private static TruffleString getNameIntl(TruffleString name) {
397397
@SuppressWarnings("unused")
398398
@Specialization(guards = {"isES2019OrLater()", "!isJSFunction(fnObj)", "isCallable.executeBoolean(fnObj)"}, limit = "1")
399399
protected TruffleString toStringCallable(Object fnObj,
400-
@Cached @Shared("isCallable") IsCallableNode isCallable,
401-
@CachedLibrary("fnObj") InteropLibrary interop) {
402-
if (interop.hasExecutableName(fnObj)) {
403-
try {
404-
Object name = interop.getExecutableName(fnObj);
405-
return getNameIntl(InteropLibrary.getUncached().asTruffleString(name));
406-
} catch (UnsupportedMessageException e) {
400+
@Cached @Shared IsCallableNode isCallable,
401+
@CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop,
402+
@CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interopStr,
403+
@Cached TruffleString.SwitchEncodingNode switchEncoding) {
404+
try {
405+
Object name = null;
406+
if (interop.hasExecutableName(fnObj)) {
407+
name = interop.getExecutableName(fnObj);
408+
} else if (interop.isMetaObject(fnObj)) {
409+
name = interop.getMetaSimpleName(fnObj);
407410
}
408-
} else if (interop.isMetaObject(fnObj)) {
409-
try {
410-
Object name = interop.getMetaSimpleName(fnObj);
411-
return getNameIntl(InteropLibrary.getUncached().asTruffleString(name));
412-
} catch (UnsupportedMessageException e) {
411+
if (name != null) {
412+
return getNameIntl(Strings.interopAsTruffleString(name, interopStr, switchEncoding));
413413
}
414+
} catch (UnsupportedMessageException e) {
414415
}
415416
return Strings.FUNCTION_NATIVE_CODE;
416417
}
417418

418419
@SuppressWarnings("unused")
419420
@Specialization(guards = {"isES2019OrLater()", "!isCallable.executeBoolean(fnObj)"}, limit = "1")
420421
protected TruffleString toStringNotCallable(Object fnObj,
421-
@Cached @Shared("isCallable") IsCallableNode isCallable) {
422+
@Cached @Shared IsCallableNode isCallable) {
422423
throw Errors.createTypeErrorNotAFunction(fnObj);
423424
}
424425

@@ -445,7 +446,7 @@ private static TruffleString toStringDefaultTarget(JSDynamicObject fnObj) {
445446
if (ssect == null || !ssect.isAvailable() || ssect.getSource().isInternal()) {
446447
result = Strings.concatAll(Strings.FUNCTION_SPC, JSFunction.getName(fnObj), Strings.FUNCTION_NATIVE_CODE_BODY);
447448
} else {
448-
result = Strings.fromCharSequence(ssect.getCharacters());
449+
result = Strings.fromJavaString(ssect.getCharacters().toString());
449450
}
450451
return result;
451452
}

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,21 +1243,20 @@ public JSGlobalIndirectEvalNode(JSContext context, JSBuiltin builtin) {
12431243
}
12441244

12451245
@Specialization
1246-
protected Object indirectEvalString(TruffleString source) {
1246+
protected Object indirectEvalString(TruffleString source,
1247+
@Cached @Shared TruffleString.ToJavaStringNode toJavaString) {
12471248
JSRealm realm = getRealm();
1248-
return parseIndirectEval(realm, Strings.toJavaString(source)).runEval(callNode, realm);
1249+
return parseIndirectEval(realm, Strings.toJavaString(toJavaString, source)).runEval(callNode, realm);
12491250
}
12501251

12511252
@InliningCutoff
12521253
@Specialization(guards = "isForeignObject(source)", limit = "3")
12531254
protected Object indirectEvalForeignObject(Object source,
1254-
@CachedLibrary("source") InteropLibrary interop) {
1255+
@CachedLibrary("source") InteropLibrary interop,
1256+
@Cached TruffleString.SwitchEncodingNode switchEncoding,
1257+
@Cached @Shared TruffleString.ToJavaStringNode toJavaString) {
12551258
if (interop.isString(source)) {
1256-
try {
1257-
return indirectEvalString(interop.asTruffleString(source));
1258-
} catch (UnsupportedMessageException ex) {
1259-
throw Errors.createTypeErrorInteropException(source, ex, "asString", this);
1260-
}
1259+
return indirectEvalString(Strings.interopAsTruffleString(source, interop, switchEncoding), toJavaString);
12611260
} else {
12621261
return source;
12631262
}
@@ -1311,7 +1310,7 @@ protected BigInt indirectEvalBigInt(BigInt source) {
13111310
return source;
13121311
}
13131312

1314-
@Specialization(guards = "isJSDynamicObject(object)")
1313+
@Specialization
13151314
public JSDynamicObject indirectEvalJSType(JSDynamicObject object) {
13161315
return object;
13171316
}
@@ -1715,7 +1714,7 @@ private void doImport(Object globalContextBindings) {
17151714
Object hashKey = membersInterop.readArrayElement(members, i);
17161715
InteropLibrary keyInterop = InteropLibrary.getUncached(hashKey);
17171716
if (keyInterop.isString(hashKey)) {
1718-
TruffleString stringKey = keyInterop.asTruffleString(hashKey);
1717+
TruffleString stringKey = Strings.interopAsTruffleString(hashKey, keyInterop);
17191718
Object value = DynamicObjectLibrary.getUncached().getOrDefault(globalObject, stringKey, Undefined.instance);
17201719
if ((value == Undefined.instance || value instanceof ScriptEngineGlobalScopeBindingsPropertyProxy &&
17211720
((ScriptEngineGlobalScopeBindingsPropertyProxy) value).get(globalObject) == Undefined.instance) &&

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JavaBuiltins.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,11 +301,11 @@ abstract static class JavaTypeNameNode extends JSBuiltinNode {
301301
}
302302

303303
@Specialization(guards = "isJavaInteropClass(type, typeInterop)")
304-
protected TruffleString typeNameJavaInteropClass(Object type,
304+
protected Object typeNameJavaInteropClass(Object type,
305305
@CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary typeInterop,
306-
@CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary stringInterop) {
306+
@Cached ImportValueNode importValue) {
307307
try {
308-
return stringInterop.asTruffleString(typeInterop.getMetaQualifiedName(type));
308+
return importValue.executeWithTarget(typeInterop.getMetaQualifiedName(type));
309309
} catch (UnsupportedMessageException e) {
310310
throw Errors.createTypeErrorInteropException(type, e, "Java.typeName", this);
311311
}

0 commit comments

Comments
 (0)