]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - dfg/DFGCapabilities.h
JavaScriptCore-1218.tar.gz
[apple/javascriptcore.git] / dfg / DFGCapabilities.h
index b807979babb962f8762ac3dd36b88d7a9de0f860..a9dc51325c326cdee65731b64c5b16f640e1eee1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,6 +27,7 @@
 #define DFGCapabilities_h
 
 #include "Intrinsic.h"
+#include "DFGCommon.h"
 #include "DFGNode.h"
 #include "Executable.h"
 #include "Options.h"
@@ -38,36 +39,50 @@ namespace JSC { namespace DFG {
 #if ENABLE(DFG_JIT)
 // Fast check functions; if they return true it is still necessary to
 // check opcodes.
-inline bool mightCompileEval(CodeBlock* codeBlock)
-{
-    return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
-}
-inline bool mightCompileProgram(CodeBlock* codeBlock)
-{
-    return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
-}
-inline bool mightCompileFunctionForCall(CodeBlock* codeBlock)
-{
-    return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
-}
-inline bool mightCompileFunctionForConstruct(CodeBlock* codeBlock)
-{
-    return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
-}
+bool mightCompileEval(CodeBlock*);
+bool mightCompileProgram(CodeBlock*);
+bool mightCompileFunctionForCall(CodeBlock*);
+bool mightCompileFunctionForConstruct(CodeBlock*);
+bool mightInlineFunctionForCall(CodeBlock*);
+bool mightInlineFunctionForClosureCall(CodeBlock*);
+bool mightInlineFunctionForConstruct(CodeBlock*);
 
-inline bool mightInlineFunctionForCall(CodeBlock* codeBlock)
-{
-    return codeBlock->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount
-        && !codeBlock->ownerExecutable()->needsActivation();
-}
-inline bool mightInlineFunctionForConstruct(CodeBlock* codeBlock)
+// Opcode checking.
+inline bool canInlineResolveOperations(ResolveOperations* operations)
 {
-    return codeBlock->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount
-        && !codeBlock->ownerExecutable()->needsActivation();
+    for (unsigned i = 0; i < operations->size(); i++) {
+        switch (operations->data()[i].m_operation) {
+        case ResolveOperation::ReturnGlobalObjectAsBase:
+        case ResolveOperation::SetBaseToGlobal:
+        case ResolveOperation::SetBaseToUndefined:
+        case ResolveOperation::GetAndReturnGlobalProperty:
+        case ResolveOperation::GetAndReturnGlobalVar:
+        case ResolveOperation::GetAndReturnGlobalVarWatchable:
+        case ResolveOperation::SkipScopes:
+        case ResolveOperation::SetBaseToScope:
+        case ResolveOperation::ReturnScopeAsBase:
+        case ResolveOperation::GetAndReturnScopedVar:
+            continue;
+
+        case ResolveOperation::Fail:
+            // Fall-back resolves don't know how to deal with the ExecState* having a different
+            // global object (and scope) than the inlined code that is invoking that resolve.
+            return false;
+
+        case ResolveOperation::SkipTopScopeNode:
+            // We don't inline code blocks that create activations. Creation of
+            // activations is the only thing that leads to SkipTopScopeNode.
+            return false;
+
+        case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope:
+            // This would be easy to support in all cases.
+            return false;
+        }
+    }
+    return true;
 }
 
-// Opcode checking.
-inline bool canCompileOpcode(OpcodeID opcodeID)
+inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instruction*)
 {
     switch (opcodeID) {
     case op_enter:
@@ -80,10 +95,8 @@ inline bool canCompileOpcode(OpcodeID opcodeID)
     case op_rshift:
     case op_lshift:
     case op_urshift:
-    case op_pre_inc:
-    case op_post_inc:
-    case op_pre_dec:
-    case op_post_dec:
+    case op_inc:
+    case op_dec:
     case op_add:
     case op_sub:
     case op_negate:
@@ -115,21 +128,21 @@ inline bool canCompileOpcode(OpcodeID opcodeID)
     case op_nstricteq:
     case op_get_by_val:
     case op_put_by_val:
-    case op_method_check:
-    case op_get_scoped_var:
-    case op_put_scoped_var:
     case op_get_by_id:
+    case op_get_by_id_out_of_line:
+    case op_get_array_length:
     case op_put_by_id:
+    case op_put_by_id_out_of_line:
     case op_put_by_id_transition_direct:
+    case op_put_by_id_transition_direct_out_of_line:
     case op_put_by_id_transition_normal:
-    case op_get_global_var:
-    case op_put_global_var:
+    case op_put_by_id_transition_normal_out_of_line:
+    case op_init_global_const_nop:
+    case op_init_global_const:
+    case op_init_global_const_check:
     case op_jmp:
-    case op_loop:
     case op_jtrue:
     case op_jfalse:
-    case op_loop_if_true:
-    case op_loop_if_false:
     case op_jeq_null:
     case op_jneq_null:
     case op_jless:
@@ -141,72 +154,110 @@ inline bool canCompileOpcode(OpcodeID opcodeID)
     case op_jngreater:
     case op_jngreatereq:
     case op_loop_hint:
-    case op_loop_if_less:
-    case op_loop_if_lesseq:
-    case op_loop_if_greater:
-    case op_loop_if_greatereq:
     case op_ret:
     case op_end:
     case op_call_put_result:
-    case op_resolve:
-    case op_resolve_base:
-    case op_resolve_global:
     case op_new_object:
     case op_new_array:
+    case op_new_array_with_size:
     case op_new_array_buffer:
     case op_strcat:
     case op_to_primitive:
     case op_throw:
-    case op_throw_reference_error:
+    case op_throw_static_error:
     case op_call:
     case op_construct:
     case op_new_regexp: 
     case op_init_lazy_reg:
     case op_create_activation:
     case op_tear_off_activation:
+    case op_create_arguments:
+    case op_tear_off_arguments:
     case op_new_func:
     case op_new_func_exp:
-        return true;
+    case op_get_argument_by_val:
+    case op_get_arguments_length:
+    case op_jneq_ptr:
+    case op_put_to_base_variable:
+    case op_put_to_base:
+    case op_typeof:
+    case op_to_number:
+        return CanCompile;
         
+    case op_call_varargs:
+        return MayInline;
+
+    case op_resolve:
+    case op_resolve_global_property:
+    case op_resolve_global_var:
+    case op_resolve_scoped_var:
+    case op_resolve_scoped_var_on_top_scope:
+    case op_resolve_scoped_var_with_top_scope_check:
+        return CanCompile;
+
+    case op_get_scoped_var:
+    case op_put_scoped_var:
+        return CanCompile;
+
+    case op_resolve_base_to_global:
+    case op_resolve_base_to_global_dynamic:
+    case op_resolve_base_to_scope:
+    case op_resolve_base_to_scope_with_top_scope_check:
+    case op_resolve_base:
+    case op_resolve_with_base:
+    case op_resolve_with_this:
+        return CanCompile;
+
     default:
-        return false;
+        return CannotCompile;
     }
 }
 
-inline bool canInlineOpcode(OpcodeID opcodeID)
+inline bool canInlineOpcode(OpcodeID opcodeID, CodeBlock* codeBlock, Instruction* pc)
 {
     switch (opcodeID) {
-        
-    // These opcodes would be easy to support with inlining, but we currently don't do it.
-    // The issue is that the scope chain will not be set correctly.
-    case op_get_scoped_var:
-    case op_put_scoped_var:
     case op_resolve:
+    case op_resolve_global_property:
+    case op_resolve_global_var:
+    case op_resolve_scoped_var:
+    case op_resolve_scoped_var_on_top_scope:
+    case op_resolve_scoped_var_with_top_scope_check:
+        return canInlineResolveOperations(pc[3].u.resolveOperations);
+
+    case op_resolve_base_to_global:
+    case op_resolve_base_to_global_dynamic:
+    case op_resolve_base_to_scope:
+    case op_resolve_base_to_scope_with_top_scope_check:
     case op_resolve_base:
-    case op_resolve_global:
-        
-    // Constant buffers aren't copied correctly. This is easy to fix, but for
-    // now we just disable inlining for functions that use them.
-    case op_new_array_buffer:
-        
+    case op_resolve_with_base:
+    case op_resolve_with_this:
+        return canInlineResolveOperations(pc[4].u.resolveOperations);
+
+    case op_get_scoped_var:
+    case op_put_scoped_var:
+        return !codeBlock->needsFullScopeChain();
+
     // Inlining doesn't correctly remap regular expression operands.
     case op_new_regexp:
-        return false;
         
     // We don't support inlining code that creates activations or has nested functions.
-    case op_init_lazy_reg:
     case op_create_activation:
     case op_tear_off_activation:
     case op_new_func:
     case op_new_func_exp:
         return false;
         
+    // Inlining supports op_call_varargs if it's a call that just forwards the caller's
+    // arguments.
+    case op_call_varargs:
+        return codeBlock->usesArguments() && pc[3].u.operand == codeBlock->argumentsRegister();
+        
     default:
-        return canCompileOpcode(opcodeID);
+        return canCompileOpcode(opcodeID, codeBlock, pc) == CanCompile;
     }
 }
 
-bool canCompileOpcodes(CodeBlock*);
+CapabilityLevel canCompileOpcodes(CodeBlock*);
 bool canInlineOpcodes(CodeBlock*);
 #else // ENABLE(DFG_JIT)
 inline bool mightCompileEval(CodeBlock*) { return false; }
@@ -214,32 +265,45 @@ inline bool mightCompileProgram(CodeBlock*) { return false; }
 inline bool mightCompileFunctionForCall(CodeBlock*) { return false; }
 inline bool mightCompileFunctionForConstruct(CodeBlock*) { return false; }
 inline bool mightInlineFunctionForCall(CodeBlock*) { return false; }
+inline bool mightInlineFunctionForClosureCall(CodeBlock*) { return false; }
 inline bool mightInlineFunctionForConstruct(CodeBlock*) { return false; }
 
-inline bool canCompileOpcode(OpcodeID) { return false; }
-inline bool canInlineOpcode(OpcodeID) { return false; }
-inline bool canCompileOpcodes(CodeBlock*) { return false; }
+inline CapabilityLevel canCompileOpcode(OpcodeID, CodeBlock*, Instruction*) { return CannotCompile; }
+inline bool canInlineOpcode(OpcodeID, CodeBlock*, Instruction*) { return false; }
+inline CapabilityLevel canCompileOpcodes(CodeBlock*) { return CannotCompile; }
 inline bool canInlineOpcodes(CodeBlock*) { return false; }
 #endif // ENABLE(DFG_JIT)
 
-inline bool canCompileEval(CodeBlock* codeBlock)
+inline CapabilityLevel canCompileEval(CodeBlock* codeBlock)
 {
-    return mightCompileEval(codeBlock) && canCompileOpcodes(codeBlock);
+    if (!mightCompileEval(codeBlock))
+        return CannotCompile;
+    
+    return canCompileOpcodes(codeBlock);
 }
 
-inline bool canCompileProgram(CodeBlock* codeBlock)
+inline CapabilityLevel canCompileProgram(CodeBlock* codeBlock)
 {
-    return mightCompileProgram(codeBlock) && canCompileOpcodes(codeBlock);
+    if (!mightCompileProgram(codeBlock))
+        return CannotCompile;
+    
+    return canCompileOpcodes(codeBlock);
 }
 
-inline bool canCompileFunctionForCall(CodeBlock* codeBlock)
+inline CapabilityLevel canCompileFunctionForCall(CodeBlock* codeBlock)
 {
-    return mightCompileFunctionForCall(codeBlock) && canCompileOpcodes(codeBlock);
+    if (!mightCompileFunctionForCall(codeBlock))
+        return CannotCompile;
+    
+    return canCompileOpcodes(codeBlock);
 }
 
-inline bool canCompileFunctionForConstruct(CodeBlock* codeBlock)
+inline CapabilityLevel canCompileFunctionForConstruct(CodeBlock* codeBlock)
 {
-    return mightCompileFunctionForConstruct(codeBlock) && canCompileOpcodes(codeBlock);
+    if (!mightCompileFunctionForConstruct(codeBlock))
+        return CannotCompile;
+    
+    return canCompileOpcodes(codeBlock);
 }
 
 inline bool canInlineFunctionForCall(CodeBlock* codeBlock)
@@ -247,6 +311,11 @@ inline bool canInlineFunctionForCall(CodeBlock* codeBlock)
     return mightInlineFunctionForCall(codeBlock) && canInlineOpcodes(codeBlock);
 }
 
+inline bool canInlineFunctionForClosureCall(CodeBlock* codeBlock)
+{
+    return mightInlineFunctionForClosureCall(codeBlock) && canInlineOpcodes(codeBlock);
+}
+
 inline bool canInlineFunctionForConstruct(CodeBlock* codeBlock)
 {
     return mightInlineFunctionForConstruct(codeBlock) && canInlineOpcodes(codeBlock);
@@ -260,8 +329,12 @@ inline bool mightInlineFunctionFor(CodeBlock* codeBlock, CodeSpecializationKind
     return mightInlineFunctionForConstruct(codeBlock);
 }
 
-inline bool canInlineFunctionFor(CodeBlock* codeBlock, CodeSpecializationKind kind)
+inline bool canInlineFunctionFor(CodeBlock* codeBlock, CodeSpecializationKind kind, bool isClosureCall)
 {
+    if (isClosureCall) {
+        ASSERT(kind == CodeForCall);
+        return canInlineFunctionForClosureCall(codeBlock);
+    }
     if (kind == CodeForCall)
         return canInlineFunctionForCall(codeBlock);
     ASSERT(kind == CodeForConstruct);