@Override public boolean containsKey(Object key) { for (HashNode<V> node : array) { if (node.getCode() == key.hashCode()) return true; } return false; }
private void updateModel(int index) { byte c = buf[index]; if (index > 0) { HashNode hNode = new HashNode(); byte prevC = buf[index - 1]; int pos = ((prevC & 0xff) << 8) | (c & 0xff); hNode.index = index - 1; hNode.next = hashTable[pos]; hashTable[pos] = hNode; } }
@Override public V get(Object key) { int code = key.hashCode(); int index = calculateHash(code); HashNode<V> arrayNode = array[index]; while (arrayNode != null && arrayNode.getCode() != code) { arrayNode = arrayNode.getNext(); } if (arrayNode == null) return null; else return arrayNode.getObject(); }
public void serialize(SerializerOutput out, HashNode obj) throws IOException { if (obj.getClass() == HashBucket.class) { out.write(Serialization.HTREE_BUCKET); HashBucket b = (HashBucket) obj; b.writeExternal(out); } else { out.write(Serialization.HTREE_DIRECTORY); HashDirectory n = (HashDirectory) obj; n.writeExternal(out); } }
@Specialization(guards = {"isNullHash(hash)", "!isRubyString(key)"}) public Object setNull( VirtualFrame frame, DynamicObject hash, Object key, Object value, boolean byIdentity) { HashNodes.setStore( hash, PackedArrayStrategy.createStore(hashNode.hash(frame, key), key, value), 1, null, null); assert HashNodes.verifyStore(hash); return value; }
@ExplodeLoop @Specialization(guards = {"isPackedHash(hash)", "!isRubyString(key)"}) public Object setPackedArray( VirtualFrame frame, DynamicObject hash, Object key, Object value, boolean byIdentity) { assert HashNodes.verifyStore(hash); final int hashed = hashNode.hash(frame, key); final Object[] store = (Object[]) Layouts.HASH.getStore(hash); final int size = Layouts.HASH.getSize(hash); for (int n = 0; n < PackedArrayStrategy.MAX_ENTRIES; n++) { if (n < size) { if (hashed == PackedArrayStrategy.getHashed(store, n)) { final boolean equal; if (byIdentityProfile.profile(byIdentity)) { equal = equalNode.executeReferenceEqual(frame, key, PackedArrayStrategy.getKey(store, n)); } else { equal = eqlNode.callBoolean(frame, key, "eql?", null, PackedArrayStrategy.getKey(store, n)); } if (equal) { PackedArrayStrategy.setValue(store, n, value); assert HashNodes.verifyStore(hash); return value; } } } } extendProfile.enter(); if (strategyProfile.profile(size + 1 <= PackedArrayStrategy.MAX_ENTRIES)) { PackedArrayStrategy.setHashedKeyValue(store, size, hashed, key, value); Layouts.HASH.setSize(hash, size + 1); return value; } else { PackedArrayStrategy.promoteToBuckets(hash, store, size); BucketsStrategy.addNewEntry(hash, hashed, key, value); } assert HashNodes.verifyStore(hash); return value; }
@ExplodeLoop @Override public Object execute(VirtualFrame frame) { final Object[] store = PackedArrayStrategy.createStore(); int size = 0; initializers: for (int n = 0; n < keyValues.length / 2; n++) { Object key = keyValues[n * 2].execute(frame); if (stringKeyProfile.profile(RubyGuards.isRubyString(key))) { if (isFrozenNode == null) { CompilerDirectives.transferToInterpreter(); isFrozenNode = insert(IsFrozenNodeGen.create(getContext(), getSourceSection(), null)); } if (!isFrozenNode.executeIsFrozen(key)) { key = freezeNode.call(frame, dupNode.call(frame, key, "dup", null), "freeze", null); } } final int hashed = hashNode.hash(frame, key); final Object value = keyValues[n * 2 + 1].execute(frame); for (int i = 0; i < n; i++) { if (i < size && hashed == PackedArrayStrategy.getHashed(store, i) && equalNode.callBoolean( frame, key, "eql?", null, PackedArrayStrategy.getKey(store, i))) { PackedArrayStrategy.setKey(store, i, key); PackedArrayStrategy.setValue(store, i, value); continue initializers; } } PackedArrayStrategy.setHashedKeyValue(store, size, hashed, key, value); size++; } return HashNodes.createHash(getContext().getCoreLibrary().getHashClass(), store, size); }
@Override public V put(K key, V value) { HashNode<V> hashNode = new HashNode<V>(key.hashCode(), value); int index = calculateHash(hashNode.getCode()); if (array[index] == null) array[index] = hashNode; else { HashNode<V> arrayNode = array[index]; while (arrayNode.getNext() != null) { arrayNode = arrayNode.getNext(); } arrayNode.setNext(hashNode); } return value; }
public void inspect(Node node) { if (RubyInstanceConfig.FULL_TRACE_ENABLED) { disable(); // we still inspect since some nodes change state as a result (JRUBY-6836) } if (node == null) return; switch (node.getNodeType()) { case ALIASNODE: setFlag(node, METHOD); break; case ANDNODE: AndNode andNode = (AndNode) node; inspect(andNode.getFirstNode()); inspect(andNode.getSecondNode()); break; case ARGSCATNODE: ArgsCatNode argsCatNode = (ArgsCatNode) node; inspect(argsCatNode.getFirstNode()); inspect(argsCatNode.getSecondNode()); break; case ARGSPUSHNODE: ArgsPushNode argsPushNode = (ArgsPushNode) node; inspect(argsPushNode.getFirstNode()); inspect(argsPushNode.getSecondNode()); break; case ARGUMENTNODE: break; case ARRAYNODE: case BLOCKNODE: case DREGEXPNODE: case DSTRNODE: case DSYMBOLNODE: case DXSTRNODE: case LISTNODE: ListNode listNode = (ListNode) node; for (int i = 0; i < listNode.size(); i++) { inspect(listNode.get(i)); } break; case ARGSNODE: ArgsNode argsNode = (ArgsNode) node; if (argsNode.getBlock() != null) setFlag(node, BLOCK_ARG); if (argsNode.getOptArgs() != null) { setFlag(node, OPT_ARGS); inspect(argsNode.getOptArgs()); } if (argsNode.getRestArg() == -2 || argsNode.getRestArg() >= 0) setFlag(node, REST_ARG); break; case ATTRASSIGNNODE: AttrAssignNode attrAssignNode = (AttrAssignNode) node; inspect(attrAssignNode.getArgsNode()); inspect(attrAssignNode.getReceiverNode()); break; case BACKREFNODE: setFlag(node, BACKREF); break; case BEGINNODE: inspect(((BeginNode) node).getBodyNode()); break; case BIGNUMNODE: break; case BINARYOPERATORNODE: BinaryOperatorNode binaryOperatorNode = (BinaryOperatorNode) node; inspect(binaryOperatorNode.getFirstNode()); inspect(binaryOperatorNode.getSecondNode()); break; case BLOCKARGNODE: break; case BLOCKPASSNODE: BlockPassNode blockPassNode = (BlockPassNode) node; inspect(blockPassNode.getArgsNode()); inspect(blockPassNode.getBodyNode()); break; case BREAKNODE: inspect(((BreakNode) node).getValueNode()); break; case CALLNODE: CallNode callNode = (CallNode) node; inspect(callNode.getReceiverNode()); // check for Proc.new, an especially magic method if (callNode.getName() == "new" && callNode.getReceiverNode() instanceof ConstNode && ((ConstNode) callNode.getReceiverNode()).getName() == "Proc") { // Proc.new needs the caller's block to instantiate a proc setFlag(node, FRAME_BLOCK); } if (callNode.getArgsNode() == null && callNode.getIterNode() == null) { switch (callNode.getReceiverNode().getNodeType()) { // no unary methods on literal numbers, symbols, or strings have frame/scope effects case FIXNUMNODE: case FLOATNODE: case BIGNUMNODE: case STRNODE: case SYMBOLNODE: return; } } case FCALLNODE: inspect(((IArgumentNode) node).getArgsNode()); inspect(((BlockAcceptingNode) node).getIterNode()); case VCALLNODE: INameNode nameNode = (INameNode) node; if (FRAME_AWARE_METHODS.contains(nameNode.getName())) { setFlag(node, FRAME_AWARE); if (nameNode.getName().indexOf("eval") != -1) { setFlag(node, EVAL); } } if (SCOPE_AWARE_METHODS.contains(nameNode.getName())) { setFlag(node, SCOPE_AWARE); } break; case CASENODE: CaseNode caseNode = (CaseNode) node; inspect(caseNode.getCaseNode()); if (caseNode.getCases().size() > Options.COMPILE_OUTLINE_CASECOUNT.load()) { // if more than N cases, disable; we'll compile them as separate bodies // see BaseBodyCompiler#compiledSequencedConditional and ASTCompiler#compileCase disable(); return; } else { for (Node when : caseNode.getCases().childNodes()) { inspect(when); } inspect(caseNode.getElseNode()); } break; case CLASSNODE: setFlag(node, CLASS); ClassNode classNode = (ClassNode) node; inspect(classNode.getCPath()); inspect(classNode.getSuperNode()); break; case CLASSVARNODE: setFlag(node, CLASS_VAR); break; case CONSTDECLNODE: inspect(((AssignableNode) node).getValueNode()); setFlag(node, CONSTANT); break; case CLASSVARASGNNODE: inspect(((AssignableNode) node).getValueNode()); setFlag(node, CLASS_VAR); break; case CLASSVARDECLNODE: inspect(((AssignableNode) node).getValueNode()); setFlag(node, CLASS_VAR); break; case COLON2NODE: inspect(((Colon2Node) node).getLeftNode()); break; case COLON3NODE: break; case CONSTNODE: setFlag(node, CONSTANT); break; case DEFNNODE: case DEFSNODE: setFlag(node, METHOD); setFlag(node, FRAME_VISIBILITY); setFlag(node, SCOPE_AWARE); break; case DEFINEDNODE: switch (((DefinedNode) node).getExpressionNode().getNodeType()) { case CLASSVARASGNNODE: case CLASSVARDECLNODE: case CONSTDECLNODE: case DASGNNODE: case GLOBALASGNNODE: case LOCALASGNNODE: case MULTIPLEASGNNODE: case OPASGNNODE: case OPELEMENTASGNNODE: case DVARNODE: case FALSENODE: case TRUENODE: case LOCALVARNODE: case INSTVARNODE: case BACKREFNODE: case SELFNODE: case VCALLNODE: case YIELDNODE: case GLOBALVARNODE: case CONSTNODE: case FCALLNODE: case CLASSVARNODE: // ok, we have fast paths inspect(((DefinedNode) node).getExpressionNode()); break; default: // long, slow way causes disabling // we still inspect because some nodes may change state (JRUBY-6836) inspect(((DefinedNode) node).getExpressionNode()); disable(); } break; case DOTNODE: DotNode dotNode = (DotNode) node; inspect(dotNode.getBeginNode()); inspect(dotNode.getEndNode()); break; case DASGNNODE: inspect(((AssignableNode) node).getValueNode()); break; case DVARNODE: break; case ENSURENODE: inspect(((EnsureNode) node).getBodyNode()); inspect(((EnsureNode) node).getEnsureNode()); disable(); break; case ENCODINGNODE: break; case EVSTRNODE: inspect(((EvStrNode) node).getBody()); break; case FALSENODE: break; case FIXNUMNODE: break; case FLIPNODE: inspect(((FlipNode) node).getBeginNode()); inspect(((FlipNode) node).getEndNode()); break; case FLOATNODE: break; case FORNODE: setFlag(node, CLOSURE); setFlag(node, SCOPE_AWARE); inspect(((ForNode) node).getIterNode()); inspect(((ForNode) node).getBodyNode()); inspect(((ForNode) node).getVarNode()); break; case GLOBALASGNNODE: GlobalAsgnNode globalAsgnNode = (GlobalAsgnNode) node; if (globalAsgnNode.getName().equals("$_")) { setFlag(node, LASTLINE); } else if (globalAsgnNode.getName().equals("$~")) { setFlag(node, BACKREF); } inspect(globalAsgnNode.getValueNode()); break; case GLOBALVARNODE: { String name = ((GlobalVarNode) node).getName(); if (name.equals("$_") || name.equals("$LAST_READ_LINE")) { setFlag(node, LASTLINE); } else if (name.equals("$~") || name.equals("$`") || name.equals("$'") || name.equals("$+") || name.equals("$LAST_MATCH_INFO") || name.equals("$PREMATCH") || name.equals("$POSTMATCH") || name.equals("$LAST_PAREN_MATCH")) { setFlag(node, BACKREF); } break; } case HASHNODE: HashNode hashNode = (HashNode) node; inspect(hashNode.getListNode()); break; case IFNODE: IfNode ifNode = (IfNode) node; inspect(ifNode.getCondition()); inspect(ifNode.getThenBody()); inspect(ifNode.getElseBody()); break; case INSTASGNNODE: inspect(((AssignableNode) node).getValueNode()); break; case INSTVARNODE: break; case ISCOPINGNODE: IScopingNode iscopingNode = (IScopingNode) node; inspect(iscopingNode.getCPath()); break; case ITERNODE: setFlag(node, CLOSURE); break; case LAMBDANODE: setFlag(node, CLOSURE); break; case LOCALASGNNODE: LocalAsgnNode localAsgnNode = (LocalAsgnNode) node; if (PRAGMAS.contains(localAsgnNode.getName())) { if (localAsgnNode.getName().equals("__NOFRAME__")) { noFrame = localAsgnNode.getValueNode() instanceof TrueNode; } break; } inspect(localAsgnNode.getValueNode()); break; case LOCALVARNODE: break; case MATCHNODE: inspect(((MatchNode) node).getRegexpNode()); setFlag(node, BACKREF); break; case MATCH2NODE: Match2Node match2Node = (Match2Node) node; inspect(match2Node.getReceiverNode()); inspect(match2Node.getValueNode()); setFlag(node, BACKREF); if (match2Node instanceof Match2CaptureNode) { // additionally need scope, to set local vars // FIXME: this can be done without heap scope setFlag(node, SCOPE_AWARE); } break; case MATCH3NODE: Match3Node match3Node = (Match3Node) node; inspect(match3Node.getReceiverNode()); inspect(match3Node.getValueNode()); setFlag(node, BACKREF); break; case MODULENODE: setFlag(node, CLASS); inspect(((ModuleNode) node).getCPath()); break; case MULTIPLEASGN19NODE: MultipleAsgn19Node multipleAsgn19Node = (MultipleAsgn19Node) node; inspect(multipleAsgn19Node.getPre()); inspect(multipleAsgn19Node.getPost()); inspect(multipleAsgn19Node.getRest()); inspect(multipleAsgn19Node.getValueNode()); break; case MULTIPLEASGNNODE: MultipleAsgnNode multipleAsgnNode = (MultipleAsgnNode) node; inspect(multipleAsgnNode.getArgsNode()); inspect(multipleAsgnNode.getHeadNode()); inspect(multipleAsgnNode.getValueNode()); break; case NEWLINENODE: inspect(((NewlineNode) node).getNextNode()); break; case NEXTNODE: inspect(((NextNode) node).getValueNode()); break; case NILNODE: break; case NOTNODE: inspect(((NotNode) node).getConditionNode()); break; case NTHREFNODE: break; case OPASGNANDNODE: OpAsgnAndNode opAsgnAndNode = (OpAsgnAndNode) node; inspect(opAsgnAndNode.getFirstNode()); inspect(opAsgnAndNode.getSecondNode()); break; case OPASGNNODE: OpAsgnNode opAsgnNode = (OpAsgnNode) node; inspect(opAsgnNode.getReceiverNode()); inspect(opAsgnNode.getValueNode()); break; case OPASGNORNODE: switch (((OpAsgnOrNode) node).getFirstNode().getNodeType()) { case CLASSVARASGNNODE: case CLASSVARDECLNODE: case CONSTDECLNODE: case DASGNNODE: case GLOBALASGNNODE: case LOCALASGNNODE: case MULTIPLEASGNNODE: case OPASGNNODE: case OPELEMENTASGNNODE: case DVARNODE: case FALSENODE: case TRUENODE: case LOCALVARNODE: case INSTVARNODE: case BACKREFNODE: case SELFNODE: case VCALLNODE: case YIELDNODE: case GLOBALVARNODE: case CONSTNODE: case FCALLNODE: case CLASSVARNODE: // ok, we have fast paths inspect(((OpAsgnOrNode) node).getSecondNode()); break; default: // long, slow way causes disabling for defined inspect(((OpAsgnOrNode) node).getFirstNode()); inspect(((OpAsgnOrNode) node).getSecondNode()); disable(); } break; case OPELEMENTASGNNODE: OpElementAsgnNode opElementAsgnNode = (OpElementAsgnNode) node; inspect(opElementAsgnNode.getArgsNode()); inspect(opElementAsgnNode.getReceiverNode()); inspect(opElementAsgnNode.getValueNode()); break; case OPTARGNODE: inspect(((OptArgNode) node).getValue()); break; case ORNODE: OrNode orNode = (OrNode) node; inspect(orNode.getFirstNode()); inspect(orNode.getSecondNode()); break; case POSTEXENODE: PostExeNode postExeNode = (PostExeNode) node; setFlag(node, CLOSURE); setFlag(node, SCOPE_AWARE); inspect(postExeNode.getBodyNode()); inspect(postExeNode.getVarNode()); break; case PREEXENODE: PreExeNode preExeNode = (PreExeNode) node; setFlag(node, CLOSURE); setFlag(node, SCOPE_AWARE); inspect(preExeNode.getBodyNode()); inspect(preExeNode.getVarNode()); break; case REDONODE: break; case REGEXPNODE: break; case ROOTNODE: inspect(((RootNode) node).getBodyNode()); if (((RootNode) node).getBodyNode() instanceof BlockNode) { BlockNode blockNode = (BlockNode) ((RootNode) node).getBodyNode(); if (blockNode.size() > 500) { // method has more than 500 lines; we'll need to split it // and therefore need to use a heap-based scope setFlag(node, SCOPE_AWARE); } } break; case RESCUEBODYNODE: RescueBodyNode rescueBody = (RescueBodyNode) node; inspect(rescueBody.getExceptionNodes()); inspect(rescueBody.getBodyNode()); inspect(rescueBody.getOptRescueNode()); break; case RESCUENODE: RescueNode rescueNode = (RescueNode) node; inspect(rescueNode.getBodyNode()); inspect(rescueNode.getElseNode()); inspect(rescueNode.getRescueNode()); disable(); break; case RETRYNODE: setFlag(node, RETRY); break; case RETURNNODE: inspect(((ReturnNode) node).getValueNode()); break; case SCLASSNODE: setFlag(node, CLASS); setFlag(node, FRAME_AWARE); SClassNode sclassNode = (SClassNode) node; inspect(sclassNode.getReceiverNode()); break; case SCOPENODE: break; case SELFNODE: break; case SPLATNODE: inspect(((SplatNode) node).getValue()); break; case STARNODE: break; case STRNODE: break; case SUPERNODE: SuperNode superNode = (SuperNode) node; inspect(superNode.getArgsNode()); inspect(superNode.getIterNode()); setFlag(node, SUPER); break; case SVALUENODE: inspect(((SValueNode) node).getValue()); break; case SYMBOLNODE: break; case TOARYNODE: inspect(((ToAryNode) node).getValue()); break; case TRUENODE: break; case UNDEFNODE: setFlag(node, METHOD); break; case UNTILNODE: UntilNode untilNode = (UntilNode) node; ASTInspector untilInspector = subInspect(untilNode.getConditionNode(), untilNode.getBodyNode()); // a while node could receive non-local flow control from any of these: // * a closure within the loop // * an eval within the loop // * a block-arg-based proc called within the loop if (untilInspector.getFlag(CLOSURE) || untilInspector.getFlag(EVAL)) { untilNode.containsNonlocalFlow = true; // we set scope-aware to true to force heap-based locals setFlag(node, SCOPE_AWARE); } integrate(untilInspector); break; case VALIASNODE: break; case WHENNODE: { inspect(((WhenNode) node).getBodyNode()); inspect(((WhenNode) node).getExpressionNodes()); inspect(((WhenNode) node).getNextCase()); // if any elements are not literals or are regexp, set backref Node expr = ((WhenNode) node).getExpressionNodes(); if (!(expr instanceof ILiteralNode) || expr.getNodeType() == NodeType.REGEXPNODE) { setFlag(node, BACKREF); } break; } case WHILENODE: WhileNode whileNode = (WhileNode) node; ASTInspector whileInspector = subInspect(whileNode.getConditionNode(), whileNode.getBodyNode()); // a while node could receive non-local flow control from any of these: // * a closure within the loop // * an eval within the loop // * a block-arg-based proc called within the loop // * any case that disables optimization, like rescues and ensures if (whileInspector.getFlag(CLOSURE) || whileInspector.getFlag(EVAL) || getFlag(BLOCK_ARG)) { whileNode.containsNonlocalFlow = true; // we set scope-aware to true to force heap-based locals setFlag(node, SCOPE_AWARE); } integrate(whileInspector); break; case XSTRNODE: break; case YIELDNODE: inspect(((YieldNode) node).getArgsNode()); break; case ZARRAYNODE: break; case ZEROARGNODE: break; case ZSUPERNODE: setFlag(node, SCOPE_AWARE); setFlag(node, ZSUPER); inspect(((ZSuperNode) node).getIterNode()); break; default: // encountered a node we don't recognize, set everything to true to disable optz assert false : "All nodes should be accounted for in AST inspector: " + node; disable(); } }
// consider refactoring signature to return PotentialMatch object with fields set... int findMatch(int index, int[] distOut, int[] gainOut, int[] costPerByteOut) { final int maxCostCacheLength = 32; int[] literalCostCache = new int[maxCostCacheLength + 1]; int maxIndexMinusIndex = buf.length - index; int bestLength = 0; int bestDist = 0; int bestGain = 0; int bestCopyCost = 0; int maxComputedLength = 0; if (maxIndexMinusIndex > 1) { int pos = ((buf[index] & 0xff) << 8) | (buf[index + 1] & 0xff); HashNode prevNode = null; int hNodeCount = 0; for (HashNode hNode = hashTable[pos]; hNode != null; prevNode = hNode, hNode = hNode.next) { int i = hNode.index; int dist = index - i; hNodeCount++; if (hNodeCount > 256 || dist > maxCopyDist) { if (hashTable[pos] == hNode) { hashTable[pos] = null; } else { prevNode.next = null; } break; } int maxLen = index - i; if (maxIndexMinusIndex < maxLen) { maxLen = maxIndexMinusIndex; } if (maxLen < LEN_MIN) { continue; } i += 2; int length = 2; for (length = 2; length < maxLen && buf[i] == buf[index + length]; length++) { i++; } if (length < LEN_MIN) { continue; } dist = dist - length + 1; if (dist > distMax || (length == 2 && dist >= MAX_2BYTE_DIST)) { continue; } if (length <= bestLength && dist > bestDist) { if (length <= bestLength - 2) { continue; } if (dist > (bestDist << DIST_WIDTH)) { if (length < bestLength || dist > (bestDist << (DIST_WIDTH + 1))) { continue; } } } int literalCost = 0; if (length > maxComputedLength) { int limit = length; if (limit > maxCostCacheLength) limit = maxCostCacheLength; for (i = maxComputedLength; i < limit; i++) { byte c = buf[index + i]; literalCostCache[i + 1] = literalCostCache[i] + symEncoder.writeSymbolCost(c & 0xff); } maxComputedLength = limit; if (length > maxCostCacheLength) { literalCost = literalCostCache[maxCostCacheLength]; literalCost += literalCost / maxCostCacheLength * (length - maxCostCacheLength); } else { literalCost = literalCostCache[length]; } } else { literalCost = literalCostCache[length]; } if (literalCost > bestGain) { int distRanges = getNumDistRanges(dist); int copyCost = encodeLengthCost(length, dist, distRanges); if (literalCost - copyCost - (distRanges << 16) > bestGain) { copyCost += encodeDistance2Cost(dist, distRanges); int gain = literalCost - copyCost; if (gain > bestGain) { bestGain = gain; bestLength = length; bestDist = dist; bestCopyCost = copyCost; } } } } } costPerByteOut[0] = bestLength > 0 ? bestCopyCost / bestLength : 0; distOut[0] = bestDist; gainOut[0] = bestGain; return bestLength; }