From 81b000faf9a2412421d906ebbb08dfb5bac911f9 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Sun, 26 May 2024 06:50:44 -0500 Subject: [PATCH] Fork off NewMarshalCache and use identity for symbols --- .../jruby/runtime/marshal/MarshalCache.java | 12 --- .../org/jruby/runtime/marshal/NewMarshal.java | 30 +++---- .../runtime/marshal/NewMarshalCache.java | 84 +++++++++++++++++++ 3 files changed, 99 insertions(+), 27 deletions(-) create mode 100644 core/src/main/java/org/jruby/runtime/marshal/NewMarshalCache.java diff --git a/core/src/main/java/org/jruby/runtime/marshal/MarshalCache.java b/core/src/main/java/org/jruby/runtime/marshal/MarshalCache.java index d1ccb1983c8..2f11655d143 100644 --- a/core/src/main/java/org/jruby/runtime/marshal/MarshalCache.java +++ b/core/src/main/java/org/jruby/runtime/marshal/MarshalCache.java @@ -73,23 +73,11 @@ public void writeLink(MarshalStream output, IRubyObject value) throws IOExceptio output.writeInt(registeredIndex(value)); } - public void writeLink(NewMarshal output, NewMarshal.RubyOutputStream out, IRubyObject value) { - assert !(value instanceof RubySymbol) : "Use writeSymbolLink for symbols"; - - out.write('@'); - output.writeInt(out, registeredIndex(value)); - } - public void writeSymbolLink(MarshalStream output, ByteList sym) throws IOException { output.write(';'); output.writeInt(registeredSymbolIndex(sym)); } - public void writeSymbolLink(NewMarshal output, NewMarshal.RubyOutputStream out, ByteList sym) { - out.write(';'); - output.writeInt(out, registeredSymbolIndex(sym)); - } - private int registeredIndex(IRubyObject value) { return linkCache.get(value); } diff --git a/core/src/main/java/org/jruby/runtime/marshal/NewMarshal.java b/core/src/main/java/org/jruby/runtime/marshal/NewMarshal.java index 357f45f4fba..d1c31db71a4 100644 --- a/core/src/main/java/org/jruby/runtime/marshal/NewMarshal.java +++ b/core/src/main/java/org/jruby/runtime/marshal/NewMarshal.java @@ -86,12 +86,12 @@ * @author Anders */ public class NewMarshal { - private final MarshalCache cache; + private final NewMarshalCache cache; private final int depthLimit; private int depth = 0; public NewMarshal(int depthLimit) { - this.cache = new MarshalCache(); + this.cache = new NewMarshalCache(); this.depthLimit = depthLimit >= 0 ? depthLimit : Integer.MAX_VALUE; } @@ -154,7 +154,7 @@ public void registerLinkTarget(IRubyObject newObject) { } } - public void registerSymbol(ByteList sym) { + public void registerSymbol(RubySymbol sym) { cache.registerSymbol(sym); } @@ -173,12 +173,12 @@ private static boolean isMarshalFixnum(RubyFixnum fixnum) { return fixnum.getLongValue() <= RubyFixnum.MAX_MARSHAL_FIXNUM && fixnum.getLongValue() >= RubyFixnum.MIN_MARSHAL_FIXNUM; } - private void writeAndRegisterSymbol(RubyOutputStream out, ByteList sym) { + private void writeAndRegisterSymbol(RubyOutputStream out, RubySymbol sym) { if (cache.isSymbolRegistered(sym)) { cache.writeSymbolLink(this, out, sym); } else { registerSymbol(sym); - dumpSymbol(out, sym); + dumpSymbol(out, sym.getBytes()); } } @@ -386,7 +386,7 @@ private void writeObjectData(ThreadContext context, RubyOutputStream out, IRubyO RubyStruct.marshalTo((RubyStruct)value, this, context, out); return; case SYMBOL: - writeAndRegisterSymbol(out, ((RubySymbol) value).getBytes()); + writeAndRegisterSymbol(out, ((RubySymbol) value)); return; case TRUE: out.write('T'); @@ -415,7 +415,7 @@ private void userNewCommon(ThreadContext context, RubyOutputStream out, IRubyObj out.write(TYPE_USRMARSHAL); final RubyClass klass = getMetaClass(value); final Ruby runtime = context.runtime; - writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, klass.getRealClass().getName()).getBytes()); + writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, klass.getRealClass().getName())); IRubyObject marshaled; if (entry != null) { @@ -483,7 +483,7 @@ private void userCommon(ThreadContext context, RubyOutputStream out, IRubyObject private void dumpUserdefBase(RubyOutputStream out, Ruby runtime, RubyClass klass, RubyString marshaled) { out.write(TYPE_USERDEF); - writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, klass.getRealClass().getName()).getBytes()); + writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, klass.getRealClass().getName())); writeString(out, marshaled.getByteList()); } @@ -498,7 +498,7 @@ public void writeUserClass(ThreadContext context, RubyOutputStream out, RubyClas } // w_symbol - writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, type.getName()).getBytes()); + writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, type.getName())); } public void dumpVariables(ThreadContext context, RubyOutputStream out, IRubyObject value) { @@ -538,7 +538,7 @@ public void dumpVariables(ThreadContext context, RubyOut private static void dumpVariable(NewMarshal marshal, ThreadContext context, RubyOutputStream out, String name, Object value) { if (value instanceof IRubyObject) { - marshal.writeAndRegisterSymbol(out, RubySymbol.newSymbol(context.runtime, name).getBytes()); + marshal.writeAndRegisterSymbol(out, RubySymbol.newSymbol(context.runtime, name)); marshal.dumpObject(context, out, (IRubyObject) value); } } @@ -546,13 +546,13 @@ private static void dumpVariable(NewMarshal marshal, ThreadContext context, Ruby public void writeEncoding(ThreadContext context, RubyOutputStream out, Encoding encoding) { Ruby runtime = context.runtime; if (encoding == null || encoding == USASCIIEncoding.INSTANCE) { - writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, SYMBOL_ENCODING_SPECIAL).getBytes()); + writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, SYMBOL_ENCODING_SPECIAL)); writeObjectData(context, out, runtime.getFalse()); } else if (encoding == UTF8Encoding.INSTANCE) { - writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, SYMBOL_ENCODING_SPECIAL).getBytes()); + writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, SYMBOL_ENCODING_SPECIAL)); writeObjectData(context, out, runtime.getTrue()); } else { - writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, SYMBOL_ENCODING).getBytes()); + writeAndRegisterSymbol(out, RubySymbol.newSymbol(runtime, SYMBOL_ENCODING)); RubyString encodingString = new RubyString(runtime, runtime.getString(), encoding.getName()); writeObjectData(context, out, encodingString); } @@ -580,7 +580,7 @@ private RubyClass dumpExtended(ThreadContext context, RubyOutputStream out, Ruby } while(type.isIncluded()) { out.write('e'); - writeAndRegisterSymbol(out, RubySymbol.newSymbol(context.runtime, type.getOrigin().getName()).getBytes()); + writeAndRegisterSymbol(out, RubySymbol.newSymbol(context.runtime, type.getOrigin().getName())); type = type.getSuperClass(); } return type; @@ -593,7 +593,7 @@ public void dumpDefaultObjectHeader(ThreadContext context, RubyOutputStream out, public void dumpDefaultObjectHeader(ThreadContext context, RubyOutputStream out, char tp, RubyClass type) { dumpExtended(context, out, type); out.write(tp); - writeAndRegisterSymbol(out, RubySymbol.newSymbol(context.runtime, getPathFromClass(context, type.getRealClass())).getBytes()); + writeAndRegisterSymbol(out, RubySymbol.newSymbol(context.runtime, getPathFromClass(context, type.getRealClass()))); } public void writeString(RubyOutputStream out, String value) { diff --git a/core/src/main/java/org/jruby/runtime/marshal/NewMarshalCache.java b/core/src/main/java/org/jruby/runtime/marshal/NewMarshalCache.java new file mode 100644 index 00000000000..cd55112919c --- /dev/null +++ b/core/src/main/java/org/jruby/runtime/marshal/NewMarshalCache.java @@ -0,0 +1,84 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/epl-v20.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * Copyright (C) 2002 Jan Arne Petersen + * Copyright (C) 2002-2004 Anders Bengtsson + * Copyright (C) 2004 Stefan Matthias Aust + * Copyright (C) 2007 Ola Bini + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the EPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the EPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ + +package org.jruby.runtime.marshal; + +import org.jruby.RubySymbol; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.util.ByteList; +import org.jruby.util.collections.HashMapInt; + +import java.io.IOException; + +public class NewMarshalCache { + private final HashMapInt linkCache = new HashMapInt<>(true); + private final HashMapInt symbolCache = new HashMapInt<>(true); + + public boolean isRegistered(IRubyObject value) { + assert !(value instanceof RubySymbol) : "Use isSymbolRegistered for symbol links"; + + return linkCache.containsKey(value); + } + + public boolean isSymbolRegistered(RubySymbol sym) { + return symbolCache.containsKey(sym); + } + + public void register(IRubyObject value) { + assert !(value instanceof RubySymbol) : "Use registeredSymbolIndex for symbols"; + + linkCache.put(value, Integer.valueOf(linkCache.size())); + } + + public void registerSymbol(RubySymbol sym) { + symbolCache.put(sym, symbolCache.size()); + } + + public void writeLink(NewMarshal output, NewMarshal.RubyOutputStream out, IRubyObject value) { + assert !(value instanceof RubySymbol) : "Use writeSymbolLink for symbols"; + + out.write('@'); + output.writeInt(out, registeredIndex(value)); + } + + public void writeSymbolLink(NewMarshal output, NewMarshal.RubyOutputStream out, RubySymbol sym) { + out.write(';'); + output.writeInt(out, registeredSymbolIndex(sym)); + } + + private int registeredIndex(IRubyObject value) { + return linkCache.get(value); + } + + private int registeredSymbolIndex(RubySymbol sym) { + return symbolCache.get(sym); + } +}