1 // Copyright 2011 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 "ast.h" 32 #include "frame-element.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 48 Isolate* isolate() { 49 ASSERT(Isolate::Current() == isolate_); 50 return isolate_; 51 } 52 bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; } 53 bool is_eval() const { return (flags_ & IsEval::mask()) != 0; } 54 bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; } 55 bool is_strict_mode() const { return (flags_ & IsStrictMode::mask()) != 0; } 56 bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; } 57 FunctionLiteral* function() const { return function_; } 58 Scope* scope() const { return scope_; } 59 Handle<Code> code() const { return code_; } 60 Handle<JSFunction> closure() const { return closure_; } 61 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; } 62 Handle<Script> script() const { return script_; } 63 v8::Extension* extension() const { return extension_; } 64 ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; } 65 Handle<Context> calling_context() const { return calling_context_; } 66 int osr_ast_id() const { return osr_ast_id_; } 67 68 void MarkAsEval() { 69 ASSERT(!is_lazy()); 70 flags_ |= IsEval::encode(true); 71 } 72 void MarkAsGlobal() { 73 ASSERT(!is_lazy()); 74 flags_ |= IsGlobal::encode(true); 75 } 76 void MarkAsStrictMode() { 77 flags_ |= IsStrictMode::encode(true); 78 } 79 StrictModeFlag StrictMode() { 80 return is_strict_mode() ? kStrictMode : kNonStrictMode; 81 } 82 void MarkAsInLoop() { 83 ASSERT(is_lazy()); 84 flags_ |= IsInLoop::encode(true); 85 } 86 void MarkAsNative() { 87 flags_ |= IsNative::encode(true); 88 } 89 bool is_native() const { 90 return IsNative::decode(flags_); 91 } 92 void SetFunction(FunctionLiteral* literal) { 93 ASSERT(function_ == NULL); 94 function_ = literal; 95 } 96 void SetScope(Scope* scope) { 97 ASSERT(scope_ == NULL); 98 scope_ = scope; 99 } 100 void SetCode(Handle<Code> code) { code_ = code; } 101 void SetExtension(v8::Extension* extension) { 102 ASSERT(!is_lazy()); 103 extension_ = extension; 104 } 105 void SetPreParseData(ScriptDataImpl* pre_parse_data) { 106 ASSERT(!is_lazy()); 107 pre_parse_data_ = pre_parse_data; 108 } 109 void SetCallingContext(Handle<Context> context) { 110 ASSERT(is_eval()); 111 calling_context_ = context; 112 } 113 void SetOsrAstId(int osr_ast_id) { 114 ASSERT(IsOptimizing()); 115 osr_ast_id_ = osr_ast_id; 116 } 117 118 bool has_global_object() const { 119 return !closure().is_null() && (closure()->context()->global() != NULL); 120 } 121 122 GlobalObject* global_object() const { 123 return has_global_object() ? closure()->context()->global() : NULL; 124 } 125 126 // Accessors for the different compilation modes. 127 bool IsOptimizing() const { return mode_ == OPTIMIZE; } 128 bool IsOptimizable() const { return mode_ == BASE; } 129 void SetOptimizing(int osr_ast_id) { 130 SetMode(OPTIMIZE); 131 osr_ast_id_ = osr_ast_id; 132 } 133 void DisableOptimization(); 134 135 // Deoptimization support. 136 bool HasDeoptimizationSupport() const { return supports_deoptimization_; } 137 void EnableDeoptimizationSupport() { 138 ASSERT(IsOptimizable()); 139 supports_deoptimization_ = true; 140 } 141 142 // Determine whether or not we can adaptively optimize. 143 bool AllowOptimize() { 144 return V8::UseCrankshaft() && !closure_.is_null(); 145 } 146 147 private: 148 Isolate* isolate_; 149 150 // Compilation mode. 151 // BASE is generated by the full codegen, optionally prepared for bailouts. 152 // OPTIMIZE is optimized code generated by the Hydrogen-based backend. 153 // NONOPT is generated by the full codegen or the classic backend 154 // and is not prepared for recompilation/bailouts. These functions 155 // are never recompiled. 156 enum Mode { 157 BASE, 158 OPTIMIZE, 159 NONOPT 160 }; 161 162 CompilationInfo() : function_(NULL) {} 163 164 void Initialize(Mode mode) { 165 mode_ = V8::UseCrankshaft() ? mode : NONOPT; 166 if (script_->type()->value() == Script::TYPE_NATIVE) { 167 MarkAsNative(); 168 } 169 if (!shared_info_.is_null() && shared_info_->strict_mode()) { 170 MarkAsStrictMode(); 171 } 172 } 173 174 void SetMode(Mode mode) { 175 ASSERT(V8::UseCrankshaft()); 176 mode_ = mode; 177 } 178 179 // Flags using template class BitField<type, start, length>. All are 180 // false by default. 181 // 182 // Compilation is either eager or lazy. 183 class IsLazy: public BitField<bool, 0, 1> {}; 184 // Flags that can be set for eager compilation. 185 class IsEval: public BitField<bool, 1, 1> {}; 186 class IsGlobal: public BitField<bool, 2, 1> {}; 187 // Flags that can be set for lazy compilation. 188 class IsInLoop: public BitField<bool, 3, 1> {}; 189 // Strict mode - used in eager compilation. 190 class IsStrictMode: public BitField<bool, 4, 1> {}; 191 // Is this a function from our natives. 192 class IsNative: public BitField<bool, 6, 1> {}; 193 194 unsigned flags_; 195 196 // Fields filled in by the compilation pipeline. 197 // AST filled in by the parser. 198 FunctionLiteral* function_; 199 // The scope of the function literal as a convenience. Set to indicate 200 // that scopes have been analyzed. 201 Scope* scope_; 202 // The compiled code. 203 Handle<Code> code_; 204 205 // Possible initial inputs to the compilation process. 206 Handle<JSFunction> closure_; 207 Handle<SharedFunctionInfo> shared_info_; 208 Handle<Script> script_; 209 210 // Fields possibly needed for eager compilation, NULL by default. 211 v8::Extension* extension_; 212 ScriptDataImpl* pre_parse_data_; 213 214 // The context of the caller is needed for eval code, and will be a null 215 // handle otherwise. 216 Handle<Context> calling_context_; 217 218 // Compilation mode flag and whether deoptimization is allowed. 219 Mode mode_; 220 bool supports_deoptimization_; 221 int osr_ast_id_; 222 223 DISALLOW_COPY_AND_ASSIGN(CompilationInfo); 224 }; 225 226 227 // The V8 compiler 228 // 229 // General strategy: Source code is translated into an anonymous function w/o 230 // parameters which then can be executed. If the source code contains other 231 // functions, they will be compiled and allocated as part of the compilation 232 // of the source code. 233 234 // Please note this interface returns shared function infos. This means you 235 // need to call Factory::NewFunctionFromSharedFunctionInfo before you have a 236 // real function with a context. 237 238 class Compiler : public AllStatic { 239 public: 240 // Default maximum number of function optimization attempts before we 241 // give up. 242 static const int kDefaultMaxOptCount = 10; 243 244 static const int kMaxInliningLevels = 3; 245 246 // All routines return a SharedFunctionInfo. 247 // If an error occurs an exception is raised and the return handle 248 // contains NULL. 249 250 // Compile a String source within a context. 251 static Handle<SharedFunctionInfo> Compile(Handle<String> source, 252 Handle<Object> script_name, 253 int line_offset, 254 int column_offset, 255 v8::Extension* extension, 256 ScriptDataImpl* pre_data, 257 Handle<Object> script_data, 258 NativesFlag is_natives_code); 259 260 // Compile a String source within a context for Eval. 261 static Handle<SharedFunctionInfo> CompileEval(Handle<String> source, 262 Handle<Context> context, 263 bool is_global, 264 StrictModeFlag strict_mode); 265 266 // Compile from function info (used for lazy compilation). Returns true on 267 // success and false if the compilation resulted in a stack overflow. 268 static bool CompileLazy(CompilationInfo* info); 269 270 // Compile a shared function info object (the function is possibly lazily 271 // compiled). 272 static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node, 273 Handle<Script> script); 274 275 // Set the function info for a newly compiled function. 276 static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info, 277 FunctionLiteral* lit, 278 bool is_toplevel, 279 Handle<Script> script); 280 281 #ifdef ENABLE_DEBUGGER_SUPPORT 282 static bool MakeCodeForLiveEdit(CompilationInfo* info); 283 #endif 284 285 static void RecordFunctionCompilation(Logger::LogEventsAndTags tag, 286 CompilationInfo* info, 287 Handle<SharedFunctionInfo> shared); 288 }; 289 290 291 // During compilation we need a global list of handles to constants 292 // for frame elements. When the zone gets deleted, we make sure to 293 // clear this list of handles as well. 294 class CompilationZoneScope : public ZoneScope { 295 public: 296 explicit CompilationZoneScope(ZoneScopeMode mode) : ZoneScope(mode) { } 297 virtual ~CompilationZoneScope() { 298 if (ShouldDeleteOnExit()) { 299 Isolate* isolate = Isolate::Current(); 300 isolate->frame_element_constant_list()->Clear(); 301 isolate->result_constant_list()->Clear(); 302 } 303 } 304 }; 305 306 307 } } // namespace v8::internal 308 309 #endif // V8_COMPILER_H_ 310