/*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
if (edgesUseStructure(graph, node))
read(JSCell_structureID);
+ // We allow the runtime to perform a stack scan at any time. We don't model which nodes get implemented
+ // by calls into the runtime. For debugging we might replace the implementation of any node with a call
+ // to the runtime, and that call may walk stack. Therefore, each node must read() anything that a stack
+ // scan would read. That's what this does.
+ for (InlineCallFrame* inlineCallFrame = node->origin.semantic.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame) {
+ if (inlineCallFrame->isClosureCall)
+ read(AbstractHeap(Stack, inlineCallFrame->stackOffset + JSStack::Callee));
+ if (inlineCallFrame->isVarargs())
+ read(AbstractHeap(Stack, inlineCallFrame->stackOffset + JSStack::ArgumentCount));
+ }
+
switch (node->op()) {
case JSConstant:
case DoubleConstant:
case Int52Constant:
def(PureValue(node, node->constant()));
return;
-
+
case Identity:
case Phantom:
case Check:
case CheckStructureImmediate:
return;
- case BitAnd:
- case BitOr:
- case BitXor:
- case BitLShift:
- case BitRShift:
- case BitURShift:
+ case LazyJSConstant:
+ // We should enable CSE of LazyJSConstant. It's a little annoying since LazyJSValue has
+ // more bits than we currently have in PureValue.
+ return;
+
case ArithIMul:
case ArithAbs:
case ArithClz32:
case ArithLog:
case GetScope:
case SkipScope:
+ case GetGlobalObject:
case StringCharCodeAt:
- case StringFromCharCode:
- case CompareEqConstant:
case CompareStrictEq:
+ case IsJSArray:
+ case IsArrayConstructor:
+ case IsEmpty:
case IsUndefined:
case IsBoolean:
case IsNumber:
case IsString:
case IsObject:
+ case IsRegExpObject:
case LogicalNot:
case CheckInBounds:
case DoubleRep:
case BooleanToNumber:
case FiatInt52:
case MakeRope:
+ case StrCat:
case ValueToInt32:
case GetExecutable:
case BottomValue:
case TypeOf:
def(PureValue(node));
return;
-
+
+ case BitAnd:
+ case BitOr:
+ case BitXor:
+ case BitLShift:
+ case BitRShift:
+ case BitURShift:
+ if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
+ read(World);
+ write(Heap);
+ return;
+ }
+ def(PureValue(node));
+ return;
+
+ case ArithRandom:
+ read(MathDotRandomState);
+ write(MathDotRandomState);
+ return;
+
+ case IsArrayObject:
case HasGenericProperty:
case HasStructureProperty:
case GetEnumerableLength:
return;
}
+ case StringFromCharCode:
+ switch (node->child1().useKind()) {
+ case Int32Use:
+ def(PureValue(node));
+ return;
+ case UntypedUse:
+ read(World);
+ write(Heap);
+ return;
+ default:
+ DFG_CRASH(graph, node, "Bad use kind");
+ }
+ return;
+
case ArithAdd:
- case ArithSub:
case ArithNegate:
- case ArithMul:
- case ArithDiv:
case ArithMod:
case DoubleAsInt32:
case UInt32ToNumber:
def(PureValue(node, node->arithMode()));
return;
+ case ArithDiv:
+ case ArithMul:
+ case ArithSub:
+ switch (node->binaryUseKind()) {
+ case Int32Use:
+ case Int52RepUse:
+ case DoubleRepUse:
+ def(PureValue(node, node->arithMode()));
+ return;
+ case UntypedUse:
+ read(World);
+ write(Heap);
+ return;
+ default:
+ DFG_CRASH(graph, node, "Bad use kind");
+ }
+
case ArithRound:
+ case ArithFloor:
+ case ArithCeil:
+ case ArithTrunc:
def(PureValue(node, static_cast<uintptr_t>(node->arithRoundingMode())));
return;
case MovHint:
case ZombieHint:
+ case ExitOK:
case KillStack:
case Upsilon:
case Phi:
case CheckTierUpInLoop:
case CheckTierUpAtReturn:
case CheckTierUpAndOSREnter:
- case CheckTierUpWithNestedTriggerAndOSREnter:
case LoopHint:
- case Breakpoint:
case ProfileWillCall:
case ProfileDidCall:
case ProfileType:
write(HeapObjectCount);
return;
+ case CallObjectConstructor:
case ToThis:
case CreateThis:
read(MiscFields);
case GetById:
case GetByIdFlush:
+ case GetByIdWithThis:
+ case GetByValWithThis:
case PutById:
+ case PutByIdWithThis:
+ case PutByValWithThis:
case PutByIdFlush:
case PutByIdDirect:
+ case PutGetterById:
+ case PutSetterById:
+ case PutGetterSetterById:
+ case PutGetterByVal:
+ case PutSetterByVal:
+ case DeleteById:
+ case DeleteByVal:
case ArrayPush:
case ArrayPop:
case Call:
+ case TailCallInlinedCaller:
case Construct:
case CallVarargs:
case CallForwardVarargs:
+ case TailCallVarargsInlinedCaller:
+ case TailCallForwardVarargsInlinedCaller:
case ConstructVarargs:
case ConstructForwardVarargs:
case ToPrimitive:
case In:
case ValueAdd:
+ case SetFunctionName:
+ case GetDynamicVar:
+ case PutDynamicVar:
+ case ResolveScope:
read(World);
write(Heap);
return;
+
+ case TailCall:
+ case TailCallVarargs:
+ case TailCallForwardVarargs:
+ read(World);
+ write(SideState);
+ return;
case GetGetter:
read(GetterSetter_getter);
read(AbstractHeap(Stack, JSStack::ArgumentCount));
def(HeapLocation(StackPayloadLoc, AbstractHeap(Stack, JSStack::ArgumentCount)), LazyNode(node));
return;
+
+ case GetRestLength:
+ read(Stack);
+ return;
case GetLocal:
read(AbstractHeap(Stack, node->local()));
read(MiscFields);
def(HeapLocation(IndexedPropertyLoc, TypedArrayProperties, node->child1(), node->child2()), LazyNode(node));
return;
+ // We should not get an AnyTypedArray in a GetByVal as AnyTypedArray is only created from intrinsics, which
+ // are only added from Inline Caching a GetById.
+ case Array::AnyTypedArray:
+ DFG_CRASH(graph, node, "impossible array mode for get");
+ return;
}
RELEASE_ASSERT_NOT_REACHED();
return;
}
- case GetMyArgumentByVal: {
+ case GetMyArgumentByVal:
+ case GetMyArgumentByValOutOfBounds: {
read(Stack);
// FIXME: It would be trivial to have a def here.
// https://bugs.webkit.org/show_bug.cgi?id=143077
// FIXME: We can't def() anything here because these operations truncate their inputs.
// https://bugs.webkit.org/show_bug.cgi?id=134737
return;
+ case Array::AnyTypedArray:
case Array::String:
case Array::DirectArguments:
case Array::ScopedArguments:
read(JSCell_structureID);
return;
- case CheckHasInstance:
+ case CheckTypeInfoFlags:
read(JSCell_typeInfoFlags);
- def(HeapLocation(CheckHasInstanceLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
+ def(HeapLocation(CheckTypeInfoFlagsLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
+ return;
+
+ case OverridesHasInstance:
+ read(JSCell_typeInfoFlags);
+ def(HeapLocation(OverridesHasInstanceLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
return;
case InstanceOf:
def(HeapLocation(InstanceOfLoc, JSCell_structureID, node->child1(), node->child2()), LazyNode(node));
return;
+ case InstanceOfCustom:
+ read(World);
+ write(Heap);
+ return;
+
case PutStructure:
write(JSCell_structureID);
write(JSCell_typeInfoType);
read(JSObject_butterfly);
def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
return;
-
+
case Arrayify:
case ArrayifyToStructure:
read(JSCell_structureID);
def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node));
return;
}
-
+
+ case TryGetById: {
+ read(Heap);
+ return;
+ }
+
case MultiGetByOffset: {
read(JSCell_structureID);
read(JSObject_butterfly);
case Array::String:
def(PureValue(node, mode.asWord()));
return;
-
+
case Array::DirectArguments:
case Array::ScopedArguments:
read(MiscFields);
def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
return;
-
+
default:
- ASSERT(mode.typedArrayType() != NotTypedArray);
+ ASSERT(mode.isSomeTypedArrayView());
read(MiscFields);
def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
return;
write(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node->child2().node()));
return;
+
+ case GetRegExpObjectLastIndex:
+ read(RegExpObject_lastIndex);
+ def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node));
+ return;
+
+ case SetRegExpObjectLastIndex:
+ write(RegExpObject_lastIndex);
+ def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node->child2().node()));
+ return;
+
+ case RecordRegExpCachedResult:
+ write(RegExpState);
+ return;
case GetFromArguments: {
AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
}
case GetGlobalVar:
+ case GetGlobalLexicalVariable:
read(AbstractHeap(Absolute, node->variablePointer()));
def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node));
return;
- case PutGlobalVar:
+ case PutGlobalVariable:
write(AbstractHeap(Absolute, node->variablePointer()));
def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node->child2().node()));
return;
if (operandIdx >= numElements)
continue;
Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
+ // operandIdx comes from graph.m_uint32ValuesInUse and thus is guaranteed to be already frozen
def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
LazyNode(use.node()));
}
LazyNode(graph.freeze(data[index]), op));
}
} else {
+ Vector<uint32_t> possibleIndices;
for (uint32_t index : graph.m_uint32ValuesInUse) {
if (index >= numElements)
continue;
+ possibleIndices.append(index);
+ }
+ for (uint32_t index : possibleIndices) {
def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
LazyNode(graph.freeze(data[index]), op));
}
return;
}
+ case CopyRest: {
+ read(Stack);
+ write(Heap);
+ return;
+ }
+
case NewObject:
case NewRegexp:
case NewStringObject:
case PhantomNewObject:
case MaterializeNewObject:
case PhantomNewFunction:
+ case PhantomNewGeneratorFunction:
case PhantomCreateActivation:
case MaterializeCreateActivation:
read(HeapObjectCount);
write(HeapObjectCount);
return;
-
+
case NewFunction:
+ case NewGeneratorFunction:
if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid())
write(Watchpoint_fire);
read(HeapObjectCount);
case RegExpExec:
case RegExpTest:
- read(RegExpState);
- write(RegExpState);
+ if (node->child2().useKind() == RegExpObjectUse
+ && node->child3().useKind() == StringUse) {
+ read(RegExpState);
+ read(RegExpObject_lastIndex);
+ write(RegExpState);
+ write(RegExpObject_lastIndex);
+ return;
+ }
+ read(World);
+ write(Heap);
+ return;
+
+ case StringReplace:
+ case StringReplaceRegExp:
+ if (node->child1().useKind() == StringUse
+ && node->child2().useKind() == RegExpObjectUse
+ && node->child3().useKind() == StringUse) {
+ read(RegExpState);
+ read(RegExpObject_lastIndex);
+ write(RegExpState);
+ write(RegExpObject_lastIndex);
+ return;
+ }
+ read(World);
+ write(Heap);
return;
case StringCharAt:
case CompareLessEq:
case CompareGreater:
case CompareGreaterEq:
+ if (node->isBinaryUseKind(StringUse)) {
+ read(HeapObjectCount);
+ write(HeapObjectCount);
+ return;
+ }
if (!node->isBinaryUseKind(UntypedUse)) {
def(PureValue(node));
return;
case ThrowReferenceError:
write(SideState);
- read(HeapObjectCount);
- write(HeapObjectCount);
return;
case CountExecution:
write(InternalState);
return;
+ case LogShadowChickenPrologue:
+ case LogShadowChickenTail:
+ write(SideState);
+ return;
+
case LastNodeType:
RELEASE_ASSERT_NOT_REACHED();
return;