diff --git a/src/org/mozilla/javascript/Arguments.java b/src/org/mozilla/javascript/Arguments.java
index f7027bc..24e2782 100644
--- a/src/org/mozilla/javascript/Arguments.java
+++ b/src/org/mozilla/javascript/Arguments.java
@@ -47,14 +47,27 @@ final class Arguments extends IdScriptableObject
         }
     }
 
+    Arguments(Object[] args) {
+        this.args = args;
+        if (args == null) {
+            lengthObj = 0;
+        }
+        else {
+            lengthObj = Integer.valueOf(args.length);
+        }
+    }
+
     @Override
     public String getClassName()
     {
+        if (Context.getContext().hasFeature(Context.FEATURE_HTMLUNIT_ARGUMENTS_IS_OBJECT)) {
+            return "Object";
+        }
         return FTAG;
     }
 
     private Object arg(int index) {
-      if (index < 0 || args.length <= index) return NOT_FOUND;
+      if (index < 0 || args == null || args.length <= index) return NOT_FOUND;
       return args[index];
     }
 
@@ -75,7 +88,7 @@ final class Arguments extends IdScriptableObject
         putIntoActivation(index, value);
       }
       synchronized (this) {
-        if (args == activation.originalArgs) {
+        if (activation != null && args == activation.originalArgs) {
           args = args.clone();
         }
         args[index] = value;
@@ -121,6 +134,7 @@ final class Arguments extends IdScriptableObject
 
     private boolean sharedWithActivation(int index)
     {
+        if (activation == null) return false;
         NativeFunction f = activation.function;
         int definedCount = f.getParamCount();
         if (index < definedCount) {
@@ -142,6 +156,9 @@ final class Arguments extends IdScriptableObject
     @Override
     public void put(int index, Scriptable start, Object value)
     {
+        if (Context.getCurrentContext().hasFeature(Context.FEATURE_HTMLUNIT_ARGUMENTS_IS_READ_ONLY)) {
+            return;
+        }
         if (arg(index) == NOT_FOUND) {
           super.put(index, start, value);
         } else {
@@ -356,6 +373,11 @@ final class Arguments extends IdScriptableObject
       }
     }
 
+    @Override
+    public Object getDefaultValue(Class<?> typeHint) {
+        return "[object " + getClassName() + "]";
+    }
+
 // Fields to hold caller, callee and length properties,
 // where NOT_FOUND value tags deleted properties.
 // In addition if callerObj == NULL_VALUE, it tags null for scripts, as
diff --git a/src/org/mozilla/javascript/Context.java b/src/org/mozilla/javascript/Context.java
index df4c4c0..15713ce 100644
--- a/src/org/mozilla/javascript/Context.java
+++ b/src/org/mozilla/javascript/Context.java
@@ -283,6 +283,76 @@ public class Context
      */
     public static final int FEATURE_ENHANCED_JAVA_ACCESS = 13;
 
+    /**
+     * Special to HtmlUnit's Rhino fork.
+     *
+     * The same web browser (e.g. FF) may allow setting read-only property, 
+     * ignores setting the read-only property, or even throw an exception.
+     *
+     * So, by having this feature, ScriptableObject itself is asked throw
+     * {@link ScriptableObject#isReadOnlySettable} whether to allow, ignore or throw an exception.
+     *
+     * By default {@link #hasFeature(int)} returns false.
+     */
+    public static final int FEATURE_HTMLUNIT_ASK_OBJECT_TO_WRITE_READONLY = 14;
+
+    /**
+     * Special to HtmlUnit's Rhino fork.
+     * Indicates if a JavaScript catch statement can catch Java exceptions
+     * (exceptions occurring in host objects).
+     * By default {@link #hasFeature(int)} returns true.
+     */
+    public static final int FEATURE_HTMLUNIT_JS_CATCH_JAVA_EXCEPTION = 15;
+
+    /**
+     * Special to HtmlUnit's Rhino fork.
+     *
+     * Is the default value of {@link Arguments} "Object" or "Arguments"
+     *
+     * By default {@link #hasFeature(int)} returns false.
+     */
+    public static final int FEATURE_HTMLUNIT_ARGUMENTS_IS_OBJECT = 16;
+
+    /**
+     * Special to HtmlUnit's Rhino fork.
+     *
+     * When setting the function name to call, call thisObject.setter.
+     *
+     * This is needed for something like "function onclick() {onclick = null}"
+     *
+     * Implemented by transforming it into "function onclick() {<b>this.</b>onclick = null}"
+     *
+     * By default {@link #hasFeature(int)} returns false.
+     */
+    public static final int FEATURE_HTMLUNIT_FUNCTION_NULL_SETTER = 17;
+
+    /**
+     * Special to HtmlUnit's Rhino fork.
+     *
+     * Whether the "arguments" object read-only or not.
+     *
+     * By default {@link #hasFeature(int)} returns false.
+     */
+    public static final int FEATURE_HTMLUNIT_ARGUMENTS_IS_READ_ONLY = 18;
+
+    /**
+     * Special to HtmlUnit's Rhino fork.
+     *
+     * Indicates that 'eval' function should have access to the local function scope.
+     *
+     * By default {@link #hasFeature(int)} returns true.
+     */
+    public static final int FEATURE_HTMLUNIT_EVAL_LOCAL_SCOPE = 19;
+
+    /**
+     * Special to HtmlUnit's Rhino fork.
+     *
+     * Indicates that 'exception' (technically NativeError) exposes "stack" property.
+     *
+     * By default {@link #hasFeature(int)} returns true.
+     */
+    public static final int FEATURE_HTMLUNIT_ERROR_STACK= 20;
+
     public static final String languageVersionProperty = "language version";
     public static final String errorReporterProperty   = "error reporter";
 
@@ -1325,7 +1395,7 @@ public class Context
                              securityDomain);
     }
 
-    final Script compileString(String source,
+    protected Script compileString(String source,
                                Evaluator compiler,
                                ErrorReporter compilationErrorReporter,
                                String sourceName, int lineno,
diff --git a/src/org/mozilla/javascript/ContextFactory.java b/src/org/mozilla/javascript/ContextFactory.java
index 642a3b3..5d17252 100644
--- a/src/org/mozilla/javascript/ContextFactory.java
+++ b/src/org/mozilla/javascript/ContextFactory.java
@@ -279,6 +279,27 @@ public class ContextFactory
 
           case Context.FEATURE_ENHANCED_JAVA_ACCESS:
             return false;
+
+          case Context.FEATURE_HTMLUNIT_ASK_OBJECT_TO_WRITE_READONLY:
+            return false;
+
+          case Context.FEATURE_HTMLUNIT_JS_CATCH_JAVA_EXCEPTION:
+            return true;
+
+          case Context.FEATURE_HTMLUNIT_ARGUMENTS_IS_OBJECT:
+            return false;
+
+          case Context.FEATURE_HTMLUNIT_FUNCTION_NULL_SETTER:
+            return false;
+
+          case Context.FEATURE_HTMLUNIT_ARGUMENTS_IS_READ_ONLY:
+            return false;
+
+          case Context.FEATURE_HTMLUNIT_EVAL_LOCAL_SCOPE:
+            return true;
+
+          case Context.FEATURE_HTMLUNIT_ERROR_STACK:
+            return true;
         }
         // It is a bug to call the method with unknown featureIndex
         throw new IllegalArgumentException(String.valueOf(featureIndex));
diff --git a/src/org/mozilla/javascript/Delegator.java b/src/org/mozilla/javascript/Delegator.java
index 8e8bac4..e273d0f 100644
--- a/src/org/mozilla/javascript/Delegator.java
+++ b/src/org/mozilla/javascript/Delegator.java
@@ -85,85 +85,85 @@ public class Delegator implements Function {
      * @see org.mozilla.javascript.Scriptable#getClassName
      */
     public String getClassName() {
-        return obj.getClassName();
+        return getDelegee().getClassName();
     }
     /**
      * @see org.mozilla.javascript.Scriptable#get(String, Scriptable)
      */
     public Object get(String name, Scriptable start) {
-        return obj.get(name,start);
+        return getDelegee().get(name,start);
     }
     /**
      * @see org.mozilla.javascript.Scriptable#get(int, Scriptable)
      */
     public Object get(int index, Scriptable start) {
-        return obj.get(index,start);
+        return getDelegee().get(index,start);
         }
     /**
      * @see org.mozilla.javascript.Scriptable#has(String, Scriptable)
      */
     public boolean has(String name, Scriptable start) {
-        return obj.has(name,start);
+        return getDelegee().has(name,start);
         }
     /**
      * @see org.mozilla.javascript.Scriptable#has(int, Scriptable)
      */
     public boolean has(int index, Scriptable start) {
-        return obj.has(index,start);
+        return getDelegee().has(index,start);
         }
     /**
      * @see org.mozilla.javascript.Scriptable#put(String, Scriptable, Object)
      */
     public void put(String name, Scriptable start, Object value) {
-        obj.put(name,start,value);
+        getDelegee().put(name,start,value);
     }
     /**
      * @see org.mozilla.javascript.Scriptable#put(int, Scriptable, Object)
      */
     public void put(int index, Scriptable start, Object value) {
-        obj.put(index,start,value);
+        getDelegee().put(index,start,value);
     }
     /**
      * @see org.mozilla.javascript.Scriptable#delete(String)
      */
     public void delete(String name) {
-        obj.delete(name);
+        getDelegee().delete(name);
     }
     /**
      * @see org.mozilla.javascript.Scriptable#delete(int)
      */
     public void delete(int index) {
-        obj.delete(index);
+        getDelegee().delete(index);
     }
     /**
      * @see org.mozilla.javascript.Scriptable#getPrototype
      */
     public Scriptable getPrototype() {
-        return obj.getPrototype();
+        return getDelegee().getPrototype();
     }
     /**
      * @see org.mozilla.javascript.Scriptable#setPrototype
      */
     public void setPrototype(Scriptable prototype) {
-        obj.setPrototype(prototype);
+        getDelegee().setPrototype(prototype);
     }
     /**
      * @see org.mozilla.javascript.Scriptable#getParentScope
      */
     public Scriptable getParentScope() {
-        return obj.getParentScope();
+        return getDelegee().getParentScope();
     }
     /**
      * @see org.mozilla.javascript.Scriptable#setParentScope
      */
     public void setParentScope(Scriptable parent) {
-        obj.setParentScope(parent);
+        getDelegee().setParentScope(parent);
     }
     /**
      * @see org.mozilla.javascript.Scriptable#getIds
      */
     public Object[] getIds() {
-        return obj.getIds();
+        return getDelegee().getIds();
     }
     /**
      * Note that this method does not get forwarded to the delegee if
@@ -181,13 +181,13 @@ public class Delegator implements Function {
         return (hint == null ||
                 hint == ScriptRuntime.ScriptableClass ||
                 hint == ScriptRuntime.FunctionClass) ?
-            this : obj.getDefaultValue(hint);
+            this : getDelegee().getDefaultValue(hint);
     }
     /**
      * @see org.mozilla.javascript.Scriptable#hasInstance
      */
     public boolean hasInstance(Scriptable instance) {
-        return obj.hasInstance(instance);
+        return getDelegee().hasInstance(instance);
     }
     /**
      * @see org.mozilla.javascript.Function#call
@@ -195,7 +195,7 @@ public class Delegator implements Function {
     public Object call(Context cx, Scriptable scope, Scriptable thisObj,
                        Object[] args)
     {
-        return ((Function)obj).call(cx,scope,thisObj,args);
+        return ((Function)getDelegee()).call(cx,scope,thisObj,args);
     }
 
     /**
@@ -215,7 +215,7 @@ public class Delegator implements Function {
      */
     public Scriptable construct(Context cx, Scriptable scope, Object[] args)
     {
-        if (obj == null) {
+        if (getDelegee() == null) {
             //this little trick allows us to declare prototype objects for
             //Delegators
             Delegator n = newInstance();
@@ -229,7 +229,7 @@ public class Delegator implements Function {
             return n;
         }
         else {
-            return ((Function)obj).construct(cx,scope,args);
+            return ((Function)getDelegee()).construct(cx,scope,args);
         }
     }
 }
diff --git a/src/org/mozilla/javascript/FunctionObject.java b/src/org/mozilla/javascript/FunctionObject.java
index 376ef0c..600fa98 100644
--- a/src/org/mozilla/javascript/FunctionObject.java
+++ b/src/org/mozilla/javascript/FunctionObject.java
@@ -397,6 +397,9 @@ public class FunctionObject extends BaseFunction
         } else {
             if (!isStatic) {
                 Class<?> clazz = member.getDeclaringClass();
+                if (thisObj instanceof Delegator) {
+                    thisObj = ((Delegator) thisObj).getDelegee();
+                }
                 if (!clazz.isInstance(thisObj)) {
                     boolean compatible = false;
                     if (thisObj == scope) {
diff --git a/src/org/mozilla/javascript/IRFactory.java b/src/org/mozilla/javascript/IRFactory.java
index 81fb8db..ad24816 100644
--- a/src/org/mozilla/javascript/IRFactory.java
+++ b/src/org/mozilla/javascript/IRFactory.java
@@ -356,6 +356,7 @@ public final class IRFactory extends Parser
 
     private Node transformAssignment(Assignment node) {
         AstNode left = removeParens(node.getLeft());
+        left = transformAssignmentLeft(node, left);
         Node target = null;
         if (isDestructuring(left)) {
             decompile(left);
@@ -369,6 +370,32 @@ public final class IRFactory extends Parser
                                 transform(node.getRight()));
     }
 
+    private AstNode transformAssignmentLeft(Assignment node, AstNode left) {
+        AstNode right = node.getRight();
+
+        if (right.getType() == Token.NULL && node.getType() == Token.ASSIGN
+                && left instanceof Name && right instanceof KeywordLiteral
+                && Context.getCurrentContext().hasFeature(Context.FEATURE_HTMLUNIT_FUNCTION_NULL_SETTER)) {
+
+            final String identifier = ((Name) left).getIdentifier();
+            for (AstNode p = node.getParent(); p != null; p = p.getParent()) {
+                if (p instanceof FunctionNode) {
+                    final Name functionName = ((FunctionNode) p).getFunctionName();
+                    if (functionName != null && functionName.getIdentifier().equals(identifier)) {
+                        final PropertyGet propertyGet = new PropertyGet();
+                        final KeywordLiteral thisKeyword = new KeywordLiteral();
+                        thisKeyword.setType(Token.THIS);
+                        propertyGet.setLeft(thisKeyword);
+                        propertyGet.setRight(left);
+                        node.setLeft(propertyGet);
+                        return propertyGet;
+                    }
+                }
+            }
+        }
+        return left;
+    }
+
     private Node transformBlock(AstNode node) {
         if (node instanceof Scope) {
             pushScope((Scope)node);
@@ -438,6 +465,16 @@ public final class IRFactory extends Parser
     }
 
     private Node transformElementGet(ElementGet node) {
+        //Ensure "function['eval']" is transformed into "function.eval"
+        if (node.getElement().type == Token.STRING
+                && "eval".equals(((StringLiteral) node.getElement()).getValue())) {
+            final PropertyGet propertyGet = new PropertyGet();
+            propertyGet.setLeft(node.getTarget());
+            final Name name = new Name();
+            name.setIdentifier("eval");
+            propertyGet.setRight(name);
+            return transform(propertyGet);
+        }
         // OPT: could optimize to createPropertyGet
         // iff elem is string that can not be number
         Node target = transform(node.getTarget());
diff --git a/src/org/mozilla/javascript/InterpretedFunction.java b/src/org/mozilla/javascript/InterpretedFunction.java
index 92fb16a..ee9aa35 100644
--- a/src/org/mozilla/javascript/InterpretedFunction.java
+++ b/src/org/mozilla/javascript/InterpretedFunction.java
@@ -176,5 +176,14 @@ final class InterpretedFunction extends NativeFunction implements Script
     {
         return idata.argIsConst[index];
     }
+
+    /**
+     * Provides the decompiled source of the function what is helpful
+     * while debugging.
+     */
+    @Override
+    public String toString() {
+    	return decompile(2, 0);
+    }
 }
 
diff --git a/src/org/mozilla/javascript/Interpreter.java b/src/org/mozilla/javascript/Interpreter.java
index 485ae7c..25b31eb 100644
--- a/src/org/mozilla/javascript/Interpreter.java
+++ b/src/org/mozilla/javascript/Interpreter.java
@@ -2844,6 +2844,22 @@ switch (op) {
     private static void enterFrame(Context cx, CallFrame frame, Object[] args,
                                    boolean continuationRestart)
     {
+       if (frame.parentFrame != null && !frame.parentFrame.fnOrScript.isScript()) {
+           frame.fnOrScript.defaultPut("caller", frame.parentFrame.fnOrScript);
+       }
+       Object[] parameters = null;
+       if (frame.scope instanceof NativeCall) {
+           parameters = args;
+       }
+       else {
+           int paramCount = frame.idata.getParamCount();
+           if (paramCount != 0 && paramCount <= args.length) {
+               parameters = new Object[paramCount];
+               System.arraycopy(args, args.length - parameters.length, parameters, 0, parameters.length);
+           }
+       }
+       frame.fnOrScript.defaultPut("arguments", new Arguments(parameters));
+
         boolean usesActivation = frame.idata.itsNeedsActivation;
         boolean isDebugged = frame.debuggerFrame != null;
         if(usesActivation || isDebugged) {
@@ -2893,6 +2909,9 @@ switch (op) {
     private static void exitFrame(Context cx, CallFrame frame,
                                   Object throwable)
     {
+        frame.fnOrScript.defaultPut("caller", null);
+        frame.fnOrScript.defaultPut("arguments", null);
+
         if (frame.idata.itsNeedsActivation) {
             ScriptRuntime.exitActivationFunction(cx);
         }
diff --git a/src/org/mozilla/javascript/MemberBox.java b/src/org/mozilla/javascript/MemberBox.java
index cc1a8cd..9a20c8d 100644
--- a/src/org/mozilla/javascript/MemberBox.java
+++ b/src/org/mozilla/javascript/MemberBox.java
@@ -121,6 +121,17 @@ final class MemberBox implements Serializable
     Object invoke(Object target, Object[] args)
     {
         Method method = method();
+        
+        // handle delegators
+        if (target instanceof Delegator) {
+        	target = ((Delegator) target).getDelegee();
+        }
+        for (int i=0; i<args.length; ++i) {
+        	if (args[i] instanceof Delegator) {
+        		args[i] = ((Delegator) args[i]).getDelegee();
+        	}
+        }
+        
         try {
             try {
                 return method.invoke(target, args);
@@ -145,7 +156,11 @@ final class MemberBox implements Serializable
             } while ((e instanceof InvocationTargetException));
             if (e instanceof ContinuationPending)
                 throw (ContinuationPending) e;
-            throw Context.throwAsScriptRuntimeEx(e);
+
+            if (e instanceof RhinoException || Context.getCurrentContext().hasFeature(Context.FEATURE_HTMLUNIT_JS_CATCH_JAVA_EXCEPTION))
+                throw Context.throwAsScriptRuntimeEx(e);            
+            else
+            	throw new RuntimeException("Exception invoking " + method.getName(), e);
         } catch (Exception ex) {
             throw Context.throwAsScriptRuntimeEx(ex);
         }
diff --git a/src/org/mozilla/javascript/NativeError.java b/src/org/mozilla/javascript/NativeError.java
index 5053c5d..e48072c 100644
--- a/src/org/mozilla/javascript/NativeError.java
+++ b/src/org/mozilla/javascript/NativeError.java
@@ -110,7 +110,7 @@ final class NativeError extends IdScriptableObject
         // generated on demand, is cached after the first access, and is
         // overwritable like an ordinary property. Hence this setup with
         // the getter and setter below.
-        if (stackProvider == null) {
+        if (stackProvider == null && Context.getContext().hasFeature(Context.FEATURE_HTMLUNIT_ERROR_STACK)) {
             stackProvider = re;
             try {
                 defineProperty("stack", null,
@@ -124,8 +124,10 @@ final class NativeError extends IdScriptableObject
     }
 
     public Object getStack() {
+    	RhinoException.useMozillaStackStyle(true);
         Object value =  stackProvider == null ?
                 NOT_FOUND : stackProvider.getScriptStackTrace();
+    	RhinoException.useMozillaStackStyle(false);
         // We store the stack as local property both to cache it
         // and to make the property writable
         setStack(value);
diff --git a/src/org/mozilla/javascript/ScriptRuntime.java b/src/org/mozilla/javascript/ScriptRuntime.java
index e380adc..ae6dc2d 100644
--- a/src/org/mozilla/javascript/ScriptRuntime.java
+++ b/src/org/mozilla/javascript/ScriptRuntime.java
@@ -955,7 +955,10 @@ public class ScriptRuntime {
     public static Scriptable toObjectOrNull(Context cx, Object obj,
                                             final Scriptable scope)
     {
-        if (obj instanceof Scriptable) {
+    	if (obj instanceof Delegator) {
+    		return ((Delegator) obj).getDelegee();
+    	}
+    	else if (obj instanceof Scriptable) {
             return (Scriptable)obj;
         } else if (obj != null && obj != Undefined.instance) {
             return toObject(cx, scope, obj);
@@ -2167,6 +2170,9 @@ public class ScriptRuntime {
                                                   Context cx,
                                                   Scriptable scope)
     {
+        if ("eval".equals(name)) {
+            lastEvalTopCalled_ = true;
+        }
         Scriptable parent = scope.getParentScope();
         if (parent == null) {
             Object result = topScopeName(cx, scope, name);
@@ -2246,6 +2252,9 @@ public class ScriptRuntime {
                                                   String property,
                                                   Context cx, final Scriptable scope)
     {
+        if ("eval".equals(property)) {
+            lastEvalTopCalled_ = false;
+        }
         Scriptable thisObj = toObjectOrNull(cx, obj, scope);
         return getPropFunctionAndThisHelper(obj, property, cx, thisObj);
     }
@@ -2348,6 +2357,18 @@ public class ScriptRuntime {
         return function.construct(cx, scope, args);
     }
 
+    /**
+     * This indicates whether last call of "eval" was at the top scope (i.e. "eval()")
+     * or not (i.e. "scope.eval()"), as each one has different behavior.
+     *
+     * Ideally, we should have "eval" at top scope and we use Context.FEATURE_DYNAMIC_SCOPE,
+     * but it will complex the code.
+     *
+     * The current implementation sets this value to true when "eval" is called, and
+     * false on "something.eval()"
+     */
+    private static boolean lastEvalTopCalled_;
+    
     public static Object callSpecial(Context cx, Callable fun,
                                      Scriptable thisObj,
                                      Object[] args, Scriptable scope,
@@ -2356,6 +2377,12 @@ public class ScriptRuntime {
     {
         if (callType == Node.SPECIALCALL_EVAL) {
             if (thisObj.getParentScope() == null && NativeGlobal.isEvalFunction(fun)) {
+                final boolean isNative = scope instanceof NativeCall;
+                final boolean hasFeature = cx.hasFeature(Context.FEATURE_HTMLUNIT_EVAL_LOCAL_SCOPE);
+
+                if (!lastEvalTopCalled_ && (!hasFeature || !isNative)) {
+                    scope = thisObj;
+                }
                 return evalSpecial(cx, scope, callerThis, args,
                                    filename, lineNumber);
             }
@@ -2518,6 +2545,8 @@ public class ScriptRuntime {
             return "undefined";
         if (value instanceof ScriptableObject)
         	return ((ScriptableObject) value).getTypeOf();
+        if (value instanceof Delegator)
+            return typeof(((Delegator) value).getDelegee());
         if (value instanceof Scriptable)
             return (value instanceof Callable) ? "function" : "object";
         if (value instanceof CharSequence)
@@ -2526,6 +2555,10 @@ public class ScriptRuntime {
             return "number";
         if (value instanceof Boolean)
             return "boolean";
+        if (value instanceof MemberBox)
+            return typeof(((MemberBox) value).member());
+        if (value instanceof Method)
+            return "function";
         throw errorWithClassName("msg.invalid.type", value);
     }
 
@@ -2931,6 +2964,15 @@ public class ScriptRuntime {
             if (x instanceof Wrapper && y instanceof Wrapper) {
                 return ((Wrapper)x).unwrap() == ((Wrapper)y).unwrap();
             }
+            if (x instanceof Delegator && y instanceof Delegator) {
+                return shallowEq(((Delegator)x).getDelegee(), ((Delegator)y).getDelegee());
+            }
+            if (x instanceof Delegator && ((Delegator)x).getDelegee() == y) {
+                return true;
+            }
+            if (y instanceof Delegator && ((Delegator)y).getDelegee() == x) {
+                return true;
+            }
         } else {
             warnAboutNonJSObject(x);
             return x == y;
@@ -3160,13 +3202,14 @@ public class ScriptRuntime {
                 // Don't overwrite existing def if already defined in object
                 // or prototypes of object.
                 if (!ScriptableObject.hasProperty(scope, name)) {
-                    if (isConst) {
-                        ScriptableObject.defineConstProperty(varScope, name);
-                    } else if (!evalScript) {
+                    if (!evalScript) {
                         // Global var definitions are supposed to be DONTDELETE
-                        ScriptableObject.defineProperty(
-                            varScope, name, Undefined.instance,
-                            ScriptableObject.PERMANENT);
+                        if (isConst)
+                            ScriptableObject.defineConstProperty(varScope, name);
+                        else
+                            ScriptableObject.defineProperty(
+                                varScope, name, Undefined.instance,
+                                ScriptableObject.PERMANENT);
                     } else {
                         varScope.put(name, varScope, Undefined.instance);
                     }
diff --git a/src/org/mozilla/javascript/ScriptableObject.java b/src/org/mozilla/javascript/ScriptableObject.java
index 0ab2a98..b7032d0 100644
--- a/src/org/mozilla/javascript/ScriptableObject.java
+++ b/src/org/mozilla/javascript/ScriptableObject.java
@@ -241,11 +241,28 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
                     if (Context.getContext().hasFeature(Context.FEATURE_STRICT_MODE)) {
                         // Based on TC39 ES3.1 Draft of 9-Feb-2009, 8.12.4, step 2,
                         // we should throw a TypeError in this case.
-                        throw ScriptRuntime.typeError1("msg.set.prop.no.setter", name);
+                        throw ScriptRuntime.typeError3("msg.set.prop.no.setter", name, start.getClassName(), Context.toString(value));
+                    }
+                    if (Context.getContext().hasFeature(Context.FEATURE_HTMLUNIT_ASK_OBJECT_TO_WRITE_READONLY)) {
+                        Scriptable scriptable = start;
+
+                        if (scriptable instanceof Delegator) {
+                            scriptable = ((Delegator) scriptable).getDelegee();
+                        }
+
+                        if (scriptable instanceof ScriptableObject) {
+                            boolean allowSetting = ((ScriptableObject) scriptable).isReadOnlySettable(name, value);
+                            if (!allowSetting) {
+                                return true;
+                            }
+                        }
+                        getter = null;
+                    }
+                    else {
+                        // Based on TC39 ES3.1 Draft of 9-Feb-2009, 8.12.4, step 2,
+                        // we should throw a TypeError in this case.
+                        throw ScriptRuntime.typeError3("msg.set.prop.no.setter", name, start.getClassName(), Context.toString(value));
                     }
-                    // Assignment to a property with only a getter defined. The
-                    // assignment is ignored. See bug 478047.
-                    return true;
                 }
             } else {
                 Context cx = Context.getContext();
@@ -3104,4 +3121,20 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
         }
     }
 
+    /**
+     * Special to HtmlUnit's Rhino fork.
+     *
+     * Decides what to do when setting a ReadOnly property.
+     * The SimpleScriptable can return <tt>true<tt> for allowing to value to be set, <tt>false<tt> for not allowing (ignoring),
+     * or can simply throw {@link ScriptRuntime#typeError3(String, String, String, String)} with
+     * "msg.set.prop.no.setter", name, this.getClassName() and Context.toString(value).
+     *
+     * By default, this method returns <tt>true</tt>
+     * @param name the property name
+     * @param value the value
+     * @return <tt>true<tt> for allowing setting the value, <tt>false</tt> for ignoring the setting, or we can throw an exception
+     */
+    protected boolean isReadOnlySettable(final String name, final Object value) {
+        return true;
+    }
 }
diff --git a/src/org/mozilla/javascript/resources/Messages.properties b/src/org/mozilla/javascript/resources/Messages.properties
index 35e4e52..c03915c 100644
--- a/src/org/mozilla/javascript/resources/Messages.properties
+++ b/src/org/mozilla/javascript/resources/Messages.properties
@@ -536,7 +536,7 @@ msg.prop.not.found =\
     Property {0} not found.
 
 msg.set.prop.no.setter =\
-    Cannot set property {0} that has only a getter.
+    Cannot set property [{1}].{0} that has only a getter to {2}.
 
 msg.invalid.type =\
     Invalid JavaScript value of type {0}
