1 /* 2 * Copyright (C) 2009, 2010 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 "CallData.h" 30 #include "JSFunction.h" 31 #include "Interpreter.h" 32 #include "Nodes.h" 33 #include "SamplingTool.h" 34 #include <wtf/PassOwnPtr.h> 35 36 namespace JSC { 37 38 class CodeBlock; 39 class Debugger; 40 class EvalCodeBlock; 41 class FunctionCodeBlock; 42 class ProgramCodeBlock; 43 class ScopeChainNode; 44 45 struct ExceptionInfo; 46 47 class ExecutableBase : public JSCell { 48 friend class JIT; 49 50 protected: 51 static const int NUM_PARAMETERS_IS_HOST = 0; 52 static const int NUM_PARAMETERS_NOT_COMPILED = -1; 53 54 public: ExecutableBase(JSGlobalData & globalData,Structure * structure,int numParameters)55 ExecutableBase(JSGlobalData& globalData, Structure* structure, int numParameters) 56 : JSCell(globalData, structure) 57 , m_numParametersForCall(numParameters) 58 , m_numParametersForConstruct(numParameters) 59 { 60 } 61 isHostFunction()62 bool isHostFunction() const 63 { 64 ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST)); 65 return m_numParametersForCall == NUM_PARAMETERS_IS_HOST; 66 } 67 createStructure(JSGlobalData & globalData,JSValue proto)68 static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info); } 69 70 protected: 71 static const unsigned StructureFlags = 0; 72 static const ClassInfo s_info; 73 int m_numParametersForCall; 74 int m_numParametersForConstruct; 75 76 #if ENABLE(JIT) 77 public: generatedJITCodeForCall()78 JITCode& generatedJITCodeForCall() 79 { 80 ASSERT(m_jitCodeForCall); 81 return m_jitCodeForCall; 82 } 83 generatedJITCodeForConstruct()84 JITCode& generatedJITCodeForConstruct() 85 { 86 ASSERT(m_jitCodeForConstruct); 87 return m_jitCodeForConstruct; 88 } 89 90 protected: 91 JITCode m_jitCodeForCall; 92 JITCode m_jitCodeForConstruct; 93 MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck; 94 MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck; 95 #endif 96 }; 97 98 class NativeExecutable : public ExecutableBase { 99 friend class JIT; 100 public: 101 #if ENABLE(JIT) create(JSGlobalData & globalData,MacroAssemblerCodePtr callThunk,NativeFunction function,MacroAssemblerCodePtr constructThunk,NativeFunction constructor)102 static NativeExecutable* create(JSGlobalData& globalData, MacroAssemblerCodePtr callThunk, NativeFunction function, MacroAssemblerCodePtr constructThunk, NativeFunction constructor) 103 { 104 if (!callThunk) 105 return new (&globalData) NativeExecutable(globalData, JITCode(), function, JITCode(), constructor); 106 return new (&globalData) NativeExecutable(globalData, JITCode::HostFunction(callThunk), function, JITCode::HostFunction(constructThunk), constructor); 107 } 108 #else 109 static NativeExecutable* create(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor) 110 { 111 return new (&globalData) NativeExecutable(globalData, function, constructor); 112 } 113 #endif 114 115 ~NativeExecutable(); 116 function()117 NativeFunction function() { return m_function; } 118 createStructure(JSGlobalData & globalData,JSValue proto)119 static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(LeafType, StructureFlags), AnonymousSlotCount, &s_info); } 120 121 private: 122 #if ENABLE(JIT) NativeExecutable(JSGlobalData & globalData,JITCode callThunk,NativeFunction function,JITCode constructThunk,NativeFunction constructor)123 NativeExecutable(JSGlobalData& globalData, JITCode callThunk, NativeFunction function, JITCode constructThunk, NativeFunction constructor) 124 : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST) 125 , m_function(function) 126 , m_constructor(constructor) 127 { 128 m_jitCodeForCall = callThunk; 129 m_jitCodeForConstruct = constructThunk; 130 m_jitCodeForCallWithArityCheck = callThunk.addressForCall(); 131 m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall(); 132 } 133 #else 134 NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor) 135 : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST) 136 , m_function(function) 137 , m_constructor(constructor) 138 { 139 } 140 #endif 141 142 NativeFunction m_function; 143 // Probably should be a NativeConstructor, but this will currently require rewriting the JIT 144 // trampoline. It may be easier to make NativeFunction be passed 'this' as a part of the ArgList. 145 NativeFunction m_constructor; 146 static const ClassInfo s_info; 147 }; 148 149 class ScriptExecutable : public ExecutableBase { 150 public: ScriptExecutable(Structure * structure,JSGlobalData * globalData,const SourceCode & source,bool isInStrictContext)151 ScriptExecutable(Structure* structure, JSGlobalData* globalData, const SourceCode& source, bool isInStrictContext) 152 : ExecutableBase(*globalData, structure, NUM_PARAMETERS_NOT_COMPILED) 153 , m_source(source) 154 , m_features(isInStrictContext ? StrictModeFeature : 0) 155 { 156 #if ENABLE(CODEBLOCK_SAMPLING) 157 relaxAdoptionRequirement(); 158 if (SamplingTool* sampler = globalData->interpreter->sampler()) 159 sampler->notifyOfScope(this); 160 #else 161 UNUSED_PARAM(globalData); 162 #endif 163 } 164 ScriptExecutable(Structure * structure,ExecState * exec,const SourceCode & source,bool isInStrictContext)165 ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext) 166 : ExecutableBase(exec->globalData(), structure, NUM_PARAMETERS_NOT_COMPILED) 167 , m_source(source) 168 , m_features(isInStrictContext ? StrictModeFeature : 0) 169 { 170 #if ENABLE(CODEBLOCK_SAMPLING) 171 relaxAdoptionRequirement(); 172 if (SamplingTool* sampler = exec->globalData().interpreter->sampler()) 173 sampler->notifyOfScope(this); 174 #else 175 UNUSED_PARAM(exec); 176 #endif 177 } 178 source()179 const SourceCode& source() { return m_source; } sourceID()180 intptr_t sourceID() const { return m_source.provider()->asID(); } sourceURL()181 const UString& sourceURL() const { return m_source.provider()->url(); } lineNo()182 int lineNo() const { return m_firstLine; } lastLine()183 int lastLine() const { return m_lastLine; } 184 usesEval()185 bool usesEval() const { return m_features & EvalFeature; } usesArguments()186 bool usesArguments() const { return m_features & ArgumentsFeature; } needsActivation()187 bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); } isStrictMode()188 bool isStrictMode() const { return m_features & StrictModeFeature; } 189 190 protected: recordParse(CodeFeatures features,bool hasCapturedVariables,int firstLine,int lastLine)191 void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine) 192 { 193 m_features = features; 194 m_hasCapturedVariables = hasCapturedVariables; 195 m_firstLine = firstLine; 196 m_lastLine = lastLine; 197 } 198 199 SourceCode m_source; 200 CodeFeatures m_features; 201 bool m_hasCapturedVariables; 202 int m_firstLine; 203 int m_lastLine; 204 }; 205 206 class EvalExecutable : public ScriptExecutable { 207 public: 208 209 ~EvalExecutable(); 210 compile(ExecState * exec,ScopeChainNode * scopeChainNode)211 JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode) 212 { 213 ASSERT(exec->globalData().dynamicGlobalObject); 214 JSObject* error = 0; 215 if (!m_evalCodeBlock) 216 error = compileInternal(exec, scopeChainNode); 217 ASSERT(!error == !!m_evalCodeBlock); 218 return error; 219 } 220 generatedBytecode()221 EvalCodeBlock& generatedBytecode() 222 { 223 ASSERT(m_evalCodeBlock); 224 return *m_evalCodeBlock; 225 } 226 create(ExecState * exec,const SourceCode & source,bool isInStrictContext)227 static EvalExecutable* create(ExecState* exec, const SourceCode& source, bool isInStrictContext) { return new (exec) EvalExecutable(exec, source, isInStrictContext); } 228 229 #if ENABLE(JIT) generatedJITCode()230 JITCode& generatedJITCode() 231 { 232 return generatedJITCodeForCall(); 233 } 234 #endif createStructure(JSGlobalData & globalData,JSValue proto)235 static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, 0); } 236 237 private: 238 static const unsigned StructureFlags = OverridesMarkChildren | ScriptExecutable::StructureFlags; 239 static const ClassInfo s_info; 240 EvalExecutable(ExecState*, const SourceCode&, bool); 241 242 JSObject* compileInternal(ExecState*, ScopeChainNode*); 243 virtual void markChildren(MarkStack&); 244 245 OwnPtr<EvalCodeBlock> m_evalCodeBlock; 246 }; 247 248 class ProgramExecutable : public ScriptExecutable { 249 public: create(ExecState * exec,const SourceCode & source)250 static ProgramExecutable* create(ExecState* exec, const SourceCode& source) 251 { 252 return new (exec) ProgramExecutable(exec, source); 253 } 254 255 ~ProgramExecutable(); 256 compile(ExecState * exec,ScopeChainNode * scopeChainNode)257 JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode) 258 { 259 ASSERT(exec->globalData().dynamicGlobalObject); 260 JSObject* error = 0; 261 if (!m_programCodeBlock) 262 error = compileInternal(exec, scopeChainNode); 263 ASSERT(!error == !!m_programCodeBlock); 264 return error; 265 } 266 generatedBytecode()267 ProgramCodeBlock& generatedBytecode() 268 { 269 ASSERT(m_programCodeBlock); 270 return *m_programCodeBlock; 271 } 272 273 JSObject* checkSyntax(ExecState*); 274 275 #if ENABLE(JIT) generatedJITCode()276 JITCode& generatedJITCode() 277 { 278 return generatedJITCodeForCall(); 279 } 280 #endif 281 createStructure(JSGlobalData & globalData,JSValue proto)282 static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, 0); } 283 284 private: 285 static const unsigned StructureFlags = OverridesMarkChildren | ScriptExecutable::StructureFlags; 286 static const ClassInfo s_info; 287 ProgramExecutable(ExecState*, const SourceCode&); 288 289 JSObject* compileInternal(ExecState*, ScopeChainNode*); 290 virtual void markChildren(MarkStack&); 291 292 OwnPtr<ProgramCodeBlock> m_programCodeBlock; 293 }; 294 295 class FunctionExecutable : public ScriptExecutable { 296 friend class JIT; 297 public: create(ExecState * exec,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,bool isInStrictContext,int firstLine,int lastLine)298 static FunctionExecutable* create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) 299 { 300 return new (exec) FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine); 301 } 302 create(JSGlobalData * globalData,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,bool isInStrictContext,int firstLine,int lastLine)303 static FunctionExecutable* create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) 304 { 305 return new (globalData) FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine); 306 } 307 make(ExecState * exec,ScopeChainNode * scopeChain)308 JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain) 309 { 310 return new (exec) JSFunction(exec, this, scopeChain); 311 } 312 313 // Returns either call or construct bytecode. This can be appropriate 314 // for answering questions that that don't vary between call and construct -- 315 // for example, argumentsRegister(). generatedBytecode()316 FunctionCodeBlock& generatedBytecode() 317 { 318 if (m_codeBlockForCall) 319 return *m_codeBlockForCall; 320 ASSERT(m_codeBlockForConstruct); 321 return *m_codeBlockForConstruct; 322 } 323 compileForCall(ExecState * exec,ScopeChainNode * scopeChainNode)324 JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode) 325 { 326 ASSERT(exec->globalData().dynamicGlobalObject); 327 JSObject* error = 0; 328 if (!m_codeBlockForCall) 329 error = compileForCallInternal(exec, scopeChainNode); 330 ASSERT(!error == !!m_codeBlockForCall); 331 return error; 332 } 333 isGeneratedForCall()334 bool isGeneratedForCall() const 335 { 336 return m_codeBlockForCall; 337 } 338 generatedBytecodeForCall()339 FunctionCodeBlock& generatedBytecodeForCall() 340 { 341 ASSERT(m_codeBlockForCall); 342 return *m_codeBlockForCall; 343 } 344 compileForConstruct(ExecState * exec,ScopeChainNode * scopeChainNode)345 JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) 346 { 347 ASSERT(exec->globalData().dynamicGlobalObject); 348 JSObject* error = 0; 349 if (!m_codeBlockForConstruct) 350 error = compileForConstructInternal(exec, scopeChainNode); 351 ASSERT(!error == !!m_codeBlockForConstruct); 352 return error; 353 } 354 isGeneratedForConstruct()355 bool isGeneratedForConstruct() const 356 { 357 return m_codeBlockForConstruct; 358 } 359 generatedBytecodeForConstruct()360 FunctionCodeBlock& generatedBytecodeForConstruct() 361 { 362 ASSERT(m_codeBlockForConstruct); 363 return *m_codeBlockForConstruct; 364 } 365 name()366 const Identifier& name() { return m_name; } parameterCount()367 size_t parameterCount() const { return m_parameters->size(); } capturedVariableCount()368 unsigned capturedVariableCount() const { return m_numCapturedVariables; } 369 UString paramString() const; symbolTable()370 SharedSymbolTable* symbolTable() const { return m_symbolTable; } 371 372 void discardCode(); 373 void markChildren(MarkStack&); 374 static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception); createStructure(JSGlobalData & globalData,JSValue proto)375 static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, 0); } 376 377 private: 378 FunctionExecutable(JSGlobalData*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine); 379 FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine); 380 381 JSObject* compileForCallInternal(ExecState*, ScopeChainNode*); 382 JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*); 383 384 static const unsigned StructureFlags = OverridesMarkChildren | ScriptExecutable::StructureFlags; 385 static const ClassInfo s_info; 386 unsigned m_numCapturedVariables : 31; 387 bool m_forceUsesArguments : 1; 388 389 RefPtr<FunctionParameters> m_parameters; 390 OwnPtr<FunctionCodeBlock> m_codeBlockForCall; 391 OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct; 392 Identifier m_name; 393 SharedSymbolTable* m_symbolTable; 394 395 #if ENABLE(JIT) 396 public: generatedJITCodeForCallWithArityCheck()397 MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck() 398 { 399 ASSERT(m_jitCodeForCall); 400 ASSERT(m_jitCodeForCallWithArityCheck); 401 return m_jitCodeForCallWithArityCheck; 402 } 403 generatedJITCodeForConstructWithArityCheck()404 MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck() 405 { 406 ASSERT(m_jitCodeForConstruct); 407 ASSERT(m_jitCodeForConstructWithArityCheck); 408 return m_jitCodeForConstructWithArityCheck; 409 } 410 #endif 411 }; 412 jsExecutable()413 inline FunctionExecutable* JSFunction::jsExecutable() const 414 { 415 ASSERT(!isHostFunctionNonInline()); 416 return static_cast<FunctionExecutable*>(m_executable.get()); 417 } 418 isHostFunction()419 inline bool JSFunction::isHostFunction() const 420 { 421 ASSERT(m_executable); 422 return m_executable->isHostFunction(); 423 } 424 nativeFunction()425 inline NativeFunction JSFunction::nativeFunction() 426 { 427 ASSERT(isHostFunction()); 428 return static_cast<NativeExecutable*>(m_executable.get())->function(); 429 } 430 } 431 432 #endif 433