1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #ifndef Executable_h 27 #define Executable_h 28 29 #include "JSFunction.h" 30 #include "Interpreter.h" 31 #include "Nodes.h" 32 #include "SamplingTool.h" 33 34 namespace JSC { 35 36 class CodeBlock; 37 class Debugger; 38 class EvalCodeBlock; 39 class ProgramCodeBlock; 40 class ScopeChainNode; 41 42 struct ExceptionInfo; 43 44 class ExecutableBase : public RefCounted<ExecutableBase> { 45 friend class JIT; 46 47 protected: 48 static const int NUM_PARAMETERS_IS_HOST = 0; 49 static const int NUM_PARAMETERS_NOT_COMPILED = -1; 50 51 public: 52 ExecutableBase(int numParameters) 53 : m_numParameters(numParameters) 54 { 55 } 56 57 virtual ~ExecutableBase() {} 58 59 bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; } 60 61 protected: 62 int m_numParameters; 63 64 #if ENABLE(JIT) 65 public: 66 JITCode& generatedJITCode() 67 { 68 ASSERT(m_jitCode); 69 return m_jitCode; 70 } 71 72 ExecutablePool* getExecutablePool() 73 { 74 return m_jitCode.getExecutablePool(); 75 } 76 77 protected: 78 JITCode m_jitCode; 79 #endif 80 }; 81 82 #if ENABLE(JIT) 83 class NativeExecutable : public ExecutableBase { 84 public: 85 NativeExecutable(ExecState* exec) 86 : ExecutableBase(NUM_PARAMETERS_IS_HOST) 87 { 88 m_jitCode = JITCode(JITCode::HostFunction(exec->globalData().jitStubs.ctiNativeCallThunk())); 89 } 90 91 ~NativeExecutable(); 92 }; 93 #endif 94 95 class VPtrHackExecutable : public ExecutableBase { 96 public: 97 VPtrHackExecutable() 98 : ExecutableBase(NUM_PARAMETERS_IS_HOST) 99 { 100 } 101 102 ~VPtrHackExecutable(); 103 }; 104 105 class ScriptExecutable : public ExecutableBase { 106 public: 107 ScriptExecutable(JSGlobalData* globalData, const SourceCode& source) 108 : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) 109 , m_source(source) 110 , m_features(0) 111 { 112 #if ENABLE(CODEBLOCK_SAMPLING) 113 if (SamplingTool* sampler = globalData->interpreter->sampler()) 114 sampler->notifyOfScope(this); 115 #else 116 UNUSED_PARAM(globalData); 117 #endif 118 } 119 120 ScriptExecutable(ExecState* exec, const SourceCode& source) 121 : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) 122 , m_source(source) 123 , m_features(0) 124 { 125 #if ENABLE(CODEBLOCK_SAMPLING) 126 if (SamplingTool* sampler = exec->globalData().interpreter->sampler()) 127 sampler->notifyOfScope(this); 128 #else 129 UNUSED_PARAM(exec); 130 #endif 131 } 132 133 const SourceCode& source() { return m_source; } 134 intptr_t sourceID() const { return m_source.provider()->asID(); } 135 const UString& sourceURL() const { return m_source.provider()->url(); } 136 int lineNo() const { return m_firstLine; } 137 int lastLine() const { return m_lastLine; } 138 139 bool usesEval() const { return m_features & EvalFeature; } 140 bool usesArguments() const { return m_features & ArgumentsFeature; } 141 bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); } 142 143 virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0; 144 145 protected: 146 void recordParse(CodeFeatures features, int firstLine, int lastLine) 147 { 148 m_features = features; 149 m_firstLine = firstLine; 150 m_lastLine = lastLine; 151 } 152 153 SourceCode m_source; 154 CodeFeatures m_features; 155 int m_firstLine; 156 int m_lastLine; 157 }; 158 159 class EvalExecutable : public ScriptExecutable { 160 public: 161 162 ~EvalExecutable(); 163 164 EvalCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) 165 { 166 if (!m_evalCodeBlock) { 167 JSObject* error = compile(exec, scopeChainNode); 168 ASSERT_UNUSED(!error, error); 169 } 170 return *m_evalCodeBlock; 171 } 172 173 JSObject* compile(ExecState*, ScopeChainNode*); 174 175 ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); 176 static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); } 177 178 private: 179 EvalExecutable(ExecState* exec, const SourceCode& source) 180 : ScriptExecutable(exec, source) 181 , m_evalCodeBlock(0) 182 { 183 } 184 EvalCodeBlock* m_evalCodeBlock; 185 186 #if ENABLE(JIT) 187 public: 188 JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) 189 { 190 if (!m_jitCode) 191 generateJITCode(exec, scopeChainNode); 192 return m_jitCode; 193 } 194 195 private: 196 void generateJITCode(ExecState*, ScopeChainNode*); 197 #endif 198 }; 199 200 class ProgramExecutable : public ScriptExecutable { 201 public: 202 static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source) 203 { 204 return adoptRef(new ProgramExecutable(exec, source)); 205 } 206 207 ~ProgramExecutable(); 208 209 ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) 210 { 211 if (!m_programCodeBlock) { 212 JSObject* error = compile(exec, scopeChainNode); 213 ASSERT_UNUSED(!error, error); 214 } 215 return *m_programCodeBlock; 216 } 217 218 JSObject* checkSyntax(ExecState*); 219 JSObject* compile(ExecState*, ScopeChainNode*); 220 221 // CodeBlocks for program code are transient and therefore do not gain from from throwing out there exception information. 222 ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) { ASSERT_NOT_REACHED(); return 0; } 223 224 private: 225 ProgramExecutable(ExecState* exec, const SourceCode& source) 226 : ScriptExecutable(exec, source) 227 , m_programCodeBlock(0) 228 { 229 } 230 ProgramCodeBlock* m_programCodeBlock; 231 232 #if ENABLE(JIT) 233 public: 234 JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) 235 { 236 if (!m_jitCode) 237 generateJITCode(exec, scopeChainNode); 238 return m_jitCode; 239 } 240 241 private: 242 void generateJITCode(ExecState*, ScopeChainNode*); 243 #endif 244 }; 245 246 class FunctionExecutable : public ScriptExecutable { 247 friend class JIT; 248 public: 249 static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) 250 { 251 return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine)); 252 } 253 254 static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) 255 { 256 return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine)); 257 } 258 259 ~FunctionExecutable(); 260 261 JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain) 262 { 263 return new (exec) JSFunction(exec, this, scopeChain); 264 } 265 266 CodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) 267 { 268 ASSERT(scopeChainNode); 269 if (!m_codeBlock) 270 compile(exec, scopeChainNode); 271 return *m_codeBlock; 272 } 273 274 bool isGenerated() const 275 { 276 return m_codeBlock; 277 } 278 279 CodeBlock& generatedBytecode() 280 { 281 ASSERT(m_codeBlock); 282 return *m_codeBlock; 283 } 284 285 const Identifier& name() { return m_name; } 286 size_t parameterCount() const { return m_parameters->size(); } 287 size_t variableCount() const { return m_numVariables; } 288 UString paramString() const; 289 290 void recompile(ExecState*); 291 ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); 292 void markAggregate(MarkStack& markStack); 293 static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0); 294 295 private: 296 FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) 297 : ScriptExecutable(globalData, source) 298 , m_forceUsesArguments(forceUsesArguments) 299 , m_parameters(parameters) 300 , m_codeBlock(0) 301 , m_name(name) 302 , m_numVariables(0) 303 { 304 m_firstLine = firstLine; 305 m_lastLine = lastLine; 306 } 307 308 FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) 309 : ScriptExecutable(exec, source) 310 , m_forceUsesArguments(forceUsesArguments) 311 , m_parameters(parameters) 312 , m_codeBlock(0) 313 , m_name(name) 314 , m_numVariables(0) 315 { 316 m_firstLine = firstLine; 317 m_lastLine = lastLine; 318 } 319 320 void compile(ExecState*, ScopeChainNode*); 321 322 bool m_forceUsesArguments; 323 RefPtr<FunctionParameters> m_parameters; 324 CodeBlock* m_codeBlock; 325 Identifier m_name; 326 size_t m_numVariables; 327 328 #if ENABLE(JIT) 329 public: 330 JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) 331 { 332 if (!m_jitCode) 333 generateJITCode(exec, scopeChainNode); 334 return m_jitCode; 335 } 336 337 private: 338 void generateJITCode(ExecState*, ScopeChainNode*); 339 #endif 340 }; 341 342 inline FunctionExecutable* JSFunction::jsExecutable() const 343 { 344 ASSERT(!isHostFunctionNonInline()); 345 return static_cast<FunctionExecutable*>(m_executable.get()); 346 } 347 348 inline bool JSFunction::isHostFunction() const 349 { 350 ASSERT(m_executable); 351 return m_executable->isHostFunction(); 352 } 353 354 } 355 356 #endif 357