| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 1 | // Copyright 2010 the V8 project authors. All rights reserved. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 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 | #include "v8.h" | 
|  | 29 |  | 
|  | 30 | #include "bootstrapper.h" | 
|  | 31 | #include "codegen-inl.h" | 
|  | 32 | #include "compilation-cache.h" | 
|  | 33 | #include "compiler.h" | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 34 | #include "data-flow.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 35 | #include "debug.h" | 
| Leon Clarke | eab96aa | 2010-01-27 16:31:12 +0000 | [diff] [blame] | 36 | #include "fast-codegen.h" | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 37 | #include "flow-graph.h" | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 38 | #include "full-codegen.h" | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 39 | #include "liveedit.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 40 | #include "oprofile-agent.h" | 
|  | 41 | #include "rewriter.h" | 
|  | 42 | #include "scopes.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 43 |  | 
|  | 44 | namespace v8 { | 
|  | 45 | namespace internal { | 
|  | 46 |  | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 47 |  | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 48 | static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) { | 
|  | 49 | FunctionLiteral* function = info->function(); | 
|  | 50 | ASSERT(function != NULL); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 51 | // Rewrite the AST by introducing .result assignments where needed. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 52 | if (!Rewriter::Process(function)) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 53 | // Signal a stack overflow by returning a null handle.  The stack | 
|  | 54 | // overflow exception will be thrown by the caller. | 
|  | 55 | return Handle<Code>::null(); | 
|  | 56 | } | 
|  | 57 |  | 
|  | 58 | { | 
|  | 59 | // Compute top scope and allocate variables. For lazy compilation | 
|  | 60 | // the top scope only contains the single lazily compiled function, | 
|  | 61 | // so this doesn't re-allocate variables repeatedly. | 
|  | 62 | HistogramTimerScope timer(&Counters::variable_allocation); | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 63 | Scope* top = info->scope(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 64 | while (top->outer_scope() != NULL) top = top->outer_scope(); | 
|  | 65 | top->AllocateVariables(context); | 
|  | 66 | } | 
|  | 67 |  | 
|  | 68 | #ifdef DEBUG | 
|  | 69 | if (Bootstrapper::IsActive() ? | 
|  | 70 | FLAG_print_builtin_scopes : | 
|  | 71 | FLAG_print_scopes) { | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 72 | info->scope()->Print(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 73 | } | 
|  | 74 | #endif | 
|  | 75 |  | 
|  | 76 | // Optimize the AST. | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 77 | if (!Rewriter::Optimize(function)) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 78 | // Signal a stack overflow by returning a null handle.  The stack | 
|  | 79 | // overflow exception will be thrown by the caller. | 
|  | 80 | return Handle<Code>::null(); | 
|  | 81 | } | 
|  | 82 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 83 | if (function->scope()->num_parameters() > 0 || | 
|  | 84 | function->scope()->num_stack_slots()) { | 
|  | 85 | AssignedVariablesAnalyzer ava(function); | 
|  | 86 | ava.Analyze(); | 
|  | 87 | if (ava.HasStackOverflow()) { | 
|  | 88 | return Handle<Code>::null(); | 
|  | 89 | } | 
|  | 90 | } | 
|  | 91 |  | 
|  | 92 | if (FLAG_use_flow_graph) { | 
|  | 93 | FlowGraphBuilder builder; | 
|  | 94 | FlowGraph* graph = builder.Build(function); | 
|  | 95 | USE(graph); | 
|  | 96 |  | 
|  | 97 | #ifdef DEBUG | 
|  | 98 | if (FLAG_print_graph_text && !builder.HasStackOverflow()) { | 
|  | 99 | graph->PrintAsText(function->name()); | 
|  | 100 | } | 
|  | 101 | #endif | 
|  | 102 | } | 
|  | 103 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 104 | // Generate code and return it.  Code generator selection is governed by | 
|  | 105 | // which backends are enabled and whether the function is considered | 
|  | 106 | // run-once code or not: | 
|  | 107 | // | 
|  | 108 | //  --full-compiler enables the dedicated backend for code we expect to be | 
|  | 109 | //    run once | 
|  | 110 | //  --fast-compiler enables a speculative optimizing backend (for | 
|  | 111 | //    non-run-once code) | 
|  | 112 | // | 
|  | 113 | // The normal choice of backend can be overridden with the flags | 
|  | 114 | // --always-full-compiler and --always-fast-compiler, which are mutually | 
|  | 115 | // incompatible. | 
|  | 116 | CHECK(!FLAG_always_full_compiler || !FLAG_always_fast_compiler); | 
|  | 117 |  | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 118 | Handle<SharedFunctionInfo> shared = info->shared_info(); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 119 | bool is_run_once = (shared.is_null()) | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 120 | ? info->scope()->is_global_scope() | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 121 | : (shared->is_toplevel() || shared->try_full_codegen()); | 
|  | 122 |  | 
|  | 123 | if (FLAG_always_full_compiler || (FLAG_full_compiler && is_run_once)) { | 
|  | 124 | FullCodeGenSyntaxChecker checker; | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 125 | checker.Check(function); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 126 | if (checker.has_supported_syntax()) { | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 127 | return FullCodeGenerator::MakeCode(info); | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 128 | } | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 129 | } else if (FLAG_always_fast_compiler || | 
|  | 130 | (FLAG_fast_compiler && !is_run_once)) { | 
|  | 131 | FastCodeGenSyntaxChecker checker; | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 132 | checker.Check(info); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 133 | if (checker.has_supported_syntax()) { | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 134 | return FastCodeGenerator::MakeCode(info); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 135 | } | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 136 | } | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 137 |  | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 138 | return CodeGenerator::MakeCode(info); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 139 | } | 
|  | 140 |  | 
|  | 141 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 142 | #ifdef ENABLE_DEBUGGER_SUPPORT | 
|  | 143 | Handle<Code> MakeCodeForLiveEdit(CompilationInfo* info) { | 
|  | 144 | Handle<Context> context = Handle<Context>::null(); | 
|  | 145 | return MakeCode(context, info); | 
|  | 146 | } | 
|  | 147 | #endif | 
|  | 148 |  | 
|  | 149 |  | 
|  | 150 | static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global, | 
|  | 151 | bool is_eval, | 
|  | 152 | Compiler::ValidationState validate, | 
|  | 153 | Handle<Script> script, | 
|  | 154 | Handle<Context> context, | 
|  | 155 | v8::Extension* extension, | 
|  | 156 | ScriptDataImpl* pre_data) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 157 | CompilationZoneScope zone_scope(DELETE_ON_EXIT); | 
|  | 158 |  | 
|  | 159 | PostponeInterruptsScope postpone; | 
|  | 160 |  | 
|  | 161 | ASSERT(!i::Top::global_context().is_null()); | 
|  | 162 | script->set_context_data((*i::Top::global_context())->data()); | 
|  | 163 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 164 | bool is_json = (validate == Compiler::VALIDATE_JSON); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 165 | #ifdef ENABLE_DEBUGGER_SUPPORT | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 166 | if (is_eval || is_json) { | 
|  | 167 | script->set_compilation_type( | 
|  | 168 | is_json ? Smi::FromInt(Script::COMPILATION_TYPE_JSON) : | 
|  | 169 | Smi::FromInt(Script::COMPILATION_TYPE_EVAL)); | 
|  | 170 | // For eval scripts add information on the function from which eval was | 
|  | 171 | // called. | 
|  | 172 | if (is_eval) { | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 173 | StackTraceFrameIterator it; | 
|  | 174 | if (!it.done()) { | 
|  | 175 | script->set_eval_from_shared( | 
|  | 176 | JSFunction::cast(it.frame()->function())->shared()); | 
|  | 177 | int offset = static_cast<int>( | 
|  | 178 | it.frame()->pc() - it.frame()->code()->instruction_start()); | 
|  | 179 | script->set_eval_from_instructions_offset(Smi::FromInt(offset)); | 
|  | 180 | } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 181 | } | 
|  | 182 | } | 
|  | 183 |  | 
|  | 184 | // Notify debugger | 
|  | 185 | Debugger::OnBeforeCompile(script); | 
|  | 186 | #endif | 
|  | 187 |  | 
|  | 188 | // Only allow non-global compiles for eval. | 
|  | 189 | ASSERT(is_eval || is_global); | 
|  | 190 |  | 
|  | 191 | // Build AST. | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 192 | FunctionLiteral* lit = | 
|  | 193 | MakeAST(is_global, script, extension, pre_data, is_json); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 194 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 195 | LiveEditFunctionTracker live_edit_tracker(lit); | 
|  | 196 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 197 | // Check for parse errors. | 
|  | 198 | if (lit == NULL) { | 
|  | 199 | ASSERT(Top::has_pending_exception()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 200 | return Handle<SharedFunctionInfo>::null(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 201 | } | 
|  | 202 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 203 | // Measure how long it takes to do the compilation; only take the | 
|  | 204 | // rest of the function into account to avoid overlap with the | 
|  | 205 | // parsing statistics. | 
|  | 206 | HistogramTimer* rate = is_eval | 
|  | 207 | ? &Counters::compile_eval | 
|  | 208 | : &Counters::compile; | 
|  | 209 | HistogramTimerScope timer(rate); | 
|  | 210 |  | 
|  | 211 | // Compile the code. | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 212 | CompilationInfo info(lit, script, is_eval); | 
|  | 213 | Handle<Code> code = MakeCode(context, &info); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 214 |  | 
|  | 215 | // Check for stack-overflow exceptions. | 
|  | 216 | if (code.is_null()) { | 
|  | 217 | Top::StackOverflow(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 218 | return Handle<SharedFunctionInfo>::null(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 219 | } | 
|  | 220 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 221 | if (script->name()->IsString()) { | 
|  | 222 | PROFILE(CodeCreateEvent( | 
|  | 223 | is_eval ? Logger::EVAL_TAG : | 
|  | 224 | Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), | 
|  | 225 | *code, String::cast(script->name()))); | 
|  | 226 | OPROFILE(CreateNativeCodeRegion(String::cast(script->name()), | 
|  | 227 | code->instruction_start(), | 
|  | 228 | code->instruction_size())); | 
|  | 229 | } else { | 
|  | 230 | PROFILE(CodeCreateEvent( | 
|  | 231 | is_eval ? Logger::EVAL_TAG : | 
|  | 232 | Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), | 
|  | 233 | *code, "")); | 
|  | 234 | OPROFILE(CreateNativeCodeRegion(is_eval ? "Eval" : "Script", | 
|  | 235 | code->instruction_start(), | 
|  | 236 | code->instruction_size())); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 237 | } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 238 |  | 
|  | 239 | // Allocate function. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 240 | Handle<SharedFunctionInfo> result = | 
|  | 241 | Factory::NewSharedFunctionInfo(lit->name(), | 
|  | 242 | lit->materialized_literal_count(), | 
|  | 243 | code); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 244 |  | 
|  | 245 | ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 246 | Compiler::SetFunctionInfo(result, lit, true, script); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 247 |  | 
|  | 248 | // Hint to the runtime system used when allocating space for initial | 
|  | 249 | // property space by setting the expected number of properties for | 
|  | 250 | // the instances of the function. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 251 | SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 252 |  | 
|  | 253 | #ifdef ENABLE_DEBUGGER_SUPPORT | 
|  | 254 | // Notify debugger | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 255 | Debugger::OnAfterCompile(script, Debugger::NO_AFTER_COMPILE_FLAGS); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 256 | #endif | 
|  | 257 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 258 | live_edit_tracker.RecordFunctionInfo(result, lit); | 
|  | 259 |  | 
|  | 260 | return result; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 261 | } | 
|  | 262 |  | 
|  | 263 |  | 
|  | 264 | static StaticResource<SafeStringInputBuffer> safe_string_input_buffer; | 
|  | 265 |  | 
|  | 266 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 267 | Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, | 
|  | 268 | Handle<Object> script_name, | 
|  | 269 | int line_offset, | 
|  | 270 | int column_offset, | 
|  | 271 | v8::Extension* extension, | 
|  | 272 | ScriptDataImpl* input_pre_data, | 
|  | 273 | Handle<Object> script_data, | 
|  | 274 | NativesFlag natives) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 275 | int source_length = source->length(); | 
|  | 276 | Counters::total_load_size.Increment(source_length); | 
|  | 277 | Counters::total_compile_size.Increment(source_length); | 
|  | 278 |  | 
|  | 279 | // The VM is in the COMPILER state until exiting this function. | 
|  | 280 | VMState state(COMPILER); | 
|  | 281 |  | 
|  | 282 | // Do a lookup in the compilation cache but not for extensions. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 283 | Handle<SharedFunctionInfo> result; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 284 | if (extension == NULL) { | 
|  | 285 | result = CompilationCache::LookupScript(source, | 
|  | 286 | script_name, | 
|  | 287 | line_offset, | 
|  | 288 | column_offset); | 
|  | 289 | } | 
|  | 290 |  | 
|  | 291 | if (result.is_null()) { | 
|  | 292 | // No cache entry found. Do pre-parsing and compile the script. | 
|  | 293 | ScriptDataImpl* pre_data = input_pre_data; | 
|  | 294 | if (pre_data == NULL && source_length >= FLAG_min_preparse_length) { | 
|  | 295 | Access<SafeStringInputBuffer> buf(&safe_string_input_buffer); | 
|  | 296 | buf->Reset(source.location()); | 
|  | 297 | pre_data = PreParse(source, buf.value(), extension); | 
|  | 298 | } | 
|  | 299 |  | 
|  | 300 | // Create a script object describing the script to be compiled. | 
|  | 301 | Handle<Script> script = Factory::NewScript(source); | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 302 | if (natives == NATIVES_CODE) { | 
|  | 303 | script->set_type(Smi::FromInt(Script::TYPE_NATIVE)); | 
|  | 304 | } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 305 | if (!script_name.is_null()) { | 
|  | 306 | script->set_name(*script_name); | 
|  | 307 | script->set_line_offset(Smi::FromInt(line_offset)); | 
|  | 308 | script->set_column_offset(Smi::FromInt(column_offset)); | 
|  | 309 | } | 
|  | 310 |  | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 311 | script->set_data(script_data.is_null() ? Heap::undefined_value() | 
|  | 312 | : *script_data); | 
|  | 313 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 314 | // Compile the function and add it to the cache. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 315 | result = MakeFunctionInfo(true, | 
|  | 316 | false, | 
|  | 317 | DONT_VALIDATE_JSON, | 
|  | 318 | script, | 
|  | 319 | Handle<Context>::null(), | 
|  | 320 | extension, | 
|  | 321 | pre_data); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 322 | if (extension == NULL && !result.is_null()) { | 
|  | 323 | CompilationCache::PutScript(source, result); | 
|  | 324 | } | 
|  | 325 |  | 
|  | 326 | // Get rid of the pre-parsing data (if necessary). | 
|  | 327 | if (input_pre_data == NULL && pre_data != NULL) { | 
|  | 328 | delete pre_data; | 
|  | 329 | } | 
|  | 330 | } | 
|  | 331 |  | 
|  | 332 | if (result.is_null()) Top::ReportPendingMessages(); | 
|  | 333 | return result; | 
|  | 334 | } | 
|  | 335 |  | 
|  | 336 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 337 | Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, | 
|  | 338 | Handle<Context> context, | 
|  | 339 | bool is_global, | 
|  | 340 | ValidationState validate) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 341 | // Note that if validation is required then no path through this | 
|  | 342 | // function is allowed to return a value without validating that | 
|  | 343 | // the input is legal json. | 
|  | 344 |  | 
|  | 345 | int source_length = source->length(); | 
|  | 346 | Counters::total_eval_size.Increment(source_length); | 
|  | 347 | Counters::total_compile_size.Increment(source_length); | 
|  | 348 |  | 
|  | 349 | // The VM is in the COMPILER state until exiting this function. | 
|  | 350 | VMState state(COMPILER); | 
|  | 351 |  | 
|  | 352 | // Do a lookup in the compilation cache; if the entry is not there, | 
|  | 353 | // invoke the compiler and add the result to the cache.  If we're | 
|  | 354 | // evaluating json we bypass the cache since we can't be sure a | 
|  | 355 | // potential value in the cache has been validated. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 356 | Handle<SharedFunctionInfo> result; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 357 | if (validate == DONT_VALIDATE_JSON) | 
|  | 358 | result = CompilationCache::LookupEval(source, context, is_global); | 
|  | 359 |  | 
|  | 360 | if (result.is_null()) { | 
|  | 361 | // Create a script object describing the script to be compiled. | 
|  | 362 | Handle<Script> script = Factory::NewScript(source); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 363 | result = MakeFunctionInfo(is_global, | 
|  | 364 | true, | 
|  | 365 | validate, | 
|  | 366 | script, | 
|  | 367 | context, | 
|  | 368 | NULL, | 
|  | 369 | NULL); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 370 | if (!result.is_null() && validate != VALIDATE_JSON) { | 
|  | 371 | // For json it's unlikely that we'll ever see exactly the same | 
|  | 372 | // string again so we don't use the compilation cache. | 
|  | 373 | CompilationCache::PutEval(source, context, is_global, result); | 
|  | 374 | } | 
|  | 375 | } | 
|  | 376 |  | 
|  | 377 | return result; | 
|  | 378 | } | 
|  | 379 |  | 
|  | 380 |  | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 381 | bool Compiler::CompileLazy(CompilationInfo* info) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 382 | CompilationZoneScope zone_scope(DELETE_ON_EXIT); | 
|  | 383 |  | 
|  | 384 | // The VM is in the COMPILER state until exiting this function. | 
|  | 385 | VMState state(COMPILER); | 
|  | 386 |  | 
|  | 387 | PostponeInterruptsScope postpone; | 
|  | 388 |  | 
|  | 389 | // Compute name, source code and script data. | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 390 | Handle<SharedFunctionInfo> shared = info->shared_info(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 391 | Handle<String> name(String::cast(shared->name())); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 392 |  | 
|  | 393 | int start_position = shared->start_position(); | 
|  | 394 | int end_position = shared->end_position(); | 
|  | 395 | bool is_expression = shared->is_expression(); | 
|  | 396 | Counters::total_compile_size.Increment(end_position - start_position); | 
|  | 397 |  | 
|  | 398 | // Generate the AST for the lazily compiled function. The AST may be | 
|  | 399 | // NULL in case of parser stack overflow. | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 400 | FunctionLiteral* lit = MakeLazyAST(info->script(), | 
|  | 401 | name, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 402 | start_position, | 
|  | 403 | end_position, | 
|  | 404 | is_expression); | 
|  | 405 |  | 
|  | 406 | // Check for parse errors. | 
|  | 407 | if (lit == NULL) { | 
|  | 408 | ASSERT(Top::has_pending_exception()); | 
|  | 409 | return false; | 
|  | 410 | } | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 411 | info->set_function(lit); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 412 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 413 | // Measure how long it takes to do the lazy compilation; only take | 
|  | 414 | // the rest of the function into account to avoid overlap with the | 
|  | 415 | // lazy parsing statistics. | 
|  | 416 | HistogramTimerScope timer(&Counters::compile_lazy); | 
|  | 417 |  | 
|  | 418 | // Compile the code. | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 419 | Handle<Code> code = MakeCode(Handle<Context>::null(), info); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 420 |  | 
|  | 421 | // Check for stack-overflow exception. | 
|  | 422 | if (code.is_null()) { | 
|  | 423 | Top::StackOverflow(); | 
|  | 424 | return false; | 
|  | 425 | } | 
|  | 426 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 427 | RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, | 
|  | 428 | name, | 
|  | 429 | Handle<String>(shared->inferred_name()), | 
|  | 430 | start_position, | 
|  | 431 | info->script(), | 
|  | 432 | code); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 433 |  | 
|  | 434 | // Update the shared function info with the compiled code. | 
|  | 435 | shared->set_code(*code); | 
|  | 436 |  | 
|  | 437 | // Set the expected number of properties for instances. | 
|  | 438 | SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count()); | 
|  | 439 |  | 
|  | 440 | // Set the optimication hints after performing lazy compilation, as these are | 
|  | 441 | // not set when the function is set up as a lazily compiled function. | 
|  | 442 | shared->SetThisPropertyAssignmentsInfo( | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 443 | lit->has_only_simple_this_property_assignments(), | 
|  | 444 | *lit->this_property_assignments()); | 
|  | 445 |  | 
|  | 446 | // Check the function has compiled code. | 
|  | 447 | ASSERT(shared->is_compiled()); | 
|  | 448 | return true; | 
|  | 449 | } | 
|  | 450 |  | 
|  | 451 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 452 | Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, | 
|  | 453 | Handle<Script> script, | 
|  | 454 | AstVisitor* caller) { | 
|  | 455 | LiveEditFunctionTracker live_edit_tracker(literal); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 456 | #ifdef DEBUG | 
|  | 457 | // We should not try to compile the same function literal more than | 
|  | 458 | // once. | 
|  | 459 | literal->mark_as_compiled(); | 
|  | 460 | #endif | 
|  | 461 |  | 
|  | 462 | // Determine if the function can be lazily compiled. This is | 
|  | 463 | // necessary to allow some of our builtin JS files to be lazily | 
|  | 464 | // compiled. These builtins cannot be handled lazily by the parser, | 
|  | 465 | // since we have to know if a function uses the special natives | 
|  | 466 | // syntax, which is something the parser records. | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 467 | bool allow_lazy = literal->AllowsLazyCompilation() && | 
|  | 468 | !LiveEditFunctionTracker::IsActive(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 469 |  | 
|  | 470 | // Generate code | 
|  | 471 | Handle<Code> code; | 
|  | 472 | if (FLAG_lazy && allow_lazy) { | 
|  | 473 | code = ComputeLazyCompile(literal->num_parameters()); | 
|  | 474 | } else { | 
|  | 475 | // The bodies of function literals have not yet been visited by | 
|  | 476 | // the AST optimizer/analyzer. | 
|  | 477 | if (!Rewriter::Optimize(literal)) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 478 | return Handle<SharedFunctionInfo>::null(); | 
|  | 479 | } | 
|  | 480 |  | 
|  | 481 | if (literal->scope()->num_parameters() > 0 || | 
|  | 482 | literal->scope()->num_stack_slots()) { | 
|  | 483 | AssignedVariablesAnalyzer ava(literal); | 
|  | 484 | ava.Analyze(); | 
|  | 485 | if (ava.HasStackOverflow()) { | 
|  | 486 | return Handle<SharedFunctionInfo>::null(); | 
|  | 487 | } | 
|  | 488 | } | 
|  | 489 |  | 
|  | 490 | if (FLAG_use_flow_graph) { | 
|  | 491 | FlowGraphBuilder builder; | 
|  | 492 | FlowGraph* graph = builder.Build(literal); | 
|  | 493 | USE(graph); | 
|  | 494 |  | 
|  | 495 | #ifdef DEBUG | 
|  | 496 | if (FLAG_print_graph_text && !builder.HasStackOverflow()) { | 
|  | 497 | graph->PrintAsText(literal->name()); | 
|  | 498 | } | 
|  | 499 | #endif | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 500 | } | 
|  | 501 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 502 | // Generate code and return it.  The way that the compilation mode | 
|  | 503 | // is controlled by the command-line flags is described in | 
|  | 504 | // the static helper function MakeCode. | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 505 | CompilationInfo info(literal, script, false); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 506 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 507 | CHECK(!FLAG_always_full_compiler || !FLAG_always_fast_compiler); | 
|  | 508 | bool is_run_once = literal->try_full_codegen(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 509 | bool is_compiled = false; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 510 | if (FLAG_always_full_compiler || (FLAG_full_compiler && is_run_once)) { | 
|  | 511 | FullCodeGenSyntaxChecker checker; | 
|  | 512 | checker.Check(literal); | 
|  | 513 | if (checker.has_supported_syntax()) { | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 514 | code = FullCodeGenerator::MakeCode(&info); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 515 | is_compiled = true; | 
|  | 516 | } | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 517 | } else if (FLAG_always_fast_compiler || | 
|  | 518 | (FLAG_fast_compiler && !is_run_once)) { | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 519 | // Since we are not lazily compiling we do not have a receiver to | 
|  | 520 | // specialize for. | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 521 | FastCodeGenSyntaxChecker checker; | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 522 | checker.Check(&info); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 523 | if (checker.has_supported_syntax()) { | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 524 | code = FastCodeGenerator::MakeCode(&info); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 525 | is_compiled = true; | 
|  | 526 | } | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 527 | } | 
|  | 528 |  | 
|  | 529 | if (!is_compiled) { | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 530 | // We fall back to the classic V8 code generator. | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 531 | code = CodeGenerator::MakeCode(&info); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 532 | } | 
|  | 533 |  | 
|  | 534 | // Check for stack-overflow exception. | 
|  | 535 | if (code.is_null()) { | 
|  | 536 | caller->SetStackOverflow(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 537 | return Handle<SharedFunctionInfo>::null(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 538 | } | 
|  | 539 |  | 
|  | 540 | // Function compilation complete. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 541 | RecordFunctionCompilation(Logger::FUNCTION_TAG, | 
|  | 542 | literal->name(), | 
|  | 543 | literal->inferred_name(), | 
|  | 544 | literal->start_position(), | 
|  | 545 | script, | 
|  | 546 | code); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 547 | } | 
|  | 548 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 549 | // Create a shared function info object. | 
|  | 550 | Handle<SharedFunctionInfo> result = | 
|  | 551 | Factory::NewSharedFunctionInfo(literal->name(), | 
|  | 552 | literal->materialized_literal_count(), | 
|  | 553 | code); | 
|  | 554 | SetFunctionInfo(result, literal, false, script); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 555 |  | 
|  | 556 | // Set the expected number of properties for instances and return | 
|  | 557 | // the resulting function. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 558 | SetExpectedNofPropertiesFromEstimate(result, | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 559 | literal->expected_property_count()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 560 | live_edit_tracker.RecordFunctionInfo(result, literal); | 
|  | 561 | return result; | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 562 | } | 
|  | 563 |  | 
|  | 564 |  | 
|  | 565 | // Sets the function info on a function. | 
|  | 566 | // The start_position points to the first '(' character after the function name | 
|  | 567 | // in the full script source. When counting characters in the script source the | 
|  | 568 | // the first character is number 0 (not 1). | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 569 | void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 570 | FunctionLiteral* lit, | 
|  | 571 | bool is_toplevel, | 
|  | 572 | Handle<Script> script) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 573 | function_info->set_length(lit->num_parameters()); | 
|  | 574 | function_info->set_formal_parameter_count(lit->num_parameters()); | 
|  | 575 | function_info->set_script(*script); | 
|  | 576 | function_info->set_function_token_position(lit->function_token_position()); | 
|  | 577 | function_info->set_start_position(lit->start_position()); | 
|  | 578 | function_info->set_end_position(lit->end_position()); | 
|  | 579 | function_info->set_is_expression(lit->is_expression()); | 
|  | 580 | function_info->set_is_toplevel(is_toplevel); | 
|  | 581 | function_info->set_inferred_name(*lit->inferred_name()); | 
|  | 582 | function_info->SetThisPropertyAssignmentsInfo( | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 583 | lit->has_only_simple_this_property_assignments(), | 
|  | 584 | *lit->this_property_assignments()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 585 | function_info->set_try_full_codegen(lit->try_full_codegen()); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 586 | } | 
|  | 587 |  | 
|  | 588 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 589 | void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag, | 
|  | 590 | Handle<String> name, | 
|  | 591 | Handle<String> inferred_name, | 
|  | 592 | int start_position, | 
|  | 593 | Handle<Script> script, | 
|  | 594 | Handle<Code> code) { | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 595 | // Log the code generation. If source information is available | 
|  | 596 | // include script name and line number. Check explicitly whether | 
|  | 597 | // logging is enabled as finding the line number is not free. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 598 | if (Logger::is_logging() | 
|  | 599 | || OProfileAgent::is_enabled() | 
|  | 600 | || CpuProfiler::is_profiling()) { | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 601 | Handle<String> func_name(name->length() > 0 ? *name : *inferred_name); | 
|  | 602 | if (script->name()->IsString()) { | 
|  | 603 | int line_num = GetScriptLineNumber(script, start_position) + 1; | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 604 | USE(line_num); | 
|  | 605 | PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), | 
|  | 606 | *code, *func_name, | 
|  | 607 | String::cast(script->name()), line_num)); | 
|  | 608 | OPROFILE(CreateNativeCodeRegion(*func_name, | 
|  | 609 | String::cast(script->name()), | 
|  | 610 | line_num, | 
|  | 611 | code->instruction_start(), | 
|  | 612 | code->instruction_size())); | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 613 | } else { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame^] | 614 | PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), | 
|  | 615 | *code, *func_name)); | 
|  | 616 | OPROFILE(CreateNativeCodeRegion(*func_name, | 
|  | 617 | code->instruction_start(), | 
|  | 618 | code->instruction_size())); | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 619 | } | 
|  | 620 | } | 
|  | 621 | } | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 622 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 623 | } }  // namespace v8::internal |