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) 236 { 237 return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info); 238 } 239 240 private: 241 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; 242 static const ClassInfo s_info; 243 EvalExecutable(ExecState*, const SourceCode&, bool); 244 245 JSObject* compileInternal(ExecState*, ScopeChainNode*); 246 virtual void visitChildren(SlotVisitor&); 247 248 OwnPtr<EvalCodeBlock> m_evalCodeBlock; 249 }; 250 251 class ProgramExecutable : public ScriptExecutable { 252 public: create(ExecState * exec,const SourceCode & source)253 static ProgramExecutable* create(ExecState* exec, const SourceCode& source) 254 { 255 return new (exec) ProgramExecutable(exec, source); 256 } 257 258 ~ProgramExecutable(); 259 compile(ExecState * exec,ScopeChainNode * scopeChainNode)260 JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode) 261 { 262 ASSERT(exec->globalData().dynamicGlobalObject); 263 JSObject* error = 0; 264 if (!m_programCodeBlock) 265 error = compileInternal(exec, scopeChainNode); 266 ASSERT(!error == !!m_programCodeBlock); 267 return error; 268 } 269 generatedBytecode()270 ProgramCodeBlock& generatedBytecode() 271 { 272 ASSERT(m_programCodeBlock); 273 return *m_programCodeBlock; 274 } 275 276 JSObject* checkSyntax(ExecState*); 277 278 #if ENABLE(JIT) generatedJITCode()279 JITCode& generatedJITCode() 280 { 281 return generatedJITCodeForCall(); 282 } 283 #endif 284 createStructure(JSGlobalData & globalData,JSValue proto)285 static Structure* createStructure(JSGlobalData& globalData, JSValue proto) 286 { 287 return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info); 288 } 289 290 private: 291 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; 292 static const ClassInfo s_info; 293 ProgramExecutable(ExecState*, const SourceCode&); 294 295 JSObject* compileInternal(ExecState*, ScopeChainNode*); 296 virtual void visitChildren(SlotVisitor&); 297 298 OwnPtr<ProgramCodeBlock> m_programCodeBlock; 299 }; 300 301 class FunctionExecutable : public ScriptExecutable { 302 friend class JIT; 303 public: create(ExecState * exec,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,bool isInStrictContext,int firstLine,int lastLine)304 static FunctionExecutable* create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) 305 { 306 return new (exec) FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine); 307 } 308 create(JSGlobalData * globalData,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,bool isInStrictContext,int firstLine,int lastLine)309 static FunctionExecutable* create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) 310 { 311 return new (globalData) FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine); 312 } 313 make(ExecState * exec,ScopeChainNode * scopeChain)314 JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain) 315 { 316 return new (exec) JSFunction(exec, this, scopeChain); 317 } 318 319 // Returns either call or construct bytecode. This can be appropriate 320 // for answering questions that that don't vary between call and construct -- 321 // for example, argumentsRegister(). generatedBytecode()322 FunctionCodeBlock& generatedBytecode() 323 { 324 if (m_codeBlockForCall) 325 return *m_codeBlockForCall; 326 ASSERT(m_codeBlockForConstruct); 327 return *m_codeBlockForConstruct; 328 } 329 compileForCall(ExecState * exec,ScopeChainNode * scopeChainNode)330 JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode) 331 { 332 ASSERT(exec->globalData().dynamicGlobalObject); 333 JSObject* error = 0; 334 if (!m_codeBlockForCall) 335 error = compileForCallInternal(exec, scopeChainNode); 336 ASSERT(!error == !!m_codeBlockForCall); 337 return error; 338 } 339 isGeneratedForCall()340 bool isGeneratedForCall() const 341 { 342 return m_codeBlockForCall; 343 } 344 generatedBytecodeForCall()345 FunctionCodeBlock& generatedBytecodeForCall() 346 { 347 ASSERT(m_codeBlockForCall); 348 return *m_codeBlockForCall; 349 } 350 compileForConstruct(ExecState * exec,ScopeChainNode * scopeChainNode)351 JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) 352 { 353 ASSERT(exec->globalData().dynamicGlobalObject); 354 JSObject* error = 0; 355 if (!m_codeBlockForConstruct) 356 error = compileForConstructInternal(exec, scopeChainNode); 357 ASSERT(!error == !!m_codeBlockForConstruct); 358 return error; 359 } 360 isGeneratedForConstruct()361 bool isGeneratedForConstruct() const 362 { 363 return m_codeBlockForConstruct; 364 } 365 generatedBytecodeForConstruct()366 FunctionCodeBlock& generatedBytecodeForConstruct() 367 { 368 ASSERT(m_codeBlockForConstruct); 369 return *m_codeBlockForConstruct; 370 } 371 name()372 const Identifier& name() { return m_name; } parameterCount()373 size_t parameterCount() const { return m_parameters->size(); } capturedVariableCount()374 unsigned capturedVariableCount() const { return m_numCapturedVariables; } 375 UString paramString() const; symbolTable()376 SharedSymbolTable* symbolTable() const { return m_symbolTable; } 377 378 void discardCode(); 379 void visitChildren(SlotVisitor&); 380 static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception); createStructure(JSGlobalData & globalData,JSValue proto)381 static Structure* createStructure(JSGlobalData& globalData, JSValue proto) 382 { 383 return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info); 384 } 385 386 private: 387 FunctionExecutable(JSGlobalData*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine); 388 FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine); 389 390 JSObject* compileForCallInternal(ExecState*, ScopeChainNode*); 391 JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*); 392 393 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; 394 static const ClassInfo s_info; 395 unsigned m_numCapturedVariables : 31; 396 bool m_forceUsesArguments : 1; 397 398 RefPtr<FunctionParameters> m_parameters; 399 OwnPtr<FunctionCodeBlock> m_codeBlockForCall; 400 OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct; 401 Identifier m_name; 402 SharedSymbolTable* m_symbolTable; 403 404 #if ENABLE(JIT) 405 public: generatedJITCodeForCallWithArityCheck()406 MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck() 407 { 408 ASSERT(m_jitCodeForCall); 409 ASSERT(m_jitCodeForCallWithArityCheck); 410 return m_jitCodeForCallWithArityCheck; 411 } 412 generatedJITCodeForConstructWithArityCheck()413 MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck() 414 { 415 ASSERT(m_jitCodeForConstruct); 416 ASSERT(m_jitCodeForConstructWithArityCheck); 417 return m_jitCodeForConstructWithArityCheck; 418 } 419 #endif 420 }; 421 jsExecutable()422 inline FunctionExecutable* JSFunction::jsExecutable() const 423 { 424 ASSERT(!isHostFunctionNonInline()); 425 return static_cast<FunctionExecutable*>(m_executable.get()); 426 } 427 isHostFunction()428 inline bool JSFunction::isHostFunction() const 429 { 430 ASSERT(m_executable); 431 return m_executable->isHostFunction(); 432 } 433 nativeFunction()434 inline NativeFunction JSFunction::nativeFunction() 435 { 436 ASSERT(isHostFunction()); 437 return static_cast<NativeExecutable*>(m_executable.get())->function(); 438 } 439 } 440 441 #endif 442