[INFER] Don't inline calls from heavyweight or eval scripts, bug 651209.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 20 Apr 2011 07:06:59 -0700
changeset 74964 e2ac5bec56fb81619893dd85021b0a12f8910a02
parent 74963 e5efb8c97426a6ebbed4db1bc1239f418b25802a
child 74965 03aa9eb2a8fc9deea9fed340ad8ad30926989c1b
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs651209
milestone6.0a1
[INFER] Don't inline calls from heavyweight or eval scripts, bug 651209.
js/src/jit-test/tests/jaeger/inline/bug651209.js
js/src/jsobj.cpp
js/src/jsscript.h
js/src/methodjit/Compiler.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/inline/bug651209.js
@@ -0,0 +1,11 @@
+var i = 0;
+try { test(); } catch (e) { }
+function test() {
+  var jstop  = 900;
+  var code = '';
+  code+=createCode(i);
+  eval();
+}
+function createCode(i) {
+  jstop+= +  +  + i + " string.';";
+}
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1088,38 +1088,42 @@ class EvalScriptGuard
         str_(str),
         script_(NULL) {
         bucket_ = EvalCacheHash(cx, str);
     }
 
     ~EvalScriptGuard() {
         if (script_) {
             js_CallDestroyScriptHook(cx_, script_);
+            script_->isActiveEval = false;
             script_->isCachedEval = true;
             script_->u.nextToGC = *bucket_;
             *bucket_ = script_;
 #ifdef CHECK_SCRIPT_OWNER
             script_->owner = NULL;
 #endif
         }
     }
 
     void lookupInEvalCache(JSStackFrame *caller, uintN staticLevel,
                            JSPrincipals *principals, JSObject &scopeobj) {
         if (JSScript *found = EvalCacheLookup(cx_, str_, caller, staticLevel,
                                               principals, scopeobj, bucket_)) {
             js_CallNewScriptHook(cx_, found, NULL);
             script_ = found;
+            script_->isCachedEval = false;
+            script_->isActiveEval = true;
         }
     }
 
     void setNewScript(JSScript *script) {
         /* NewScriptFromCG has already called js_CallNewScriptHook. */
         JS_ASSERT(!script_ && script);
         script_ = script;
+        script_->isActiveEval = true;
     }
 
     bool foundScript() {
         return !!script_;
     }
 
     JSScript *script() const {
         JS_ASSERT(script_);
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -451,17 +451,18 @@ struct JSScript {
     bool            strictModeCode:1; /* code is in strict mode */
     bool            compileAndGo:1;   /* script was compiled with TCF_COMPILE_N_GO */
     bool            usesEval:1;       /* script uses eval() */
     bool            usesArguments:1;  /* script uses arguments */
     bool            warnedAboutTwoArgumentEval:1; /* have warned about use of
                                                      obsolete eval(s, o) in
                                                      this script */
     bool            hasSingletons:1;  /* script has singleton objects */
-    bool            isCachedEval:1;   /* script came from eval() */
+    bool            isActiveEval:1;   /* script came from eval(), and is still active */
+    bool            isCachedEval:1;   /* script came from eval(), and is in eval cache */
     bool            isUncachedEval:1; /* script came from EvaluateScript */
     bool            calledWithNew:1;  /* script has been called using 'new' */
     bool            analyzed:1;       /* script has been analyzed by type inference */
 #ifdef JS_METHODJIT
     bool            debugMode:1;      /* script was compiled in debug mode */
     bool            singleStepMode:1; /* compile script in single-step mode */
     bool            inlineParents:1;  /* script may be inlined in other frames */
     bool            failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -3877,16 +3877,24 @@ mjit::Compiler::inlineScriptedFunction(u
 
     /* :XXX: Not doing inlining yet when calling 'new' or calling from 'new'. */
     if (isConstructing || callingNew)
         return Compile_InlineAbort;
 
     if (applyTricks == LazyArgsObj)
         return Compile_InlineAbort;
 
+    /* Don't inline from functions which could have a non-global scope object. */
+    if (!outerScript->compileAndGo ||
+        (outerScript->fun && outerScript->fun->getParent() != globalObj) ||
+        (outerScript->fun && outerScript->fun->isHeavyweight()) ||
+        outerScript->isActiveEval) {
+        return Compile_InlineAbort;
+    }
+
     FrameEntry *origCallee = frame.peek(-((int)argc + 2));
     FrameEntry *origThis = frame.peek(-((int)argc + 1));
 
     types::TypeSet *types = frame.extra(origCallee).types;
     if (!types || types->getKnownTypeTag(cx) != JSVAL_TYPE_OBJECT)
         return Compile_InlineAbort;
 
     /*
@@ -3909,34 +3917,33 @@ mjit::Compiler::inlineScriptedFunction(u
 
     /*
      * Scan each of the possible callees for other conditions precluding
      * inlining. We only inline at a call site if all callees are inlineable.
      */
     unsigned count = types->getObjectCount();
     for (unsigned i = 0; i < count; i++) {
         types::TypeObject *object = types->getObject(i);
-        JS_ASSERT(object);  /* Hash case for types->objectSet not possible here. */
+        if (!object)
+            continue;
 
         if (!object->singleton || !object->singleton->isFunction())
             return Compile_InlineAbort;
 
         JSFunction *fun = object->singleton->getFunctionPrivate();
         if (!fun->isInterpreted())
             return Compile_InlineAbort;
         JSScript *script = fun->script();
 
         /*
          * The outer and inner scripts must have the same scope. This only
          * allows us to inline calls between non-inner functions. Also check
          * for consistent strictness between the functions.
          */
-        if (!outerScript->compileAndGo ||
-            (outerScript->fun && outerScript->fun->getParent() != globalObj) ||
-            !script->compileAndGo ||
+        if (!script->compileAndGo ||
             fun->getParent() != globalObj ||
             outerScript->strictModeCode != script->strictModeCode) {
             return Compile_InlineAbort;
         }
 
         /* We can't cope with inlining recursive functions yet. */
         ActiveFrame *checka = a;
         while (checka) {
@@ -4003,17 +4010,18 @@ mjit::Compiler::inlineScriptedFunction(u
     bool returnSet = false;
     AnyRegisterID returnRegister;
     Registers returnParentRegs = 0;
 
     Vector<Jump, 4, CompilerAllocPolicy> returnJumps(CompilerAllocPolicy(cx, *this));
 
     for (unsigned i = 0; i < count; i++) {
         types::TypeObject *object = types->getObject(i);
-        JS_ASSERT(object);
+        if (!object)
+            continue;
 
         JSFunction *fun = object->singleton->getFunctionPrivate();
 
         CompileStatus status;
 
         status = pushActiveFrame(fun->script(), argc);
         if (status != Compile_Okay)
             return status;