Constructor returning null should construct an object instead of null
https://bugs.webkit.org/show_bug.cgi?id=141640
Reviewed by Geoffrey Garen.
Source/JavaScriptCore:
When constructor code doesn't return object, constructor should return this
object instead.
Since we used op_is_object
for this check and op_is_object
is intended to be used for typeof
,
it allows null
as an object.
This patch fixes it by introducing an new bytecode op_is_object_or_null
for typeof
use cases.
Instead, constructor uses simplified is_object
.
As a result, op_is_object
becomes fairly simple. So we introduce optimization for op_is_object
.
- LLInt and baseline JIT support
op_is_object
as a fast path.
- DFG abstract interpreter support
op_is_object
. And recognize its speculated type and read-write effects.
- DFG introduces inlined asm for
op_is_object
rather than calling a C++ function.
- FTL lowers DFG's IsObject into LLVM IR.
And at the same time, this patch fixes isString / isObject predicate used for op_is_object
and others
in LLInt, JIT, DFG and FTL.
Before introducing ES6 Symbol, JSCell is only used for object and string in user observable area.
So in many places, when the cell is not object, we recognize it as a string, and vice versa.
However, now ES6 Symbol is implemented as a JSCell, this assumption is broken.
So this patch stop using !isString as isObject.
To check whether a cell is an object, instead of seeing that structure ID of a cell is not stringStructure,
we examine typeInfo in JSCell.
- JavaScriptCore.order:
- bytecode/BytecodeList.json:
- bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
(JSC::CodeBlock::dumpBytecode):
- bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFor):
- bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitEqualityOp):
(JSC::BytecodeGenerator::emitReturn):
- dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
- dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::capabilityLevel):
(JSC::DFG::clobberize):
IsObject operation only touches JSCell typeInfoType.
And this value would not be changed through structure transition.
As a result, IsObject can report that it doesn't read any information.
(JSC::DFG::doesGC):
(JSC::DFG::FixupPhase::fixupNode):
Just like IsString, IsObject is also fixed up.
(WTF::printInternal):
- dfg/DFGHeapLocation.h:
- dfg/DFGNodeType.h:
- dfg/DFGOperations.cpp:
- dfg/DFGOperations.h:
- dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::safeToExecute):
- dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality):
(JSC::DFG::SpeculativeJIT::compileStringToUntypedEquality):
(JSC::DFG::SpeculativeJIT::compileStringIdentToNotStringVarEquality):
(JSC::DFG::SpeculativeJIT::compileToStringOnCell):
(JSC::DFG::SpeculativeJIT::speculateObject):
(JSC::DFG::SpeculativeJIT::speculateObjectOrOther):
(JSC::DFG::SpeculativeJIT::speculateString):
(JSC::DFG::SpeculativeJIT::speculateNotStringVar):
(JSC::DFG::SpeculativeJIT::emitSwitchChar):
(JSC::DFG::SpeculativeJIT::emitSwitchString):
(JSC::DFG::SpeculativeJIT::branchIsObject):
(JSC::DFG::SpeculativeJIT::branchNotObject):
(JSC::DFG::SpeculativeJIT::branchIsString):
(JSC::DFG::SpeculativeJIT::branchNotString):
- dfg/DFGSpeculativeJIT.h:
- dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compile):
- dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::FTL::canCompile):
- ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileToString):
(JSC::FTL::LowerDFGToLLVM::compileIsObject):
(JSC::FTL::LowerDFGToLLVM::compileIsObjectOrNull):
(JSC::FTL::LowerDFGToLLVM::speculateTruthyObject):
(JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined):
(JSC::FTL::LowerDFGToLLVM::isObject):
(JSC::FTL::LowerDFGToLLVM::isNotObject):
(JSC::FTL::LowerDFGToLLVM::isNotString):
(JSC::FTL::LowerDFGToLLVM::speculateNonNullObject):
(JSC::JIT::privateCompileMainPass):
- jit/JIT.h:
- jit/JITInlines.h:
(JSC::JIT::emitJumpIfCellObject):
(JSC::JIT::emit_op_is_object):
(JSC::JIT::emit_op_to_primitive):
(JSC::JIT::emit_op_is_object):
(JSC::JIT::emit_op_to_primitive):
(JSC::JIT::compileOpStrictEq):
- llint/LowLevelInterpreter.asm:
- llint/LowLevelInterpreter32_64.asm:
- llint/LowLevelInterpreter64.asm:
- runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
- runtime/CommonSlowPaths.h:
- runtime/Operations.cpp:
(JSC::jsIsObjectTypeOrNull):
(JSC::jsIsObjectType): Deleted.
LayoutTests:
- js/dfg-to-primitive-pass-symbol-expected.txt: Added.
- js/dfg-to-primitive-pass-symbol.html: Added.
- js/dom/constructor-with-return-masquerades-expected.txt: Added.
- js/dom/constructor-with-return-masquerades.html: Added.
- js/dom/script-tests/constructor-with-return-masquerades.js: Added.
(Constructor):
Follow the old ret_object_or_this semantics.
When constructor returns an object that masquerades as undefined, we see it as an object.
- js/regress/constructor-with-return-expected.txt: Added.
- js/regress/constructor-with-return.html: Added.
- js/regress/script-tests/constructor-with-return.js: Added.
(Test):
When constructor doesn't return an object, this
should be returned instead.
In this test, we check all primitives. And test object, array and wrappers.
- js/script-tests/dfg-to-primitive-pass-symbol.js: Added.
(toPrimitiveTarget):
(doToPrimitive):
op_to_primitive operation passes Symbol in fast path.