[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 75734 e2ac5bec56fb81619893dd85021b0a12f8910a02
parent 75733 e5efb8c97426a6ebbed4db1bc1239f418b25802a
child 75735 03aa9eb2a8fc9deea9fed340ad8ad30926989c1b
push id235
push userbzbarsky@mozilla.com
push dateTue, 27 Sep 2011 17:13:04 +0000
treeherdermozilla-beta@2d1e082d176a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs651209
milestone6.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
[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;