// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef V8_COMPILER_H_ #define V8_COMPILER_H_ #include "allocation.h" #include "ast.h" #include "zone.h" namespace v8 { namespace internal { class ScriptDataImpl; // CompilationInfo encapsulates some information known at compile time. It // is constructed based on the resources available at compile-time. class CompilationInfo BASE_EMBEDDED { public: explicit CompilationInfo(Handle<Script> script); explicit CompilationInfo(Handle<SharedFunctionInfo> shared_info); explicit CompilationInfo(Handle<JSFunction> closure); Isolate* isolate() { ASSERT(Isolate::Current() == isolate_); return isolate_; } bool is_lazy() const { return IsLazy::decode(flags_); } bool is_eval() const { return IsEval::decode(flags_); } bool is_global() const { return IsGlobal::decode(flags_); } bool is_classic_mode() const { return language_mode() == CLASSIC_MODE; } bool is_extended_mode() const { return language_mode() == EXTENDED_MODE; } LanguageMode language_mode() const { return LanguageModeField::decode(flags_); } bool is_in_loop() const { return IsInLoop::decode(flags_); } FunctionLiteral* function() const { return function_; } Scope* scope() const { return scope_; } Scope* global_scope() const { return global_scope_; } Handle<Code> code() const { return code_; } Handle<JSFunction> closure() const { return closure_; } Handle<SharedFunctionInfo> shared_info() const { return shared_info_; } Handle<Script> script() const { return script_; } v8::Extension* extension() const { return extension_; } ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; } Handle<Context> calling_context() const { return calling_context_; } int osr_ast_id() const { return osr_ast_id_; } void MarkAsEval() { ASSERT(!is_lazy()); flags_ |= IsEval::encode(true); } void MarkAsGlobal() { ASSERT(!is_lazy()); flags_ |= IsGlobal::encode(true); } void SetLanguageMode(LanguageMode language_mode) { ASSERT(this->language_mode() == CLASSIC_MODE || this->language_mode() == language_mode || language_mode == EXTENDED_MODE); flags_ = LanguageModeField::update(flags_, language_mode); } void MarkAsInLoop() { ASSERT(is_lazy()); flags_ |= IsInLoop::encode(true); } void MarkAsNative() { flags_ |= IsNative::encode(true); } bool is_native() const { return IsNative::decode(flags_); } void SetFunction(FunctionLiteral* literal) { ASSERT(function_ == NULL); function_ = literal; } void SetScope(Scope* scope) { ASSERT(scope_ == NULL); scope_ = scope; } void SetGlobalScope(Scope* global_scope) { ASSERT(global_scope_ == NULL); global_scope_ = global_scope; } void SetCode(Handle<Code> code) { code_ = code; } void SetExtension(v8::Extension* extension) { ASSERT(!is_lazy()); extension_ = extension; } void SetPreParseData(ScriptDataImpl* pre_parse_data) { ASSERT(!is_lazy()); pre_parse_data_ = pre_parse_data; } void SetCallingContext(Handle<Context> context) { ASSERT(is_eval()); calling_context_ = context; } void SetOsrAstId(int osr_ast_id) { ASSERT(IsOptimizing()); osr_ast_id_ = osr_ast_id; } void MarkCompilingForDebugging(Handle<Code> current_code) { ASSERT(mode_ != OPTIMIZE); ASSERT(current_code->kind() == Code::FUNCTION); flags_ |= IsCompilingForDebugging::encode(true); if (current_code->is_compiled_optimizable()) { EnableDeoptimizationSupport(); } else { mode_ = CompilationInfo::NONOPT; } } bool IsCompilingForDebugging() { return IsCompilingForDebugging::decode(flags_); } bool has_global_object() const { return !closure().is_null() && (closure()->context()->global() != NULL); } GlobalObject* global_object() const { return has_global_object() ? closure()->context()->global() : NULL; } // Accessors for the different compilation modes. bool IsOptimizing() const { return mode_ == OPTIMIZE; } bool IsOptimizable() const { return mode_ == BASE; } void SetOptimizing(int osr_ast_id) { SetMode(OPTIMIZE); osr_ast_id_ = osr_ast_id; } void DisableOptimization(); // Deoptimization support. bool HasDeoptimizationSupport() const { return SupportsDeoptimization::decode(flags_); } void EnableDeoptimizationSupport() { ASSERT(IsOptimizable()); flags_ |= SupportsDeoptimization::encode(true); } // Determines whether or not to insert a self-optimization header. bool ShouldSelfOptimize(); // Disable all optimization attempts of this info for the rest of the // current compilation pipeline. void AbortOptimization(); private: Isolate* isolate_; // Compilation mode. // BASE is generated by the full codegen, optionally prepared for bailouts. // OPTIMIZE is optimized code generated by the Hydrogen-based backend. // NONOPT is generated by the full codegen and is not prepared for // recompilation/bailouts. These functions are never recompiled. enum Mode { BASE, OPTIMIZE, NONOPT }; CompilationInfo() : function_(NULL) {} void Initialize(Mode mode) { mode_ = V8::UseCrankshaft() ? mode : NONOPT; ASSERT(!script_.is_null()); if (script_->type()->value() == Script::TYPE_NATIVE) { MarkAsNative(); } if (!shared_info_.is_null()) { ASSERT(language_mode() == CLASSIC_MODE); SetLanguageMode(shared_info_->language_mode()); } } void SetMode(Mode mode) { ASSERT(V8::UseCrankshaft()); mode_ = mode; } // Flags using template class BitField<type, start, length>. All are // false by default. // // Compilation is either eager or lazy. class IsLazy: public BitField<bool, 0, 1> {}; // Flags that can be set for eager compilation. class IsEval: public BitField<bool, 1, 1> {}; class IsGlobal: public BitField<bool, 2, 1> {}; // Flags that can be set for lazy compilation. class IsInLoop: public BitField<bool, 3, 1> {}; // Strict mode - used in eager compilation. class LanguageModeField: public BitField<LanguageMode, 4, 2> {}; // Is this a function from our natives. class IsNative: public BitField<bool, 6, 1> {}; // Is this code being compiled with support for deoptimization.. class SupportsDeoptimization: public BitField<bool, 7, 1> {}; // If compiling for debugging produce just full code matching the // initial mode setting. class IsCompilingForDebugging: public BitField<bool, 8, 1> {}; unsigned flags_; // Fields filled in by the compilation pipeline. // AST filled in by the parser. FunctionLiteral* function_; // The scope of the function literal as a convenience. Set to indicate // that scopes have been analyzed. Scope* scope_; // The global scope provided as a convenience. Scope* global_scope_; // The compiled code. Handle<Code> code_; // Possible initial inputs to the compilation process. Handle<JSFunction> closure_; Handle<SharedFunctionInfo> shared_info_; Handle<Script> script_; // Fields possibly needed for eager compilation, NULL by default. v8::Extension* extension_; ScriptDataImpl* pre_parse_data_; // The context of the caller is needed for eval code, and will be a null // handle otherwise. Handle<Context> calling_context_; // Compilation mode flag and whether deoptimization is allowed. Mode mode_; int osr_ast_id_; DISALLOW_COPY_AND_ASSIGN(CompilationInfo); }; // The V8 compiler // // General strategy: Source code is translated into an anonymous function w/o // parameters which then can be executed. If the source code contains other // functions, they will be compiled and allocated as part of the compilation // of the source code. // Please note this interface returns shared function infos. This means you // need to call Factory::NewFunctionFromSharedFunctionInfo before you have a // real function with a context. class Compiler : public AllStatic { public: // Default maximum number of function optimization attempts before we // give up. static const int kDefaultMaxOptCount = 10; static const int kMaxInliningLevels = 3; // Call count before primitive functions trigger their own optimization. static const int kCallsUntilPrimitiveOpt = 200; // All routines return a SharedFunctionInfo. // If an error occurs an exception is raised and the return handle // contains NULL. // Compile a String source within a context. static Handle<SharedFunctionInfo> Compile(Handle<String> source, Handle<Object> script_name, int line_offset, int column_offset, v8::Extension* extension, ScriptDataImpl* pre_data, Handle<Object> script_data, NativesFlag is_natives_code); // Compile a String source within a context for Eval. static Handle<SharedFunctionInfo> CompileEval(Handle<String> source, Handle<Context> context, bool is_global, LanguageMode language_mode, int scope_position); // Compile from function info (used for lazy compilation). Returns true on // success and false if the compilation resulted in a stack overflow. static bool CompileLazy(CompilationInfo* info); // Compile a shared function info object (the function is possibly lazily // compiled). static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node, Handle<Script> script); // Set the function info for a newly compiled function. static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info, FunctionLiteral* lit, bool is_toplevel, Handle<Script> script); #ifdef ENABLE_DEBUGGER_SUPPORT static bool MakeCodeForLiveEdit(CompilationInfo* info); #endif static void RecordFunctionCompilation(Logger::LogEventsAndTags tag, CompilationInfo* info, Handle<SharedFunctionInfo> shared); }; } } // namespace v8::internal #endif // V8_COMPILER_H_