Constructor returning null should construct an object instead of null
https://bugs.webkit.org/show_bug.cgi?id=141640
Reviewed by Filip Pizlo.
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`.
1. LLInt and baseline JIT support `op_is_object` as a fast path.
2. DFG abstract interpreter support `op_is_object`. And recognize its speculated type and read-write effects.
3. DFG introduces inlined asm for `op_is_object` rather than calling a C++ function.
4. 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):
* bytecode/CodeBlock.cpp:
(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):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
IsObject operation only touches JSCell typeInfoType.
And this value would be changed through structure transition.
As a result, IsObject can report that it doesn't read any information.
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
Just like IsString, IsObject is also fixed up.
* dfg/DFGHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGHeapLocation.h:
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(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):
* ftl/FTLCapabilities.cpp:
(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):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITInlines.h:
(JSC::JIT::emitJumpIfCellObject):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_is_object):
(JSC::JIT::emit_op_to_primitive):
* jit/JITOpcodes32_64.cpp:
(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.
* runtime/Operations.h:
* tests/stress/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.
* tests/stress/dfg-to-primitive-pass-symbol.js: Added.
(toPrimitiveTarget):
(doToPrimitive):
op_to_primitive operation passes Symbol in fast path.
LayoutTests:
Follow the old ret_object_or_this semantics.
When constructor returns an object that masquerades as undefined, we see it as an object.
* 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):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@180587 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/JavaScriptCore.order b/Source/JavaScriptCore/JavaScriptCore.order
index 71ed89f..bfa72a9 100644
--- a/Source/JavaScriptCore/JavaScriptCore.order
+++ b/Source/JavaScriptCore/JavaScriptCore.order
@@ -1348,7 +1348,6 @@
__ZN3JSC11PostfixNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC11PostfixNode11emitResolveERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC17BytecodeGenerator7emitIncEPNS_10RegisterIDE
-__ZN3JSC14jsIsObjectTypeEPNS_9ExecStateENS_7JSValueE
__ZN3JSC6JSCell11getCallDataEPS0_RNS_8CallDataE
__ZN3JSC8JSObject16getPropertyNamesEPS0_PNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
__ZN3JSC8JSObject19getOwnPropertyNamesEPS0_PNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
@@ -1665,7 +1664,7 @@
__ZN3JSCL8getByValEPNS_9ExecStateENS_7JSValueES2_NS_16ReturnAddressPtrE
_cti_op_stricteq
_cti_op_jtrue
-_cti_op_is_object
+_cti_op_is_object_or_null
__ZN3JSC8JSString12toThisObjectEPNS_6JSCellEPNS_9ExecStateE
__ZN3JSC12StringObjectC1ERNS_2VMEPNS_9StructureE
__ZNK3JSC6JSCell11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
@@ -2963,7 +2962,6 @@
__ZN3WTF6VectorIPN3JSC8JSObjectELm4ENS_15CrashOnOverflowEE15reserveCapacityEm
__ZN3WTF15BinarySemaphore4waitEd
__ZN3WTF15BinarySemaphore6signalEv
-_JSValueIsObject
__ZN3JSCL19arrayProtoFuncShiftEPNS_9ExecStateE
__ZN3JSC5shiftILNS_7JSArray14ShiftCountModeE0EEEvPNS_9ExecStateEPNS_8JSObjectEjjjj
__ZN3JSC7JSArray26shiftCountWithArrayStorageEjjPNS_12ArrayStorageE
@@ -3390,7 +3388,6 @@
__ZN3JSC8JSObject20ensureContiguousSlowERNS_2VME
__ZN3JSC8JSObject20ensureContiguousSlowERNS_2VMENS0_22DoubleToContiguousModeE
_operationMakeRope3
-_operationIsObject
__ZN3JSC3DFG12slowPathCallINS_22AbstractMacroAssemblerINS_12X86AssemblerEE4JumpEPFxPNS_9ExecStateExPNS_7JSArrayEENS0_11NoResultTagENS_12X86Registers10RegisterIDESE_SE_EEN3WTF10PassOwnPtrINS0_17SlowPathGeneratorEEET_PNS0_14SpeculativeJITET0_T1_T2_T3_T4_NS0_18SpillRegistersModeE
__ZN3JSC3DFG14SpeculativeJIT13callOperationEPFxPNS_9ExecStateExPNS_7JSArrayEENS_12X86Registers10RegisterIDES9_S9_
_operationArrayPush
@@ -4897,7 +4894,7 @@
_llint_slow_path_check_has_instance
_llint_slow_path_instanceof
_llint_slow_path_typeof
-_llint_slow_path_is_object
+_llint_slow_path_is_object_or_null
_llint_slow_path_is_function
_llint_slow_path_in
_llint_slow_path_resolve
@@ -5035,7 +5032,7 @@
_llint_op_greatereq
_llint_op_mod
_llint_op_typeof
-_llint_op_is_object
+_llint_op_is_object_or_null
_llint_op_is_function
_llint_op_in
_llint_op_put_to_base_variable