Diff
Modified: trunk/JSTests/ChangeLog (266105 => 266106)
--- trunk/JSTests/ChangeLog 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/JSTests/ChangeLog 2020-08-25 07:45:00 UTC (rev 266106)
@@ -1,3 +1,13 @@
+2020-08-25 Alexey Shvayka <[email protected]>
+
+ Implementation of the class "extends" clause incorrectly uses __proto__ for setting prototypes
+ https://bugs.webkit.org/show_bug.cgi?id=205848
+
+ Reviewed by Keith Miller.
+
+ * microbenchmarks/class-derived-creation.js: Added.
+ * test262/expectations.yaml: Mark 4 test cases as passing.
+
2020-08-24 Keith Miller <[email protected]>
Update test262 (mid Aug 2020 edition)
Added: trunk/JSTests/microbenchmarks/class-derived-creation.js (0 => 266106)
--- trunk/JSTests/microbenchmarks/class-derived-creation.js (rev 0)
+++ trunk/JSTests/microbenchmarks/class-derived-creation.js 2020-08-25 07:45:00 UTC (rev 266106)
@@ -0,0 +1,6 @@
+class A {};
+for (var i = 0; i < 1e4; ++i) {
+ class B extends A {};
+ class C extends B {};
+ class D extends C {};
+}
Modified: trunk/JSTests/test262/expectations.yaml (266105 => 266106)
--- trunk/JSTests/test262/expectations.yaml 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/JSTests/test262/expectations.yaml 2020-08-25 07:45:00 UTC (rev 266106)
@@ -2155,9 +2155,6 @@
test/language/expressions/class/ident-name-method-def-with-escaped.js:
default: "SyntaxError: Unexpected escaped characters in keyword token: 'w\\u0069th'"
strict mode: "SyntaxError: Unexpected escaped characters in keyword token: 'w\\u0069th'"
-test/language/expressions/class/poisoned-underscore-proto.js:
- default: 'Test262Error: should not be called'
- strict mode: 'Test262Error: should not be called'
test/language/expressions/compound-assignment/S11.13.2_A5.10_T1.js:
default: "ReferenceError: Can't find variable: x"
test/language/expressions/compound-assignment/S11.13.2_A5.10_T2.js:
@@ -3049,9 +3046,6 @@
test/language/statements/class/ident-name-method-def-with-escaped.js:
default: "SyntaxError: Unexpected escaped characters in keyword token: 'w\\u0069th'"
strict mode: "SyntaxError: Unexpected escaped characters in keyword token: 'w\\u0069th'"
-test/language/statements/class/poisoned-underscore-proto.js:
- default: 'Test262Error: should not be called'
- strict mode: 'Test262Error: should not be called'
test/language/statements/class/subclass/builtin-objects/ArrayBuffer/regular-subclassing.js:
default: 'Test262Error: Expected true but got false'
strict mode: 'Test262Error: Expected true but got false'
Modified: trunk/Source/_javascript_Core/ChangeLog (266105 => 266106)
--- trunk/Source/_javascript_Core/ChangeLog 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-08-25 07:45:00 UTC (rev 266106)
@@ -1,3 +1,38 @@
+2020-08-25 Alexey Shvayka <[email protected]>
+
+ Implementation of the class "extends" clause incorrectly uses __proto__ for setting prototypes
+ https://bugs.webkit.org/show_bug.cgi?id=205848
+
+ Reviewed by Keith Miller.
+
+ To prevent `class extends` from breaking if Object.prototype.__proto__ is overridden
+ or removed, this patch replaces OpPutById bytecodes in ClassExprNode::emitBytecode()
+ with JSObject::setPrototypeDirect() invocations via OpCall.
+
+ Since the spec sets [[Prototype]] values directly [1], we are safe to skip method
+ table lookups and cycle checks.
+
+ Although this approach adds 4 `mov` ops to emitted bytecode for `class extends` creation,
+ increasing instruction count to 35, I prefer it over introducing a slow path only op.
+ To avoid emitting 2 extra `mov` ops, globalFuncSetPrototypeDirect() uses thisRegister().
+
+ Aligns JSC with V8 and SpiderMonkey. Derived class creation microbenchmark is neutral.
+
+ [1]: https://tc39.es/ecma262/#sec-createbuiltinfunction (step 7)
+
+ * builtins/BuiltinNames.h:
+ * bytecode/BytecodeDumper.cpp:
+ (JSC::CodeBlockBytecodeDumper<Block>::dumpConstants): Fix typo.
+ * bytecode/LinkTimeConstant.h:
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::emitSetPrototypeOf):
+ * bytecompiler/BytecodeGenerator.h:
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::ClassExprNode::emitBytecode):
+ * parser/Nodes.h:
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::init):
+
2020-08-24 Keith Miller <[email protected]>
DFG should always run CFG Simplification after Constant Folding.
Modified: trunk/Source/_javascript_Core/builtins/BuiltinNames.h (266105 => 266106)
--- trunk/Source/_javascript_Core/builtins/BuiltinNames.h 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/Source/_javascript_Core/builtins/BuiltinNames.h 2020-08-25 07:45:00 UTC (rev 266106)
@@ -138,6 +138,7 @@
macro(setBucketHead) \
macro(setBucketNext) \
macro(setBucketKey) \
+ macro(setPrototypeDirect) \
macro(regExpBuiltinExec) \
macro(regExpMatchFast) \
macro(regExpProtoFlagsGetter) \
Modified: trunk/Source/_javascript_Core/bytecode/BytecodeDumper.cpp (266105 => 266106)
--- trunk/Source/_javascript_Core/bytecode/BytecodeDumper.cpp 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeDumper.cpp 2020-08-25 07:45:00 UTC (rev 266106)
@@ -149,7 +149,7 @@
sourceCodeRepresentationDescription = "";
break;
case SourceCodeRepresentation::LinkTimeConstant:
- sourceCodeRepresentationDescription = ": in source as linke-time-constant";
+ sourceCodeRepresentationDescription = ": in source as link-time-constant";
break;
}
this->m_out.printf(" k%u = %s%s\n", static_cast<unsigned>(i), toCString(constant.get()).data(), sourceCodeRepresentationDescription);
Modified: trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h (266105 => 266106)
--- trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h 2020-08-25 07:45:00 UTC (rev 266106)
@@ -43,6 +43,7 @@
v(setBucketHead, nullptr) \
v(setBucketNext, nullptr) \
v(setBucketKey, nullptr) \
+ v(setPrototypeDirect, nullptr) \
v(propertyIsEnumerable, nullptr) \
v(ownKeys, nullptr) \
v(enqueueJob, nullptr) \
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (266105 => 266106)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2020-08-25 07:45:00 UTC (rev 266106)
@@ -2692,6 +2692,18 @@
return dst;
}
+RegisterID* BytecodeGenerator::emitDirectSetPrototypeOf(RegisterID* dst, RegisterID* base, RegisterID* prototype, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+{
+ RefPtr<RegisterID> setPrototypeDirect = moveLinkTimeConstant(nullptr, LinkTimeConstant::setPrototypeDirect);
+
+ CallArguments args(*this, nullptr, 1);
+ move(args.thisRegister(), base);
+ move(args.argumentRegister(0), prototype);
+
+ emitCall(newTemporary(), setPrototypeDirect.get(), NoExpectedFunction, args, divot, divotStart, divotEnd, DebuggableCall::No);
+ return dst;
+}
+
RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
{
OpPutByVal::emit(this, base, property, value, ecmaMode());
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (266105 => 266106)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2020-08-25 07:45:00 UTC (rev 266106)
@@ -812,6 +812,7 @@
RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* thisValue, RegisterID* property);
RegisterID* emitGetPrototypeOf(RegisterID* dst, RegisterID* value);
+ RegisterID* emitDirectSetPrototypeOf(RegisterID* dst, RegisterID* base, RegisterID* prototype, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
RegisterID* emitPutByVal(RegisterID* base, RegisterID* thisValue, RegisterID* property, RegisterID* value);
RegisterID* emitDirectGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (266105 => 266106)
--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2020-08-25 07:45:00 UTC (rev 266106)
@@ -4908,9 +4908,9 @@
generator.emitThrowTypeError("The value of the superclass's prototype property is not an object or null."_s);
generator.emitLabel(protoParentIsObjectOrNullLabel.get());
- generator.emitDirectPutById(constructor.get(), generator.propertyNames().underscoreProto, superclass.get(), PropertyNode::Unknown);
+ generator.emitDirectSetPrototypeOf(tempRegister.get(), constructor.get(), superclass.get(), divot(), divotStart(), divotEnd());
generator.emitLabel(superclassIsNullLabel.get());
- generator.emitDirectPutById(prototype.get(), generator.propertyNames().underscoreProto, protoParent.get(), PropertyNode::Unknown);
+ generator.emitDirectSetPrototypeOf(tempRegister.get(), prototype.get(), protoParent.get(), divot(), divotStart(), divotEnd());
}
if (needsHomeObject)
Modified: trunk/Source/_javascript_Core/parser/Nodes.h (266105 => 266106)
--- trunk/Source/_javascript_Core/parser/Nodes.h 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/Source/_javascript_Core/parser/Nodes.h 2020-08-25 07:45:00 UTC (rev 266106)
@@ -2323,7 +2323,7 @@
Type m_type;
};
- class ClassExprNode final : public ExpressionNode, public VariableEnvironmentNode {
+ class ClassExprNode final : public ExpressionNode, public ThrowableExpressionData, public VariableEnvironmentNode {
JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ClassExprNode);
public:
ClassExprNode(const JSTokenLocation&, const Identifier&, const SourceCode& classSource,
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (266105 => 266106)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2020-08-25 07:45:00 UTC (rev 266106)
@@ -1231,6 +1231,9 @@
m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::sameValue)].initLater([] (const Initializer<JSCell>& init) {
init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 2, String(), objectConstructorIs, ObjectIsIntrinsic));
});
+ m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::setPrototypeDirect)].initLater([] (const Initializer<JSCell>& init) {
+ init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 2, String(), globalFuncSetPrototypeDirect));
+ });
// RegExp.prototype helpers.
m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::regExpCreate)].initLater([] (const Initializer<JSCell>& init) {
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp (266105 => 266106)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp 2020-08-25 07:45:00 UTC (rev 266106)
@@ -730,6 +730,19 @@
return JSValue::encode(jsUndefined());
}
+EncodedJSValue JSC_HOST_CALL globalFuncSetPrototypeDirect(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+
+ JSValue value = callFrame->uncheckedArgument(0);
+ ASSERT(value.isObject() || value.isNull());
+
+ JSObject* object = asObject(callFrame->thisValue());
+ object->setPrototypeDirect(vm, value);
+
+ return { };
+}
+
EncodedJSValue JSC_HOST_CALL globalFuncHostPromiseRejectionTracker(JSGlobalObject* globalObject, CallFrame* callFrame)
{
VM& vm = globalObject->vm();
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h (266105 => 266106)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h 2020-08-25 07:42:49 UTC (rev 266105)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h 2020-08-25 07:45:00 UTC (rev 266106)
@@ -51,6 +51,7 @@
EncodedJSValue JSC_HOST_CALL globalFuncMakeTypeError(JSGlobalObject*, CallFrame*);
EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(JSGlobalObject*, CallFrame*);
EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(JSGlobalObject*, CallFrame*);
+EncodedJSValue JSC_HOST_CALL globalFuncSetPrototypeDirect(JSGlobalObject*, CallFrame*);
EncodedJSValue JSC_HOST_CALL globalFuncHostPromiseRejectionTracker(JSGlobalObject*, CallFrame*);
EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(JSGlobalObject*, CallFrame*);
EncodedJSValue JSC_HOST_CALL globalFuncBuiltinDescribe(JSGlobalObject*, CallFrame*);