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/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 7397930..8357c6f 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,155 @@
2015-02-24 Yusuke Suzuki <utatane.tea@gmail.com>
+ Constructor returning null should construct an object instead of null
+ https://bugs.webkit.org/show_bug.cgi?id=141640
+
+ Reviewed by Filip Pizlo.
+
+ 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.
+
+2015-02-24 Yusuke Suzuki <utatane.tea@gmail.com>
+
REGRESSION(r179429): Can't type comments in Facebook
https://bugs.webkit.org/show_bug.cgi?id=141859
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
diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.json b/Source/JavaScriptCore/bytecode/BytecodeList.json
index 5c1f0d8..804e8cd 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeList.json
+++ b/Source/JavaScriptCore/bytecode/BytecodeList.json
@@ -53,6 +53,7 @@
{ "name" : "op_is_number", "length" : 3 },
{ "name" : "op_is_string", "length" : 3 },
{ "name" : "op_is_object", "length" : 3 },
+ { "name" : "op_is_object_or_null", "length" : 3 },
{ "name" : "op_is_function", "length" : 3 },
{ "name" : "op_in", "length" : 4 },
{ "name" : "op_init_global_const_nop", "length" : 5 },
diff --git a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
index 78feb6c..92e58ca 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
@@ -133,6 +133,7 @@
case op_is_number:
case op_is_string:
case op_is_object:
+ case op_is_object_or_null:
case op_is_function:
case op_to_number:
case op_negate:
@@ -332,6 +333,7 @@
case op_is_number:
case op_is_string:
case op_is_object:
+ case op_is_object_or_null:
case op_is_function:
case op_in:
case op_to_number:
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index edd40a5..438dd3c 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -1008,6 +1008,10 @@
printUnaryOp(out, exec, location, it, "is_object");
break;
}
+ case op_is_object_or_null: {
+ printUnaryOp(out, exec, location, it, "is_object_or_null");
+ break;
+ }
case op_is_function: {
printUnaryOp(out, exec, location, it, "is_function");
break;
diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
index 4a82ba7..b7fe5a0 100644
--- a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
+++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
@@ -360,7 +360,7 @@
// If the structure corresponds to something that isn't an object, then give up, since
// we don't want to be adding properties to strings.
- if (structure->typeInfo().type() == StringType)
+ if (!structure->typeInfo().isObject())
return PutByIdStatus(TakesSlowPath);
RefPtr<IntendedStructureChain> chain;
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index e4770fe..abddfac 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -1096,7 +1096,7 @@
}
if (value == "object") {
rewindUnaryOp();
- emitOpcode(op_is_object);
+ emitOpcode(op_is_object_or_null);
instructions().append(dst->index());
instructions().append(srcIndex);
return dst;
@@ -1945,15 +1945,6 @@
instructions().append(isObjectRegister->index());
instructions().append(isObjectLabel->bind(begin, instructions().size()));
- emitOpcode(op_is_function);
- instructions().append(isObjectRegister->index());
- instructions().append(src->index());
-
- begin = instructions().size();
- emitOpcode(op_jtrue);
- instructions().append(isObjectRegister->index());
- instructions().append(isObjectLabel->bind(begin, instructions().size()));
-
emitUnaryNoDstOp(op_ret, &m_thisRegister);
emitLabel(isObjectLabel.get());
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 010876b..2bca9ae 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -800,6 +800,7 @@
case IsNumber:
case IsString:
case IsObject:
+ case IsObjectOrNull:
case IsFunction: {
JSValue child = forNode(node->child1()).value();
if (child) {
@@ -821,6 +822,9 @@
setConstant(node, jsBoolean(isJSString(child)));
break;
case IsObject:
+ setConstant(node, jsBoolean(child.isObject()));
+ break;
+ case IsObjectOrNull:
if (child.isNull() || !child.isObject()) {
setConstant(node, jsBoolean(child.isNull()));
break;
@@ -1178,7 +1182,7 @@
break;
}
- if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString))) {
+ if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecCellOther))) {
m_state.setFoundConstants(true);
forNode(node) = forNode(node->child1());
break;
@@ -1186,7 +1190,7 @@
clobberWorld(node->origin.semantic, clobberLimit);
- forNode(node).setType((SpecHeapTop & ~SpecCell) | SpecString);
+ forNode(node).setType((SpecHeapTop & ~SpecCell) | SpecString | SpecCellOther);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 27c58dd..1aa539b 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -2887,6 +2887,12 @@
NEXT_OPCODE(op_is_object);
}
+ case op_is_object_or_null: {
+ Node* value = get(VirtualRegister(currentInstruction[2].u.operand));
+ set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(IsObjectOrNull, value));
+ NEXT_OPCODE(op_is_object_or_null);
+ }
+
case op_is_function: {
Node* value = get(VirtualRegister(currentInstruction[2].u.operand));
set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(IsFunction, value));
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index ee4d4d1..edc2546 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -132,6 +132,7 @@
case op_is_number:
case op_is_string:
case op_is_object:
+ case op_is_object_or_null:
case op_is_function:
case op_not:
case op_less:
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index 723edaa..12dfe88 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -137,6 +137,7 @@
case IsBoolean:
case IsNumber:
case IsString:
+ case IsObject:
case LogicalNot:
case CheckInBounds:
case DoubleRep:
@@ -340,9 +341,9 @@
def(HeapLocation(AllocationProfileWatchpointLoc, MiscFields), node);
return;
- case IsObject:
+ case IsObjectOrNull:
read(MiscFields);
- def(HeapLocation(IsObjectLoc, MiscFields, node->child1()), node);
+ def(HeapLocation(IsObjectOrNullLoc, MiscFields, node->child1()), node);
return;
case IsFunction:
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index 31916d8..95afd22 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -369,7 +369,7 @@
}
case ToPrimitive: {
- if (m_state.forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString))
+ if (m_state.forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecCellOther))
break;
node->convertToIdentity();
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index b0b7896..c1a9135 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -135,6 +135,7 @@
case IsNumber:
case IsString:
case IsObject:
+ case IsObjectOrNull:
case IsFunction:
case TypeOf:
case LogicalNot:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 0c40677..e4675c2 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -1089,6 +1089,16 @@
}
break;
+ case IsObject:
+ if (node->child1()->shouldSpeculateObject()) {
+ m_insertionSet.insertNode(
+ m_indexInBlock, SpecNone, Phantom, node->origin,
+ Edge(node->child1().node(), ObjectUse));
+ m_graph.convertToConstant(node, jsBoolean(true));
+ observeUseKindOnNode<ObjectUse>(node);
+ }
+ break;
+
case GetEnumerableLength: {
fixEdge<CellUse>(node->child1());
break;
@@ -1230,7 +1240,7 @@
case IsUndefined:
case IsBoolean:
case IsNumber:
- case IsObject:
+ case IsObjectOrNull:
case IsFunction:
case CreateArguments:
case PhantomArguments:
diff --git a/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp b/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
index a20a8db..944a8a6 100644
--- a/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
+++ b/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
@@ -60,10 +60,10 @@
out.print("InvalidationPointLoc");
return;
- case IsObjectLoc:
- out.print("IsObjectLoc");
+ case IsObjectOrNullLoc:
+ out.print("IsObjectOrNullLoc");
return;
-
+
case IsFunctionLoc:
out.print("IsFunctionLoc");
return;
diff --git a/Source/JavaScriptCore/dfg/DFGHeapLocation.h b/Source/JavaScriptCore/dfg/DFGHeapLocation.h
index e217b59..568d30d 100644
--- a/Source/JavaScriptCore/dfg/DFGHeapLocation.h
+++ b/Source/JavaScriptCore/dfg/DFGHeapLocation.h
@@ -50,7 +50,7 @@
InstanceOfLoc,
InvalidationPointLoc,
IsFunctionLoc,
- IsObjectLoc,
+ IsObjectOrNullLoc,
MyArgumentByValLoc,
MyArgumentsLengthLoc,
NamedPropertyLoc,
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index e003137..7735841 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -250,6 +250,7 @@
macro(IsNumber, NodeResultBoolean) \
macro(IsString, NodeResultBoolean) \
macro(IsObject, NodeResultBoolean) \
+ macro(IsObjectOrNull, NodeResultBoolean) \
macro(IsFunction, NodeResultBoolean) \
macro(TypeOf, NodeResultJS) \
macro(LogicalNot, NodeResultBoolean) \
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 9c46fc9..dd5e71c 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -808,9 +808,9 @@
return JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), scope);
}
-size_t JIT_OPERATION operationIsObject(ExecState* exec, EncodedJSValue value)
+size_t JIT_OPERATION operationIsObjectOrNull(ExecState* exec, EncodedJSValue value)
{
- return jsIsObjectType(exec, JSValue::decode(value));
+ return jsIsObjectTypeOrNull(exec, JSValue::decode(value));
}
size_t JIT_OPERATION operationIsFunction(EncodedJSValue value)
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 78574e1c..9fed98b 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -102,7 +102,7 @@
EncodedJSValue JIT_OPERATION operationGetArgumentByVal(ExecState*, int32_t, int32_t) WTF_INTERNAL;
JSCell* JIT_OPERATION operationNewFunctionNoCheck(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
double JIT_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL;
-size_t JIT_OPERATION operationIsObject(ExecState*, EncodedJSValue) WTF_INTERNAL;
+size_t JIT_OPERATION operationIsObjectOrNull(ExecState*, EncodedJSValue) WTF_INTERNAL;
size_t JIT_OPERATION operationIsFunction(EncodedJSValue) WTF_INTERNAL;
JSCell* JIT_OPERATION operationTypeOf(ExecState*, JSCell*) WTF_INTERNAL;
char* JIT_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState*) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 5a5cec5..9e3259d 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -358,6 +358,7 @@
case IsNumber:
case IsString:
case IsObject:
+ case IsObjectOrNull:
case IsFunction: {
changed |= setPrediction(SpecBoolean);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 9199e54..0da2ff2 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -210,6 +210,7 @@
case IsNumber:
case IsString:
case IsObject:
+ case IsObjectOrNull:
case IsFunction:
case TypeOf:
case LogicalNot:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 7478865..92e55cf 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -1157,33 +1157,17 @@
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
- m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), branchNotObject(op1GPR));
}
if (m_state.forNode(node->child2()).m_type & ~SpecObject) {
speculationCheck(
- BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
- m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), branchNotObject(op2GPR));
}
} else {
- GPRTemporary structure(this);
- GPRTemporary temp(this);
- GPRReg structureGPR = structure.gpr();
-
- m_jit.emitLoadStructure(op1GPR, structureGPR, temp.gpr());
if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
speculationCheck(
BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ branchNotObject(op1GPR));
}
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
m_jit.branchTest8(
@@ -1191,14 +1175,10 @@
MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
- m_jit.emitLoadStructure(op2GPR, structureGPR, temp.gpr());
if (m_state.forNode(node->child2()).m_type & ~SpecObject) {
speculationCheck(
BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ branchNotObject(op2GPR));
}
speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
m_jit.branchTest8(
@@ -3963,10 +3943,7 @@
fastTrue.append(m_jit.branchPtr(
MacroAssembler::Equal, leftGPR, rightRegs.payloadGPR()));
- fastFalse.append(m_jit.branchStructurePtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(rightRegs.payloadGPR(), JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ fastFalse.append(branchNotString(rightRegs.payloadGPR()));
compileStringEquality(
node, leftGPR, rightRegs.payloadGPR(), lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR,
@@ -4014,10 +3991,7 @@
moveFalseTo(rightTempGPR);
JITCompiler::JumpList notString;
notString.append(branchNotCell(rightRegs));
- notString.append(m_jit.branchStructurePtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(rightRegs.payloadGPR(), JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ notString.append(branchNotString(rightRegs.payloadGPR()));
speculateStringIdentAndLoadStorage(notStringVarEdge, rightRegs.payloadGPR(), rightTempGPR);
@@ -4460,10 +4434,10 @@
m_jit.load32(JITCompiler::Address(op1GPR, JSCell::structureIDOffset()), resultGPR);
JITCompiler::Jump isString = m_jit.branchStructurePtr(
- JITCompiler::Equal,
+ JITCompiler::Equal,
resultGPR,
m_jit.vm()->stringStructure.get());
-
+
speculateStringObjectForStructure(node->child1(), resultGPR);
m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR);
@@ -4489,10 +4463,7 @@
flushRegisters();
JITCompiler::Jump done;
if (node->child1()->prediction() & SpecString) {
- JITCompiler::Jump needCall = m_jit.branchStructurePtr(
- JITCompiler::NotEqual,
- JITCompiler::Address(op1GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get());
+ JITCompiler::Jump needCall = branchNotString(op1GPR);
m_jit.move(op1GPR, resultGPR);
done = m_jit.jump();
needCall.link(&m_jit);
@@ -4716,10 +4687,7 @@
SpeculateCellOperand operand(this, edge);
GPRReg gpr = operand.gpr();
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(gpr), edge, SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(gpr, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueSource::unboxedCell(gpr), edge, SpecObject, branchNotObject(gpr));
}
void SpeculativeJIT::speculateFunction(Edge edge)
@@ -4751,10 +4719,7 @@
MacroAssembler::Jump notCell = branchNotCell(operand.jsValueRegs());
GPRReg gpr = operand.jsValueRegs().payloadGPR();
DFG_TYPE_CHECK(
- operand.jsValueRegs(), edge, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(gpr, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ operand.jsValueRegs(), edge, (~SpecCell) | SpecObject, branchNotObject(gpr));
MacroAssembler::Jump done = m_jit.jump();
notCell.link(&m_jit);
if (needsTypeCheck(edge, SpecCell | SpecOther)) {
@@ -4768,11 +4733,7 @@
void SpeculativeJIT::speculateString(Edge edge, GPRReg cell)
{
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(cell), edge, SpecString | ~SpecCell,
- m_jit.branchStructurePtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(cell, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueSource::unboxedCell(cell), edge, SpecString | ~SpecCell, branchNotString(cell));
}
void SpeculativeJIT::speculateStringIdentAndLoadStorage(Edge edge, GPRReg string, GPRReg storage)
@@ -4877,10 +4838,7 @@
JITCompiler::Jump notCell = branchNotCell(operand.jsValueRegs());
GPRReg cell = operand.jsValueRegs().payloadGPR();
- JITCompiler::Jump notString = m_jit.branchStructurePtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(cell, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get());
+ JITCompiler::Jump notString = branchNotString(cell);
speculateStringIdentAndLoadStorage(edge, cell, tempGPR);
@@ -5156,12 +5114,7 @@
addBranch(branchNotCell(op1Regs), data->fallThrough.block);
- addBranch(
- m_jit.branchStructurePtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(op1Regs.payloadGPR(), JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()),
- data->fallThrough.block);
+ addBranch(branchNotString(op1Regs.payloadGPR()), data->fallThrough.block);
emitSwitchCharStringJump(data, op1Regs.payloadGPR(), tempGPR);
noResult(node, UseChildrenCalledExplicitly);
@@ -5446,12 +5399,7 @@
addBranch(branchNotCell(op1Regs), data->fallThrough.block);
- addBranch(
- m_jit.branchStructurePtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(op1Regs.payloadGPR(), JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()),
- data->fallThrough.block);
+ addBranch(branchNotString(op1Regs.payloadGPR()), data->fallThrough.block);
emitSwitchStringOnString(data, op1Regs.payloadGPR());
noResult(node, UseChildrenCalledExplicitly);
@@ -5501,6 +5449,38 @@
}
}
+JITCompiler::Jump SpeculativeJIT::branchIsObject(GPRReg cellGPR)
+{
+ return m_jit.branch8(
+ MacroAssembler::AboveOrEqual,
+ MacroAssembler::Address(cellGPR, JSCell::typeInfoTypeOffset()),
+ MacroAssembler::TrustedImm32(ObjectType));
+}
+
+JITCompiler::Jump SpeculativeJIT::branchNotObject(GPRReg cellGPR)
+{
+ return m_jit.branch8(
+ MacroAssembler::Below,
+ MacroAssembler::Address(cellGPR, JSCell::typeInfoTypeOffset()),
+ MacroAssembler::TrustedImm32(ObjectType));
+}
+
+JITCompiler::Jump SpeculativeJIT::branchIsString(GPRReg cellGPR)
+{
+ return m_jit.branchStructurePtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(cellGPR, JSCell::structureIDOffset()),
+ m_jit.vm()->stringStructure.get());
+}
+
+JITCompiler::Jump SpeculativeJIT::branchNotString(GPRReg cellGPR)
+{
+ return m_jit.branchStructurePtr(
+ MacroAssembler::NotEqual,
+ MacroAssembler::Address(cellGPR, JSCell::structureIDOffset()),
+ m_jit.vm()->stringStructure.get());
+}
+
#if ENABLE(GGC)
void SpeculativeJIT::compileStoreBarrier(Node* node)
{
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index bfe6ae3..c63723d 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -2191,6 +2191,10 @@
JITCompiler::Jump branchNotCell(JSValueRegs);
JITCompiler::Jump branchIsOther(JSValueRegs, GPRReg tempGPR);
JITCompiler::Jump branchNotOther(JSValueRegs, GPRReg tempGPR);
+ JITCompiler::Jump branchIsObject(GPRReg cellGPR);
+ JITCompiler::Jump branchNotObject(GPRReg cellGPR);
+ JITCompiler::Jump branchIsString(GPRReg cellGPR);
+ JITCompiler::Jump branchNotString(GPRReg cellGPR);
void moveTrueTo(GPRReg);
void moveFalseTo(GPRReg);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 62b1836..0c679b1 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -1200,36 +1200,24 @@
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, branchNotObject(op1GPR));
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, branchNotObject(op2GPR));
} else {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
- speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
+ JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, branchNotObject(op1GPR));
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
m_jit.branchTest8(
MacroAssembler::NonZero,
- MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
+ MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
- speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
+ JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, branchNotObject(op2GPR));
+ speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
m_jit.branchTest8(
- MacroAssembler::NonZero,
- MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
}
@@ -1262,16 +1250,10 @@
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, branchNotObject(op1GPR));
} else {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, branchNotObject(op1GPR));
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1287,18 +1269,10 @@
// We know that within this branch, rightChild must be a cell.
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
- JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject, branchNotObject(op2PayloadGPR));
} else {
DFG_TYPE_CHECK(
- JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject, branchNotObject(op2PayloadGPR));
speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1355,16 +1329,10 @@
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, branchNotObject(op1GPR));
} else {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, branchNotObject(op1GPR));
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1380,17 +1348,11 @@
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ branchNotObject(op2PayloadGPR));
} else {
DFG_TYPE_CHECK(
JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ branchNotObject(op2PayloadGPR));
speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1474,19 +1436,11 @@
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ branchNotObject(valuePayloadGPR));
} else {
- m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), structureGPR);
-
DFG_TYPE_CHECK(
JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ branchNotObject(valuePayloadGPR));
MacroAssembler::Jump isNotMasqueradesAsUndefined =
m_jit.branchTest8(
@@ -1494,6 +1448,7 @@
MacroAssembler::Address(valuePayloadGPR, JSCell::typeInfoFlagsOffset()),
MacroAssembler::TrustedImm32(MasqueradesAsUndefined));
+ m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), structureGPR);
speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
m_jit.branchPtr(
MacroAssembler::Equal,
@@ -1603,25 +1558,18 @@
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
DFG_TYPE_CHECK(
JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ branchNotObject(valuePayloadGPR));
} else {
- m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), scratchGPR);
-
DFG_TYPE_CHECK(
JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- scratchGPR,
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ branchNotObject(valuePayloadGPR));
JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(
JITCompiler::Zero,
MacroAssembler::Address(valuePayloadGPR, JSCell::typeInfoFlagsOffset()),
TrustedImm32(MasqueradesAsUndefined));
+ m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), scratchGPR);
speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
m_jit.branchPtr(
MacroAssembler::Equal,
@@ -3165,7 +3113,7 @@
m_jit.move(op1PayloadGPR, resultPayloadGPR);
} else {
MacroAssembler::Jump alreadyPrimitive = branchNotCell(op1.jsValueRegs());
- MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1PayloadGPR, JSCell::structureIDOffset()), MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()));
+ MacroAssembler::Jump notPrimitive = branchIsObject(op1PayloadGPR);
alreadyPrimitive.link(&m_jit);
m_jit.move(op1TagGPR, resultTagGPR);
@@ -3195,10 +3143,7 @@
JITCompiler::Jump done;
if (node->child1()->prediction() & SpecString) {
JITCompiler::Jump slowPath1 = branchNotCell(op1.jsValueRegs());
- JITCompiler::Jump slowPath2 = m_jit.branchPtr(
- JITCompiler::NotEqual,
- JITCompiler::Address(op1PayloadGPR, JSCell::structureIDOffset()),
- TrustedImmPtr(m_jit.vm()->stringStructure.get()));
+ JITCompiler::Jump slowPath2 = branchNotString(op1PayloadGPR);
m_jit.move(op1PayloadGPR, resultGPR);
done = m_jit.jump();
slowPath1.link(&m_jit);
@@ -4207,12 +4152,32 @@
case IsObject: {
JSValueOperand value(this, node->child1());
+ GPRTemporary result(this, Reuse, value, TagWord);
+
+ JITCompiler::Jump isNotCell = branchNotCell(value.jsValueRegs());
+
+ m_jit.compare8(JITCompiler::AboveOrEqual,
+ JITCompiler::Address(value.payloadGPR(), JSCell::typeInfoTypeOffset()),
+ TrustedImm32(ObjectType),
+ result.gpr());
+ JITCompiler::Jump done = m_jit.jump();
+
+ isNotCell.link(&m_jit);
+ m_jit.move(TrustedImm32(0), result.gpr());
+
+ done.link(&m_jit);
+ booleanResult(result.gpr(), node);
+ break;
+ }
+
+ case IsObjectOrNull: {
+ JSValueOperand value(this, node->child1());
GPRReg valueTagGPR = value.tagGPR();
GPRReg valuePayloadGPR = value.payloadGPR();
GPRFlushedCallResult result(this);
GPRReg resultGPR = result.gpr();
flushRegisters();
- callOperation(operationIsObject, resultGPR, valueTagGPR, valuePayloadGPR);
+ callOperation(operationIsObjectOrNull, resultGPR, valueTagGPR, valuePayloadGPR);
booleanResult(result.gpr(), node);
break;
}
@@ -4247,10 +4212,7 @@
DFG_TYPE_CHECK(JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecCell, isNotCell);
if (!node->child1()->shouldSpeculateObject() || node->child1().useKind() == StringUse) {
- JITCompiler::Jump notString = m_jit.branch8(
- JITCompiler::NotEqual,
- JITCompiler::Address(payloadGPR, JSCell::typeInfoTypeOffset()),
- TrustedImm32(StringType));
+ JITCompiler::Jump notString = branchNotString(payloadGPR);
if (node->child1().useKind() == StringUse)
DFG_TYPE_CHECK(JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecString, notString);
m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.stringString()), resultGPR);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 3f18556..bfb83a1 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -1306,21 +1306,12 @@
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, branchNotObject(op1GPR));
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, branchNotObject(op2GPR));
} else {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, branchNotObject(op1GPR));
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1328,10 +1319,7 @@
MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, branchNotObject(op2GPR));
speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1364,16 +1352,10 @@
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, branchNotObject(op1GPR));
} else {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, branchNotObject(op1GPR));
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1388,16 +1370,10 @@
// We know that within this branch, rightChild must be a cell.
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
- JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, branchNotObject(op2GPR));
} else {
DFG_TYPE_CHECK(
- JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, branchNotObject(op2GPR));
speculationCheck(BadType, JSValueRegs(op2GPR), rightChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1454,16 +1430,10 @@
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, branchNotObject(op1GPR));
} else {
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, branchNotObject(op1GPR));
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1478,16 +1448,10 @@
// We know that within this branch, rightChild must be a cell.
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
- JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, branchNotObject(op2GPR));
} else {
DFG_TYPE_CHECK(
- JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, branchNotObject(op2GPR));
speculationCheck(BadType, JSValueRegs(op2GPR), rightChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1609,16 +1573,10 @@
MacroAssembler::Jump notCell = branchNotCell(JSValueRegs(valueGPR));
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
- JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(valueGPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, branchNotObject(valueGPR));
} else {
DFG_TYPE_CHECK(
- JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(valueGPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, branchNotObject(valueGPR));
MacroAssembler::Jump isNotMasqueradesAsUndefined =
m_jit.branchTest8(
@@ -1759,16 +1717,10 @@
MacroAssembler::Jump notCell = branchNotCell(JSValueRegs(valueGPR));
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
DFG_TYPE_CHECK(
- JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(valueGPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, branchNotObject(valueGPR));
} else {
DFG_TYPE_CHECK(
- JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(valueGPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
+ JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, branchNotObject(valueGPR));
JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(
JITCompiler::Zero,
@@ -3279,10 +3231,7 @@
op1.use();
MacroAssembler::Jump alreadyPrimitive = branchNotCell(JSValueRegs(op1GPR));
- MacroAssembler::Jump notPrimitive = m_jit.branchStructurePtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get());
+ MacroAssembler::Jump notPrimitive = branchIsObject(op1GPR);
alreadyPrimitive.link(&m_jit);
m_jit.move(op1GPR, resultGPR);
@@ -3307,10 +3256,7 @@
JITCompiler::Jump done;
if (node->child1()->prediction() & SpecString) {
JITCompiler::Jump slowPath1 = branchNotCell(JSValueRegs(op1GPR));
- JITCompiler::Jump slowPath2 = m_jit.branchStructurePtr(
- JITCompiler::NotEqual,
- JITCompiler::Address(op1GPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get());
+ JITCompiler::Jump slowPath2 = branchNotString(op1GPR);
m_jit.move(op1GPR, resultGPR);
done = m_jit.jump();
slowPath1.link(&m_jit);
@@ -4262,14 +4208,35 @@
jsValueResult(result.gpr(), node, DataFormatJSBoolean);
break;
}
-
+
case IsObject: {
JSValueOperand value(this, node->child1());
+ GPRTemporary result(this, Reuse, value);
+
+ JITCompiler::Jump isNotCell = branchNotCell(value.jsValueRegs());
+
+ m_jit.compare8(JITCompiler::AboveOrEqual,
+ JITCompiler::Address(value.gpr(), JSCell::typeInfoTypeOffset()),
+ TrustedImm32(ObjectType),
+ result.gpr());
+ m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+ JITCompiler::Jump done = m_jit.jump();
+
+ isNotCell.link(&m_jit);
+ m_jit.move(TrustedImm32(ValueFalse), result.gpr());
+
+ done.link(&m_jit);
+ jsValueResult(result.gpr(), node, DataFormatJSBoolean);
+ break;
+ }
+
+ case IsObjectOrNull: {
+ JSValueOperand value(this, node->child1());
GPRReg valueGPR = value.gpr();
GPRFlushedCallResult result(this);
GPRReg resultGPR = result.gpr();
flushRegisters();
- callOperation(operationIsObject, resultGPR, valueGPR);
+ callOperation(operationIsObjectOrNull, resultGPR, valueGPR);
m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
jsValueResult(result.gpr(), node, DataFormatJSBoolean);
break;
@@ -4303,10 +4270,7 @@
DFG_TYPE_CHECK(JSValueSource(valueGPR), node->child1(), SpecCell, isNotCell);
if (!node->child1()->shouldSpeculateObject() || node->child1().useKind() == StringUse) {
- JITCompiler::Jump notString = m_jit.branch8(
- JITCompiler::NotEqual,
- JITCompiler::Address(valueGPR, JSCell::typeInfoTypeOffset()),
- TrustedImm32(StringType));
+ JITCompiler::Jump notString = branchNotString(valueGPR);
if (node->child1().useKind() == StringUse)
DFG_TYPE_CHECK(JSValueSource(valueGPR), node->child1(), SpecString, notString);
m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.stringString()), resultGPR);
@@ -5078,7 +5042,7 @@
jumpToEnd.append(m_jit.branchTest64(MacroAssembler::NonZero, valueGPR, GPRInfo::tagTypeNumberRegister));
else if (cachedTypeLocation->m_lastSeenType == TypeString) {
MacroAssembler::Jump isNotCell = branchNotCell(JSValueRegs(valueGPR));
- jumpToEnd.append(m_jit.branch8(MacroAssembler::Equal, MacroAssembler::Address(valueGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType)));
+ jumpToEnd.append(branchIsString(valueGPR));
isNotCell.link(&m_jit);
}
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index b4313be..2ebec33 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -156,6 +156,7 @@
case IsNumber:
case IsString:
case IsObject:
+ case IsObjectOrNull:
case IsFunction:
case CheckHasInstance:
case InstanceOf:
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index 86c9f2c..bba2256 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -761,6 +761,9 @@
case IsObject:
compileIsObject();
break;
+ case IsObjectOrNull:
+ compileIsObjectOrNull();
+ break;
case IsFunction:
compileIsFunction();
break;
@@ -3096,9 +3099,7 @@
ValueFromBlock simpleResult = m_out.anchor(value);
LValue isStringPredicate;
if (m_node->child1()->prediction() & SpecString) {
- isStringPredicate = m_out.equal(
- m_out.load32(value, m_heaps.JSCell_structureID),
- m_out.constInt32(vm().stringStructure->id()));
+ isStringPredicate = isString(value);
} else
isStringPredicate = m_out.booleanFalse;
m_out.branch(isStringPredicate, unsure(continuation), unsure(notString));
@@ -4204,11 +4205,29 @@
m_out.appendTo(continuation, lastNext);
setBoolean(m_out.phi(m_out.boolean, notCellResult, cellResult));
}
-
+
void compileIsObject()
{
+ LValue value = lowJSValue(m_node->child1());
+
+ LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("IsObject cell case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsObject continuation"));
+
+ ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
+ m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation));
+
+ LBasicBlock lastNext = m_out.appendTo(isCellCase, continuation);
+ ValueFromBlock cellResult = m_out.anchor(isObject(value));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setBoolean(m_out.phi(m_out.boolean, notCellResult, cellResult));
+ }
+
+ void compileIsObjectOrNull()
+ {
LValue pointerResult = vmCall(
- m_out.operation(operationIsObject), m_callFrame, lowJSValue(m_node->child1()));
+ m_out.operation(operationIsObjectOrNull), m_callFrame, lowJSValue(m_node->child1()));
setBoolean(m_out.notNull(pointerResult));
}
@@ -5130,10 +5149,7 @@
return;
}
- LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
- FTL_TYPE_CHECK(
- jsValueValue(cell), edge, filter,
- m_out.equal(structureID, m_out.constInt32(vm().stringStructure->id())));
+ FTL_TYPE_CHECK(jsValueValue(cell), edge, filter, isNotObject(cell));
speculate(
BadType, jsValueValue(cell), edge.node(),
m_out.testNonZero8(
@@ -5443,10 +5459,7 @@
break;
case CellCaseSpeculatesObject:
FTL_TYPE_CHECK(
- jsValueValue(value), edge, (~SpecCell) | SpecObject,
- m_out.equal(
- m_out.load32(value, m_heaps.JSCell_structureID),
- m_out.constInt32(vm().stringStructure->id())));
+ jsValueValue(value), edge, (~SpecCell) | SpecObject, isNotObject(value));
break;
}
@@ -6272,16 +6285,25 @@
LValue isObject(LValue cell)
{
+ return m_out.aboveOrEqual(
+ m_out.load8(cell, m_heaps.JSCell_typeInfoType),
+ m_out.constInt8(ObjectType));
+ }
+
+ LValue isNotObject(LValue cell)
+ {
+ return m_out.below(
+ m_out.load8(cell, m_heaps.JSCell_typeInfoType),
+ m_out.constInt8(ObjectType));
+ }
+
+ LValue isNotString(LValue cell)
+ {
return m_out.notEqual(
m_out.load32(cell, m_heaps.JSCell_structureID),
m_out.constInt32(vm().stringStructure->id()));
}
- LValue isNotString(LValue cell)
- {
- return isObject(cell);
- }
-
LValue isString(LValue cell)
{
return m_out.equal(
@@ -6289,11 +6311,6 @@
m_out.constInt32(vm().stringStructure->id()));
}
- LValue isNotObject(LValue cell)
- {
- return isString(cell);
- }
-
LValue isArrayType(LValue cell, ArrayMode arrayMode)
{
switch (arrayMode.type()) {
@@ -6490,11 +6507,7 @@
void speculateNonNullObject(Edge edge, LValue cell)
{
- FTL_TYPE_CHECK(
- jsValueValue(cell), edge, SpecObject,
- m_out.equal(
- m_out.load32(cell, m_heaps.JSCell_structureID),
- m_out.constInt32(vm().stringStructure->id())));
+ FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecObject, isNotObject(cell));
if (masqueradesAsUndefinedWatchpointIsStillValid())
return;
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index 9abf94b..f4772fb 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -185,7 +185,7 @@
DEFINE_SLOW_OP(greater)
DEFINE_SLOW_OP(greatereq)
DEFINE_SLOW_OP(is_function)
- DEFINE_SLOW_OP(is_object)
+ DEFINE_SLOW_OP(is_object_or_null)
DEFINE_SLOW_OP(typeof)
DEFINE_OP(op_touch_entry)
@@ -225,6 +225,7 @@
DEFINE_OP(op_is_boolean)
DEFINE_OP(op_is_number)
DEFINE_OP(op_is_string)
+ DEFINE_OP(op_is_object)
DEFINE_OP(op_jeq_null)
DEFINE_OP(op_jfalse)
DEFINE_OP(op_jmp)
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index dd86d8e..16da554 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -307,6 +307,7 @@
void emitLoadDouble(int index, FPRegisterID value);
void emitLoadInt32ToDouble(int index, FPRegisterID value);
+ Jump emitJumpIfCellObject(RegisterID cellReg);
Jump emitJumpIfCellNotObject(RegisterID cellReg);
enum WriteBarrierMode { UnconditionalWriteBarrier, ShouldFilterBase, ShouldFilterValue, ShouldFilterBaseAndValue };
@@ -489,6 +490,7 @@
void emit_op_is_boolean(Instruction*);
void emit_op_is_number(Instruction*);
void emit_op_is_string(Instruction*);
+ void emit_op_is_object(Instruction*);
void emit_op_jeq_null(Instruction*);
void emit_op_jfalse(Instruction*);
void emit_op_jmp(Instruction*);
diff --git a/Source/JavaScriptCore/jit/JITInlines.h b/Source/JavaScriptCore/jit/JITInlines.h
index 79969a6..d616192 100644
--- a/Source/JavaScriptCore/jit/JITInlines.h
+++ b/Source/JavaScriptCore/jit/JITInlines.h
@@ -685,6 +685,11 @@
jump.linkTo(m_labels[m_bytecodeOffset + relativeOffset], this);
}
+ALWAYS_INLINE JIT::Jump JIT::emitJumpIfCellObject(RegisterID cellReg)
+{
+ return branch8(AboveOrEqual, Address(cellReg, JSCell::typeInfoTypeOffset()), TrustedImm32(ObjectType));
+}
+
ALWAYS_INLINE JIT::Jump JIT::emitJumpIfCellNotObject(RegisterID cellReg)
{
return branch8(Below, Address(cellReg, JSCell::typeInfoTypeOffset()), TrustedImm32(ObjectType));
diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp
index 583e529..00a20dc 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp
@@ -226,6 +226,25 @@
emitPutVirtualRegister(dst);
}
+void JIT::emit_op_is_object(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int value = currentInstruction[2].u.operand;
+
+ emitGetVirtualRegister(value, regT0);
+ Jump isNotCell = emitJumpIfNotJSCell(regT0);
+
+ compare8(AboveOrEqual, Address(regT0, JSCell::typeInfoTypeOffset()), TrustedImm32(ObjectType), regT0);
+ emitTagAsBoolImmediate(regT0);
+ Jump done = jump();
+
+ isNotCell.link(this);
+ move(TrustedImm32(ValueFalse), regT0);
+
+ done.link(this);
+ emitPutVirtualRegister(dst);
+}
+
void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction)
{
int arguments = currentInstruction[1].u.operand;
@@ -260,9 +279,7 @@
emitGetVirtualRegister(src, regT0);
Jump isImm = emitJumpIfNotJSCell(regT0);
- addSlowCase(branchStructure(NotEqual,
- Address(regT0, JSCell::structureIDOffset()),
- m_vm->stringStructure.get()));
+ addSlowCase(emitJumpIfCellObject(regT0));
isImm.link(this);
if (dst != src)
diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
index cc85349..b79df71 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -331,6 +331,24 @@
emitStoreBool(dst, regT0);
}
+void JIT::emit_op_is_object(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int value = currentInstruction[2].u.operand;
+
+ emitLoad(value, regT1, regT0);
+ Jump isNotCell = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
+
+ compare8(AboveOrEqual, Address(regT0, JSCell::typeInfoTypeOffset()), TrustedImm32(ObjectType), regT0);
+ Jump done = jump();
+
+ isNotCell.link(this);
+ move(TrustedImm32(0), regT0);
+
+ done.link(this);
+ emitStoreBool(dst, regT0);
+}
+
void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction)
{
VirtualRegister arguments = VirtualRegister(currentInstruction[1].u.operand);
@@ -351,7 +369,7 @@
emitLoad(src, regT1, regT0);
Jump isImm = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
- addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::structureIDOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
+ addSlowCase(emitJumpIfCellObject(regT0));
isImm.link(this);
if (dst != src)
@@ -624,12 +642,12 @@
addSlowCase(branch32(NotEqual, regT1, regT3));
addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
- // Jump to a slow case if both are strings.
+ // Jump to a slow case if both are strings or symbols (non object).
Jump notCell = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
- Jump firstNotString = branchPtr(NotEqual, Address(regT0, JSCell::structureIDOffset()), TrustedImmPtr(m_vm->stringStructure.get()));
- addSlowCase(branchPtr(Equal, Address(regT2, JSCell::structureIDOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
+ Jump firstIsObject = emitJumpIfCellObject(regT0);
+ addSlowCase(emitJumpIfCellNotObject(regT2));
notCell.link(this);
- firstNotString.link(this);
+ firstIsObject.link(this);
// Simply compare the payloads.
if (type == OpStrictEq)
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index 7681583d..d71a3ef 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -983,12 +983,11 @@
dispatch(3)
-_llint_op_is_object:
+_llint_op_is_object_or_null:
traceExecution()
- callSlowPath(_slow_path_is_object)
+ callSlowPath(_slow_path_is_object_or_null)
dispatch(3)
-
_llint_op_is_function:
traceExecution()
callSlowPath(_slow_path_is_function)
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
index 80a2551..63196c6 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -952,10 +952,10 @@
loadConstantOrVariable2Reg(t0, t2, t0)
bineq t2, t3, .slow
bib t2, LowestTag, .slow
- bineq t2, CellTag, .notString
- bbneq JSCell::m_type[t0], StringType, .notString
- bbeq JSCell::m_type[t1], StringType, .slow
-.notString:
+ bineq t2, CellTag, .notStringOrSymbol
+ bbaeq JSCell::m_type[t0], ObjectType, .notStringOrSymbol
+ bbb JSCell::m_type[t1], ObjectType, .slow
+.notStringOrSymbol:
loadi 4[PC], t2
equalityOperation(t0, t1, t0)
storei BooleanTag, TagOffset[cfr, t2, 8]
@@ -1333,6 +1333,21 @@
dispatch(3)
+_llint_op_is_object:
+ traceExecution()
+ loadi 8[PC], t1
+ loadi 4[PC], t2
+ loadConstantOrVariable(t1, t0, t3)
+ storei BooleanTag, TagOffset[cfr, t2, 8]
+ bineq t0, CellTag, .opIsObjectNotCell
+ cbaeq JSCell::m_type[t3], ObjectType, t1
+ storei t1, PayloadOffset[cfr, t2, 8]
+ dispatch(3)
+.opIsObjectNotCell:
+ storep 0, PayloadOffset[cfr, t2, 8]
+ dispatch(3)
+
+
macro loadPropertyAtVariableOffsetKnownNotInline(propertyOffset, objectAndStorage, tag, payload)
assert(macro (ok) bigteq propertyOffset, firstOutOfLineOffset, ok end)
negi propertyOffset
@@ -1976,7 +1991,7 @@
loadi 4[PC], t3
loadConstantOrVariable(t2, t1, t0)
bineq t1, CellTag, .opToPrimitiveIsImm
- bbneq JSCell::m_type[t0], StringType, .opToPrimitiveSlowCase
+ bbaeq JSCell::m_type[t0], ObjectType, .opToPrimitiveSlowCase
.opToPrimitiveIsImm:
storei t1, TagOffset[cfr, t3, 8]
storei t0, PayloadOffset[cfr, t3, 8]
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
index b862f93..f20a8e1 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
@@ -1206,6 +1206,21 @@
dispatch(3)
+_llint_op_is_object:
+ traceExecution()
+ loadisFromInstruction(2, t1)
+ loadisFromInstruction(1, t2)
+ loadConstantOrVariable(t1, t0)
+ btqnz t0, tagMask, .opIsObjectNotCell
+ cbaeq JSCell::m_type[t0], ObjectType, t1
+ orq ValueFalse, t1
+ storeq t1, [cfr, t2, 8]
+ dispatch(3)
+.opIsObjectNotCell:
+ storeq ValueFalse, [cfr, t2, 8]
+ dispatch(3)
+
+
macro loadPropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, value)
bilt propertyOffsetAsInt, firstOutOfLineOffset, .isInline
loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
@@ -1834,7 +1849,7 @@
loadisFromInstruction(1, t3)
loadConstantOrVariable(t2, t0)
btqnz t0, tagMask, .opToPrimitiveIsImm
- bbneq JSCell::m_type[t0], StringType, .opToPrimitiveSlowCase
+ bbaeq JSCell::m_type[t0], ObjectType, .opToPrimitiveSlowCase
.opToPrimitiveIsImm:
storeq t0, [cfr, t3, 8]
dispatch(3)
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
index dfb9412..727aa90 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
@@ -455,10 +455,10 @@
RETURN(jsTypeStringForValue(exec, OP_C(2).jsValue()));
}
-SLOW_PATH_DECL(slow_path_is_object)
+SLOW_PATH_DECL(slow_path_is_object_or_null)
{
BEGIN();
- RETURN(jsBoolean(jsIsObjectType(exec, OP_C(2).jsValue())));
+ RETURN(jsBoolean(jsIsObjectTypeOrNull(exec, OP_C(2).jsValue())));
}
SLOW_PATH_DECL(slow_path_is_function)
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
index bfe483d..70aad20 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
@@ -214,6 +214,7 @@
SLOW_PATH_HIDDEN_DECL(slow_path_bitxor);
SLOW_PATH_HIDDEN_DECL(slow_path_typeof);
SLOW_PATH_HIDDEN_DECL(slow_path_is_object);
+SLOW_PATH_HIDDEN_DECL(slow_path_is_object_or_null);
SLOW_PATH_HIDDEN_DECL(slow_path_is_function);
SLOW_PATH_HIDDEN_DECL(slow_path_in);
SLOW_PATH_HIDDEN_DECL(slow_path_del_by_val);
diff --git a/Source/JavaScriptCore/runtime/Operations.cpp b/Source/JavaScriptCore/runtime/Operations.cpp
index 0c9ccb6..5d6ad01 100644
--- a/Source/JavaScriptCore/runtime/Operations.cpp
+++ b/Source/JavaScriptCore/runtime/Operations.cpp
@@ -85,7 +85,7 @@
return jsTypeStringForValue(callFrame->vm(), callFrame->lexicalGlobalObject(), v);
}
-bool jsIsObjectType(CallFrame* callFrame, JSValue v)
+bool jsIsObjectTypeOrNull(CallFrame* callFrame, JSValue v)
{
if (!v.isCell())
return v.isNull();
diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h
index bb82cb6..ac47c8f 100644
--- a/Source/JavaScriptCore/runtime/Operations.h
+++ b/Source/JavaScriptCore/runtime/Operations.h
@@ -31,7 +31,7 @@
NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue);
JSValue jsTypeStringForValue(CallFrame*, JSValue);
JSValue jsTypeStringForValue(VM&, JSGlobalObject*, JSValue);
-bool jsIsObjectType(CallFrame*, JSValue);
+bool jsIsObjectTypeOrNull(CallFrame*, JSValue);
bool jsIsFunctionType(JSValue);
ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2)
diff --git a/Source/JavaScriptCore/tests/stress/constructor-with-return.js b/Source/JavaScriptCore/tests/stress/constructor-with-return.js
new file mode 100644
index 0000000..32a2892
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/constructor-with-return.js
@@ -0,0 +1,39 @@
+function Test(value, returnIt) {
+ this.value = value;
+ this.returnIt = returnIt;
+}
+
+var tests = [
+ new Test("string", false),
+ new Test(5, false),
+ new Test(6.5, false),
+ new Test(void(0), false),
+ new Test(null, false),
+ new Test(true, false),
+ new Test(false, false),
+ new Test(Symbol.iterator, false),
+ new Test({f:42}, true),
+ new Test([1, 2, 3], true),
+ new Test(new String("string"), true),
+ new Test(new Number(42), true),
+ new Test(new Boolean(false), true),
+ new Test(new Boolean(false), true),
+ new Test(Object(Symbol.iterator), true),
+];
+
+tests.forEach(function (test) {
+ function Constructor() {
+ return test.value;
+ }
+
+ var result = new Constructor();
+ if (test.returnIt) {
+ if (test.value !== result) {
+ throw "Bad result: " + result;
+ }
+ } else {
+ if (!(result instanceof Constructor)) {
+ throw "Bad result: " + result;
+ }
+ }
+});
diff --git a/Source/JavaScriptCore/tests/stress/dfg-to-primitive-pass-symbol.js b/Source/JavaScriptCore/tests/stress/dfg-to-primitive-pass-symbol.js
new file mode 100644
index 0000000..2a5ffa9
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/dfg-to-primitive-pass-symbol.js
@@ -0,0 +1,35 @@
+var shouldThrow = false;
+
+// str concat generates op_to_primitive.
+function toPrimitiveTarget() {
+ if (shouldThrow) {
+ return Symbol('Cocoa');
+ }
+ return 'Cocoa';
+}
+noInline(toPrimitiveTarget);
+
+function doToPrimitive() {
+ var value = toPrimitiveTarget();
+ return value + "Cappuccino" + value;
+}
+noInline(doToPrimitive);
+
+for (var i = 0; i < 10000; ++i) {
+ var result = doToPrimitive();
+ if (result !== "CocoaCappuccinoCocoa")
+ throw "Error: bad result: " + result;
+}
+
+shouldThrow = true;
+
+var didThrow;
+try {
+ shouldThrow = true;
+ doToPrimitive();
+} catch (e) {
+ didThrow = e;
+}
+
+if (String(didThrow) !== "TypeError: Type error")
+ throw "Error: didn't throw or threw wrong exception: " + didThrow;