1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_COMPILER_H_ 29 #define V8_COMPILER_H_ 30 31 #include "allocation.h" 32 #include "ast.h" 33 #include "zone.h" 34 35 namespace v8 { 36 namespace internal { 37 38 class ScriptDataImpl; 39 40 // CompilationInfo encapsulates some information known at compile time. It 41 // is constructed based on the resources available at compile-time. 42 class CompilationInfo BASE_EMBEDDED { 43 public: 44 explicit CompilationInfo(Handle<Script> script); 45 explicit CompilationInfo(Handle<SharedFunctionInfo> shared_info); 46 explicit CompilationInfo(Handle<JSFunction> closure); 47 isolate()48 Isolate* isolate() { 49 ASSERT(Isolate::Current() == isolate_); 50 return isolate_; 51 } is_lazy()52 bool is_lazy() const { return IsLazy::decode(flags_); } is_eval()53 bool is_eval() const { return IsEval::decode(flags_); } is_global()54 bool is_global() const { return IsGlobal::decode(flags_); } is_classic_mode()55 bool is_classic_mode() const { return language_mode() == CLASSIC_MODE; } is_extended_mode()56 bool is_extended_mode() const { return language_mode() == EXTENDED_MODE; } language_mode()57 LanguageMode language_mode() const { 58 return LanguageModeField::decode(flags_); 59 } is_in_loop()60 bool is_in_loop() const { return IsInLoop::decode(flags_); } function()61 FunctionLiteral* function() const { return function_; } scope()62 Scope* scope() const { return scope_; } global_scope()63 Scope* global_scope() const { return global_scope_; } code()64 Handle<Code> code() const { return code_; } closure()65 Handle<JSFunction> closure() const { return closure_; } shared_info()66 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; } script()67 Handle<Script> script() const { return script_; } extension()68 v8::Extension* extension() const { return extension_; } pre_parse_data()69 ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; } calling_context()70 Handle<Context> calling_context() const { return calling_context_; } osr_ast_id()71 int osr_ast_id() const { return osr_ast_id_; } 72 MarkAsEval()73 void MarkAsEval() { 74 ASSERT(!is_lazy()); 75 flags_ |= IsEval::encode(true); 76 } MarkAsGlobal()77 void MarkAsGlobal() { 78 ASSERT(!is_lazy()); 79 flags_ |= IsGlobal::encode(true); 80 } SetLanguageMode(LanguageMode language_mode)81 void SetLanguageMode(LanguageMode language_mode) { 82 ASSERT(this->language_mode() == CLASSIC_MODE || 83 this->language_mode() == language_mode || 84 language_mode == EXTENDED_MODE); 85 flags_ = LanguageModeField::update(flags_, language_mode); 86 } MarkAsInLoop()87 void MarkAsInLoop() { 88 ASSERT(is_lazy()); 89 flags_ |= IsInLoop::encode(true); 90 } MarkAsNative()91 void MarkAsNative() { 92 flags_ |= IsNative::encode(true); 93 } is_native()94 bool is_native() const { 95 return IsNative::decode(flags_); 96 } SetFunction(FunctionLiteral * literal)97 void SetFunction(FunctionLiteral* literal) { 98 ASSERT(function_ == NULL); 99 function_ = literal; 100 } SetScope(Scope * scope)101 void SetScope(Scope* scope) { 102 ASSERT(scope_ == NULL); 103 scope_ = scope; 104 } SetGlobalScope(Scope * global_scope)105 void SetGlobalScope(Scope* global_scope) { 106 ASSERT(global_scope_ == NULL); 107 global_scope_ = global_scope; 108 } SetCode(Handle<Code> code)109 void SetCode(Handle<Code> code) { code_ = code; } SetExtension(v8::Extension * extension)110 void SetExtension(v8::Extension* extension) { 111 ASSERT(!is_lazy()); 112 extension_ = extension; 113 } SetPreParseData(ScriptDataImpl * pre_parse_data)114 void SetPreParseData(ScriptDataImpl* pre_parse_data) { 115 ASSERT(!is_lazy()); 116 pre_parse_data_ = pre_parse_data; 117 } SetCallingContext(Handle<Context> context)118 void SetCallingContext(Handle<Context> context) { 119 ASSERT(is_eval()); 120 calling_context_ = context; 121 } SetOsrAstId(int osr_ast_id)122 void SetOsrAstId(int osr_ast_id) { 123 ASSERT(IsOptimizing()); 124 osr_ast_id_ = osr_ast_id; 125 } MarkCompilingForDebugging(Handle<Code> current_code)126 void MarkCompilingForDebugging(Handle<Code> current_code) { 127 ASSERT(mode_ != OPTIMIZE); 128 ASSERT(current_code->kind() == Code::FUNCTION); 129 flags_ |= IsCompilingForDebugging::encode(true); 130 if (current_code->is_compiled_optimizable()) { 131 EnableDeoptimizationSupport(); 132 } else { 133 mode_ = CompilationInfo::NONOPT; 134 } 135 } IsCompilingForDebugging()136 bool IsCompilingForDebugging() { 137 return IsCompilingForDebugging::decode(flags_); 138 } 139 has_global_object()140 bool has_global_object() const { 141 return !closure().is_null() && (closure()->context()->global() != NULL); 142 } 143 global_object()144 GlobalObject* global_object() const { 145 return has_global_object() ? closure()->context()->global() : NULL; 146 } 147 148 // Accessors for the different compilation modes. IsOptimizing()149 bool IsOptimizing() const { return mode_ == OPTIMIZE; } IsOptimizable()150 bool IsOptimizable() const { return mode_ == BASE; } SetOptimizing(int osr_ast_id)151 void SetOptimizing(int osr_ast_id) { 152 SetMode(OPTIMIZE); 153 osr_ast_id_ = osr_ast_id; 154 } 155 void DisableOptimization(); 156 157 // Deoptimization support. HasDeoptimizationSupport()158 bool HasDeoptimizationSupport() const { 159 return SupportsDeoptimization::decode(flags_); 160 } EnableDeoptimizationSupport()161 void EnableDeoptimizationSupport() { 162 ASSERT(IsOptimizable()); 163 flags_ |= SupportsDeoptimization::encode(true); 164 } 165 166 // Determines whether or not to insert a self-optimization header. 167 bool ShouldSelfOptimize(); 168 169 // Disable all optimization attempts of this info for the rest of the 170 // current compilation pipeline. 171 void AbortOptimization(); 172 173 private: 174 Isolate* isolate_; 175 176 // Compilation mode. 177 // BASE is generated by the full codegen, optionally prepared for bailouts. 178 // OPTIMIZE is optimized code generated by the Hydrogen-based backend. 179 // NONOPT is generated by the full codegen and is not prepared for 180 // recompilation/bailouts. These functions are never recompiled. 181 enum Mode { 182 BASE, 183 OPTIMIZE, 184 NONOPT 185 }; 186 CompilationInfo()187 CompilationInfo() : function_(NULL) {} 188 Initialize(Mode mode)189 void Initialize(Mode mode) { 190 mode_ = V8::UseCrankshaft() ? mode : NONOPT; 191 ASSERT(!script_.is_null()); 192 if (script_->type()->value() == Script::TYPE_NATIVE) { 193 MarkAsNative(); 194 } 195 if (!shared_info_.is_null()) { 196 ASSERT(language_mode() == CLASSIC_MODE); 197 SetLanguageMode(shared_info_->language_mode()); 198 } 199 } 200 SetMode(Mode mode)201 void SetMode(Mode mode) { 202 ASSERT(V8::UseCrankshaft()); 203 mode_ = mode; 204 } 205 206 // Flags using template class BitField<type, start, length>. All are 207 // false by default. 208 // 209 // Compilation is either eager or lazy. 210 class IsLazy: public BitField<bool, 0, 1> {}; 211 // Flags that can be set for eager compilation. 212 class IsEval: public BitField<bool, 1, 1> {}; 213 class IsGlobal: public BitField<bool, 2, 1> {}; 214 // Flags that can be set for lazy compilation. 215 class IsInLoop: public BitField<bool, 3, 1> {}; 216 // Strict mode - used in eager compilation. 217 class LanguageModeField: public BitField<LanguageMode, 4, 2> {}; 218 // Is this a function from our natives. 219 class IsNative: public BitField<bool, 6, 1> {}; 220 // Is this code being compiled with support for deoptimization.. 221 class SupportsDeoptimization: public BitField<bool, 7, 1> {}; 222 // If compiling for debugging produce just full code matching the 223 // initial mode setting. 224 class IsCompilingForDebugging: public BitField<bool, 8, 1> {}; 225 226 227 unsigned flags_; 228 229 // Fields filled in by the compilation pipeline. 230 // AST filled in by the parser. 231 FunctionLiteral* function_; 232 // The scope of the function literal as a convenience. Set to indicate 233 // that scopes have been analyzed. 234 Scope* scope_; 235 // The global scope provided as a convenience. 236 Scope* global_scope_; 237 // The compiled code. 238 Handle<Code> code_; 239 240 // Possible initial inputs to the compilation process. 241 Handle<JSFunction> closure_; 242 Handle<SharedFunctionInfo> shared_info_; 243 Handle<Script> script_; 244 245 // Fields possibly needed for eager compilation, NULL by default. 246 v8::Extension* extension_; 247 ScriptDataImpl* pre_parse_data_; 248 249 // The context of the caller is needed for eval code, and will be a null 250 // handle otherwise. 251 Handle<Context> calling_context_; 252 253 // Compilation mode flag and whether deoptimization is allowed. 254 Mode mode_; 255 int osr_ast_id_; 256 257 DISALLOW_COPY_AND_ASSIGN(CompilationInfo); 258 }; 259 260 261 // The V8 compiler 262 // 263 // General strategy: Source code is translated into an anonymous function w/o 264 // parameters which then can be executed. If the source code contains other 265 // functions, they will be compiled and allocated as part of the compilation 266 // of the source code. 267 268 // Please note this interface returns shared function infos. This means you 269 // need to call Factory::NewFunctionFromSharedFunctionInfo before you have a 270 // real function with a context. 271 272 class Compiler : public AllStatic { 273 public: 274 // Default maximum number of function optimization attempts before we 275 // give up. 276 static const int kDefaultMaxOptCount = 10; 277 278 static const int kMaxInliningLevels = 3; 279 280 // Call count before primitive functions trigger their own optimization. 281 static const int kCallsUntilPrimitiveOpt = 200; 282 283 // All routines return a SharedFunctionInfo. 284 // If an error occurs an exception is raised and the return handle 285 // contains NULL. 286 287 // Compile a String source within a context. 288 static Handle<SharedFunctionInfo> Compile(Handle<String> source, 289 Handle<Object> script_name, 290 int line_offset, 291 int column_offset, 292 v8::Extension* extension, 293 ScriptDataImpl* pre_data, 294 Handle<Object> script_data, 295 NativesFlag is_natives_code); 296 297 // Compile a String source within a context for Eval. 298 static Handle<SharedFunctionInfo> CompileEval(Handle<String> source, 299 Handle<Context> context, 300 bool is_global, 301 LanguageMode language_mode, 302 int scope_position); 303 304 // Compile from function info (used for lazy compilation). Returns true on 305 // success and false if the compilation resulted in a stack overflow. 306 static bool CompileLazy(CompilationInfo* info); 307 308 // Compile a shared function info object (the function is possibly lazily 309 // compiled). 310 static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node, 311 Handle<Script> script); 312 313 // Set the function info for a newly compiled function. 314 static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info, 315 FunctionLiteral* lit, 316 bool is_toplevel, 317 Handle<Script> script); 318 319 #ifdef ENABLE_DEBUGGER_SUPPORT 320 static bool MakeCodeForLiveEdit(CompilationInfo* info); 321 #endif 322 323 static void RecordFunctionCompilation(Logger::LogEventsAndTags tag, 324 CompilationInfo* info, 325 Handle<SharedFunctionInfo> shared); 326 }; 327 328 329 } } // namespace v8::internal 330 331 #endif // V8_COMPILER_H_ 332