+=== End merge of squirrelfish-extreme ===
+
+2008-09-06 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Sam Weinig. Adapted somewhat by Maciej Stachowiak.
+
+ - refactor WREC to share more of the JIT infrastructure with CTI
+
+ * VM/CTI.cpp:
+ (KJS::CTI::emitGetArg):
+ (KJS::CTI::emitGetPutArg):
+ (KJS::CTI::emitPutArg):
+ (KJS::CTI::emitPutArgConstant):
+ (KJS::CTI::emitPutCTIParam):
+ (KJS::CTI::emitGetCTIParam):
+ (KJS::CTI::emitPutToCallFrameHeader):
+ (KJS::CTI::emitGetFromCallFrameHeader):
+ (KJS::CTI::emitPutResult):
+ (KJS::CTI::emitDebugExceptionCheck):
+ (KJS::CTI::emitJumpSlowCaseIfNotImm):
+ (KJS::CTI::emitJumpSlowCaseIfNotImms):
+ (KJS::CTI::emitFastArithDeTagImmediate):
+ (KJS::CTI::emitFastArithReTagImmediate):
+ (KJS::CTI::emitFastArithPotentiallyReTagImmediate):
+ (KJS::CTI::emitFastArithImmToInt):
+ (KJS::CTI::emitFastArithIntToImmOrSlowCase):
+ (KJS::CTI::emitFastArithIntToImmNoCheck):
+ (KJS::CTI::CTI):
+ (KJS::CTI::compileOpCall):
+ (KJS::CTI::privateCompileMainPass):
+ (KJS::CTI::privateCompileSlowCases):
+ (KJS::CTI::privateCompile):
+ (KJS::CTI::privateCompileGetByIdSelf):
+ (KJS::CTI::privateCompileGetByIdProto):
+ (KJS::CTI::privateCompileGetByIdChain):
+ (KJS::CTI::privateCompilePutByIdReplace):
+ (KJS::CTI::privateArrayLengthTrampoline):
+ (KJS::CTI::privateStringLengthTrampoline):
+ (KJS::CTI::compileRegExp):
+ * VM/CTI.h:
+ (KJS::CallRecord::CallRecord):
+ (KJS::JmpTable::JmpTable):
+ (KJS::SlowCaseEntry::SlowCaseEntry):
+ (KJS::CTI::JSRInfo::JSRInfo):
+ * kjs/regexp.cpp:
+ (KJS::RegExp::RegExp):
+ * wrec/WREC.cpp:
+ (KJS::GenerateParenthesesNonGreedyFunctor::GenerateParenthesesNonGreedyFunctor):
+ (KJS::GeneratePatternCharacterFunctor::generateAtom):
+ (KJS::GeneratePatternCharacterFunctor::backtrack):
+ (KJS::GenerateCharacterClassFunctor::generateAtom):
+ (KJS::GenerateCharacterClassFunctor::backtrack):
+ (KJS::GenerateBackreferenceFunctor::generateAtom):
+ (KJS::GenerateBackreferenceFunctor::backtrack):
+ (KJS::GenerateParenthesesNonGreedyFunctor::generateAtom):
+ (KJS::GenerateParenthesesNonGreedyFunctor::backtrack):
+ (KJS::WRECGenerate::generateBacktrack1):
+ (KJS::WRECGenerate::generateBacktrackBackreference):
+ (KJS::WRECGenerate::generateBackreferenceQuantifier):
+ (KJS::WRECGenerate::generateNonGreedyQuantifier):
+ (KJS::WRECGenerate::generateGreedyQuantifier):
+ (KJS::WRECGenerate::generatePatternCharacter):
+ (KJS::WRECGenerate::generateCharacterClassInvertedRange):
+ (KJS::WRECGenerate::generateCharacterClassInverted):
+ (KJS::WRECGenerate::generateCharacterClass):
+ (KJS::WRECGenerate::generateParentheses):
+ (KJS::WRECGenerate::generateParenthesesNonGreedy):
+ (KJS::WRECGenerate::gererateParenthesesResetTrampoline):
+ (KJS::WRECGenerate::generateAssertionBOL):
+ (KJS::WRECGenerate::generateAssertionEOL):
+ (KJS::WRECGenerate::generateAssertionWordBoundary):
+ (KJS::WRECGenerate::generateBackreference):
+ (KJS::WRECGenerate::gernerateDisjunction):
+ (KJS::WRECGenerate::terminateDisjunction):
+ (KJS::WRECParser::parseGreedyQuantifier):
+ (KJS::WRECParser::parseQuantifier):
+ (KJS::WRECParser::parsePatternCharacterQualifier):
+ (KJS::WRECParser::parseCharacterClassQuantifier):
+ (KJS::WRECParser::parseBackreferenceQuantifier):
+ (KJS::WRECParser::parseParentheses):
+ (KJS::WRECParser::parseCharacterClass):
+ (KJS::WRECParser::parseOctalEscape):
+ (KJS::WRECParser::parseEscape):
+ (KJS::WRECParser::parseTerm):
+ (KJS::WRECParser::parseDisjunction):
+ * wrec/WREC.h:
+ (KJS::WRECGenerate::WRECGenerate):
+ (KJS::WRECParser::):
+ (KJS::WRECParser::WRECParser):
+ (KJS::WRECParser::parseAlternative):
+ (KJS::WRECParser::isEndOfPattern):
+
+2008-09-06 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by NOBODY (Build fix).
+
+ Fix the sampler build.
+
+ * VM/SamplingTool.h:
+
+2008-09-06 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Jump through the necessary hoops required to make MSVC cooperate with SFX
+
+ We now explicitly declare the calling convention on all cti_op_* cfunctions,
+ and return int instead of bool where appropriate (despite the cdecl calling
+ convention seems to state MSVC generates code that returns the result value
+ through ecx). SFX behaves slightly differently under MSVC, specifically it
+ stores the base argument address for the cti_op_* functions in the first
+ argument, and then does the required stack manipulation through that pointer.
+ This is necessary as MSVC's optimisations assume they have complete control
+ of the stack, and periodically elide our stack manipulations, or move
+ values in unexpected ways. MSVC also frequently produces tail calls which may
+ clobber the first argument, so the MSVC path is slightly less efficient due
+ to the need to restore it.
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * VM/CTI.cpp:
+ (KJS::):
+ (KJS::CTI::compileOpCall):
+ (KJS::CTI::privateCompileMainPass):
+ (KJS::CTI::privateCompileSlowCases):
+ * VM/CTI.h:
+ * VM/Machine.cpp:
+ * VM/Machine.h:
+ * masm/MacroAssembler.h:
+ (KJS::MacroAssembler::emitConvertToFastCall):
+ * masm/MacroAssemblerIA32GCC.cpp: Removed.
+ For performance reasons we need these no-op functions to be inlined.
+
+ * masm/MacroAssemblerWin.cpp:
+ (KJS::MacroAssembler::emitRestoreArgumentReference):
+ * wtf/Platform.h:
+
+2008-09-05 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej Stachowiak, or maybe the other way around.
+
+ Added the ability to coalesce JITCode buffer grow operations by first
+ growing the buffer and then executing unchecked puts to it.
+
+ About a 2% speedup on date-format-tofte.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::compileOpCall):
+ * masm/IA32MacroAsm.h:
+ (KJS::JITCodeBuffer::ensureSpace):
+ (KJS::JITCodeBuffer::putByteUnchecked):
+ (KJS::JITCodeBuffer::putByte):
+ (KJS::JITCodeBuffer::putShortUnchecked):
+ (KJS::JITCodeBuffer::putShort):
+ (KJS::JITCodeBuffer::putIntUnchecked):
+ (KJS::JITCodeBuffer::putInt):
+ (KJS::IA32MacroAssembler::emitTestl_i32r):
+ (KJS::IA32MacroAssembler::emitMovl_mr):
+ (KJS::IA32MacroAssembler::emitMovl_rm):
+ (KJS::IA32MacroAssembler::emitMovl_i32m):
+ (KJS::IA32MacroAssembler::emitUnlinkedJe):
+ (KJS::IA32MacroAssembler::emitModRm_rr):
+ (KJS::IA32MacroAssembler::emitModRm_rr_Unchecked):
+ (KJS::IA32MacroAssembler::emitModRm_rm_Unchecked):
+ (KJS::IA32MacroAssembler::emitModRm_rm):
+ (KJS::IA32MacroAssembler::emitModRm_opr):
+ (KJS::IA32MacroAssembler::emitModRm_opr_Unchecked):
+ (KJS::IA32MacroAssembler::emitModRm_opm_Unchecked):
+
+2008-09-05 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Disable WREC and CTI on platforms that we have not yet had a chance to test with.
+
+ * wtf/Platform.h:
+
+2008-09-05 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Use jo instead of a mask compare when fetching array.length and
+ string.length. 4% speedup on array.length / string.length torture
+ test.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateArrayLengthTrampoline):
+ (KJS::CTI::privateStringLengthTrampoline):
+
+2008-09-05 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Removed a CTI compilation pass by recording labels during bytecode
+ generation. This is more to reduce complexity than it is to improve
+ performance.
+
+ SunSpider reports no change.
+
+ CodeBlock now keeps a "labels" set, which holds the offsets of all the
+ instructions that can be jumped to.
+
+ * VM/CTI.cpp: Nixed a pass.
+
+ * VM/CodeBlock.h: Added a "labels" set.
+
+ * VM/LabelID.h: No need for a special LableID for holding jump
+ destinations, since the CodeBlock now knows all jump destinations.
+
+ * wtf/HashTraits.h: New hash traits to accomodate putting offset 0 in
+ the set.
+
+ * kjs/nodes.cpp:
+ (KJS::TryNode::emitCode): Emit a dummy label to record sret targets.
+
+2008-09-05 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt and Gavin Barraclough.
+
+ Move the JITCodeBuffer onto Machine and remove the static variables.
+
+ * VM/CTI.cpp: Initialize m_jit with the Machine's code buffer.
+ * VM/Machine.cpp:
+ (KJS::Machine::Machine): Allocate a JITCodeBuffer.
+ * VM/Machine.h:
+ * kjs/RegExpConstructor.cpp:
+ (KJS::constructRegExp): Pass the ExecState through.
+ * kjs/RegExpPrototype.cpp:
+ (KJS::regExpProtoFuncCompile): Ditto.
+ * kjs/StringPrototype.cpp:
+ (KJS::stringProtoFuncMatch): Ditto.
+ (KJS::stringProtoFuncSearch): Ditto.
+ * kjs/nodes.cpp:
+ (KJS::RegExpNode::emitCode): Compile the pattern at code generation time
+ so that we have access to an ExecState.
+ * kjs/nodes.h:
+ (KJS::RegExpNode::):
+ * kjs/nodes2string.cpp:
+ * kjs/regexp.cpp:
+ (KJS::RegExp::RegExp): Pass the ExecState through.
+ (KJS::RegExp::create): Ditto.
+ * kjs/regexp.h:
+ * masm/IA32MacroAsm.h:
+ (KJS::IA32MacroAssembler::IA32MacroAssembler): Reset the JITCodeBuffer when we are
+ constructed.
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::compile): Retrieve the JITCodeBuffer from the Machine.
+ * wrec/WREC.h:
+
+2008-09-05 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt and Gavin Barraclough.
+
+ Fix the build when CTI is disabled.
+
+ * VM/CodeBlock.cpp:
+ (KJS::CodeBlock::~CodeBlock):
+ * VM/CodeGenerator.cpp:
+ (KJS::prepareJumpTableForStringSwitch):
+ * VM/Machine.cpp:
+ (KJS::Machine::Machine):
+ (KJS::Machine::~Machine):
+
+2008-09-05 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Fix some windows abi issues.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompileMainPass):
+ (KJS::CTI::privateCompileSlowCases):
+ * VM/CTI.h:
+ (KJS::CallRecord::CallRecord):
+ (KJS::):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_resolve_func):
+ (KJS::Machine::cti_op_post_inc):
+ (KJS::Machine::cti_op_resolve_with_base):
+ (KJS::Machine::cti_op_post_dec):
+ * VM/Machine.h:
+
+2008-09-05 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Fix ecma/FunctionObjects/15.3.5.3.js after I broke it in r93.
+
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_call_NotJSFunction): Restore m_callFrame to the correct value after making the native call.
+ (KJS::Machine::cti_op_construct_NotJSConstruct): Ditto.
+
+2008-09-04 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Fix fast/dom/Window/console-functions.html.
+
+ The call frame on the ExecState was not being updated on calls into native functions. This meant that functions
+ such as console.log would use the line number of the last JS function on the call stack.
+
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_call_NotJSFunction): Update the ExecState's call frame before making a native function call,
+ and restore it when the function is done.
+ (KJS::Machine::cti_op_construct_NotJSConstruct): Ditto.
+
+2008-09-05 Oliver Hunt <oliver@apple.com>
+
+ Start bringing up SFX on windows.
+
+ Reviewed by Mark Rowe and Sam Weinig
+
+ Start doing the work to bring up SFX on windows. Initially
+ just working on WREC, as it does not make any calls so reduces
+ the amount of code that needs to be corrected.
+
+ Start abstracting the CTI JIT codegen engine.
+
+ * ChangeLog:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * VM/CTI.cpp:
+ * masm/IA32MacroAsm.h:
+ * masm/MacroAssembler.h: Added.
+ (KJS::MacroAssembler::MacroAssembler):
+ * masm/MacroAssemblerIA32GCC.cpp: Added.
+ (KJS::MacroAssembler::emitConvertToFastCall):
+ * masm/MacroAssemblerWin.cpp: Added.
+ (KJS::MacroAssembler::emitConvertToFastCall):
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::parseGreedyQuantifier):
+ (KJS::WRECompiler::parseCharacterClass):
+ (KJS::WRECompiler::parseEscape):
+ (KJS::WRECompiler::compilePattern):
+ * wrec/WREC.h:
+
+2008-09-04 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Support for slow scripts (timeout checking).
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompileMainPass):
+ (KJS::CTI::privateCompile):
+ * VM/Machine.cpp:
+ (KJS::slideRegisterWindowForCall):
+ (KJS::Machine::cti_timeout_check):
+ (KJS::Machine::cti_vm_throw):
+
+2008-09-04 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Third round of style cleanup.
+
+ * VM/CTI.cpp:
+ * VM/CTI.h:
+ * VM/CodeBlock.h:
+ * VM/Machine.cpp:
+ * VM/Machine.h:
+ * kjs/ExecState.h:
+
+2008-09-04 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Jon Honeycutt.
+
+ Second round of style cleanup.
+
+ * VM/CTI.cpp:
+ * VM/CTI.h:
+ * wrec/WREC.h:
+
+2008-09-04 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ First round of style cleanup.
+
+ * VM/CTI.cpp:
+ * VM/CTI.h:
+ * masm/IA32MacroAsm.h:
+ * wrec/WREC.cpp:
+ * wrec/WREC.h:
+
+2008-09-04 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Merged http://trac.webkit.org/changeset/36081 to work with CTI.
+
+ * VM/Machine.cpp:
+ (KJS::Machine::tryCtiCacheGetByID):
+
+2008-09-04 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Enable profiling in CTI.
+
+ * VM/CTI.h:
+ (KJS::):
+ (KJS::CTI::execute):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_call_JSFunction):
+ (KJS::Machine::cti_op_call_NotJSFunction):
+ (KJS::Machine::cti_op_ret):
+ (KJS::Machine::cti_op_construct_JSConstruct):
+ (KJS::Machine::cti_op_construct_NotJSConstruct):
+
+2008-09-04 Victor Hernandez <vhernandez@apple.com>
+
+ Reviewed by Geoffrey Garen.
+
+ Fixed an #if to support using WREC without CTI.
+
+ * kjs/regexp.cpp:
+ (KJS::RegExp::match):
+
+2008-09-04 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ The array/string length trampolines are owned by the Machine, not the codeblock that compiled them.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateArrayLengthTrampoline):
+ (KJS::CTI::privateStringLengthTrampoline):
+ * VM/Machine.cpp:
+ (KJS::Machine::~Machine):
+ * VM/Machine.h:
+
+2008-09-04 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Gavin Barraclough and Sam Weinig.
+
+ Fix a crash on launch of jsc when GuardMalloc is enabled.
+
+ * kjs/ScopeChain.h:
+ (KJS::ScopeChain::ScopeChain): Initialize m_node to 0 when we have no valid scope chain.
+ (KJS::ScopeChain::~ScopeChain): Null-check m_node before calling deref.
+
+2008-09-03 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Gavin Barraclough and Geoff Garen.
+
+ Fix inspector and fast array access so that it bounds
+ checks correctly.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass2_Main):
+ * masm/IA32MacroAsm.h:
+ (KJS::IA32MacroAssembler::):
+ (KJS::IA32MacroAssembler::emitUnlinkedJb):
+ (KJS::IA32MacroAssembler::emitUnlinkedJbe):
+
+2008-09-03 Mark Rowe <mrowe@apple.com>
+
+ Move the assertion after the InitializeAndReturn block, as
+ that is used even when CTI is enabled.
+
+ * VM/Machine.cpp:
+ (KJS::Machine::privateExecute):
+
+2008-09-03 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Replace calls to exit with ASSERT_WITH_MESSAGE or ASSERT_NOT_REACHED.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile_pass4_SlowCases):
+ * VM/Machine.cpp:
+ (KJS::Machine::privateExecute):
+ (KJS::Machine::cti_vm_throw):
+
+2008-09-03 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Tweak JavaScriptCore to compile on non-x86 platforms. This is achieved
+ by wrapping more code with ENABLE(CTI), ENABLE(WREC), and PLATFORM(X86)
+ #if's.
+
+ * VM/CTI.cpp:
+ * VM/CTI.h:
+ * VM/CodeBlock.cpp:
+ (KJS::CodeBlock::printStructureIDs): Use %td as the format specifier for
+ printing a ptrdiff_t.
+ * VM/Machine.cpp:
+ * VM/Machine.h:
+ * kjs/regexp.cpp:
+ (KJS::RegExp::RegExp):
+ (KJS::RegExp::~RegExp):
+ (KJS::RegExp::match):
+ * kjs/regexp.h:
+ * masm/IA32MacroAsm.h:
+ * wrec/WREC.cpp:
+ * wrec/WREC.h:
+ * wtf/Platform.h: Only enable CTI and WREC on x86. Add an extra define to
+ track whether any MASM-using features are enabled.
+
+2008-09-03 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Copy Geoff's array/string length optimization for CTI.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateArrayLengthTrampoline):
+ (KJS::CTI::privateStringLengthTrampoline):
+ * VM/CTI.h:
+ (KJS::CTI::compileArrayLengthTrampoline):
+ (KJS::CTI::compileStringLengthTrampoline):
+ * VM/Machine.cpp:
+ (KJS::Machine::Machine):
+ (KJS::Machine::getCtiArrayLengthTrampoline):
+ (KJS::Machine::getCtiStringLengthTrampoline):
+ (KJS::Machine::tryCtiCacheGetByID):
+ (KJS::Machine::cti_op_get_by_id_second):
+ * VM/Machine.h:
+ * kjs/JSString.h:
+ * kjs/ustring.h:
+
+2008-09-03 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Implement fast array accesses in CTI - 2-3% progression on sunspider.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::emitFastArithIntToImmNoCheck):
+ (KJS::CTI::compileOpCall):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile_pass4_SlowCases):
+ * VM/CTI.h:
+ * kjs/JSArray.h:
+
+2008-09-02 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Enable fast property access support in CTI.
+
+ * VM/CTI.cpp:
+ (KJS::ctiSetReturnAddress):
+ (KJS::ctiRepatchCallByReturnAddress):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile):
+ (KJS::CTI::privateCompileGetByIdSelf):
+ (KJS::CTI::privateCompileGetByIdProto):
+ (KJS::CTI::privateCompileGetByIdChain):
+ (KJS::CTI::privateCompilePutByIdReplace):
+ * VM/CTI.h:
+ (KJS::CTI::compileGetByIdSelf):
+ (KJS::CTI::compileGetByIdProto):
+ (KJS::CTI::compileGetByIdChain):
+ (KJS::CTI::compilePutByIdReplace):
+ * VM/CodeBlock.cpp:
+ (KJS::CodeBlock::~CodeBlock):
+ * VM/CodeBlock.h:
+ * VM/Machine.cpp:
+ (KJS::doSetReturnAddressVmThrowTrampoline):
+ (KJS::Machine::tryCtiCachePutByID):
+ (KJS::Machine::tryCtiCacheGetByID):
+ (KJS::Machine::cti_op_put_by_id):
+ (KJS::Machine::cti_op_put_by_id_second):
+ (KJS::Machine::cti_op_put_by_id_generic):
+ (KJS::Machine::cti_op_put_by_id_fail):
+ (KJS::Machine::cti_op_get_by_id):
+ (KJS::Machine::cti_op_get_by_id_second):
+ (KJS::Machine::cti_op_get_by_id_generic):
+ (KJS::Machine::cti_op_get_by_id_fail):
+ (KJS::Machine::cti_op_throw):
+ (KJS::Machine::cti_vm_throw):
+ * VM/Machine.h:
+ * kjs/JSCell.h:
+ * kjs/JSObject.h:
+ * kjs/PropertyMap.h:
+ * kjs/StructureID.cpp:
+ (KJS::StructureIDChain::StructureIDChain):
+ * masm/IA32MacroAsm.h:
+ (KJS::IA32MacroAssembler::emitCmpl_i32m):
+ (KJS::IA32MacroAssembler::emitMovl_mr):
+ (KJS::IA32MacroAssembler::emitMovl_rm):
+
+2008-09-02 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Mark Rowe.
+
+ A backslash (\) at the of a RegEx should produce an error.
+ Fixes fast/regex/test1.html.
+
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::parseEscape):
+
+2008-09-02 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Geoff Garen.
+
+ Link jumps for the slow case of op_loop_if_less. Fixes acid3.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass4_SlowCases):
+
+2008-09-01 Sam Weinig <sam@webkit.org>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Switch WREC on by default.
+
+ * wtf/Platform.h:
+
+2008-09-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Fix two failures in fast/regex/test1.html
+ - \- in a character class should be treated as a literal -
+ - A missing max quantifier needs to be treated differently than
+ a null max quantifier.
+
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::generateNonGreedyQuantifier):
+ (KJS::WRECompiler::generateGreedyQuantifier):
+ (KJS::WRECompiler::parseCharacterClass):
+ * wrec/WREC.h:
+ (KJS::Quantifier::Quantifier):
+
+2008-09-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Fix crash in fast/js/kde/evil-n.html
+
+ * kjs/regexp.cpp: Always pass a non-null offset vector to the wrec function.
+
+2008-09-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Mark Rowe.
+
+ Add pattern length limit fixing one test in fast/js.
+
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::compile):
+ * wrec/WREC.h:
+ (KJS::WRECompiler::):
+
+2008-09-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Mark Rowe.
+
+ Make octal escape parsing/back-reference parsing more closely match
+ prior behavior fixing one test in fast/js.
+
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::parseCharacterClass): 8 and 9 should be IdentityEscaped
+ (KJS::WRECompiler::parseEscape):
+ * wrec/WREC.h:
+ (KJS::WRECompiler::peekDigit):
+
+2008-09-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Mark Rowe.
+
+ Fix one mozilla test.
+
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::generateCharacterClassInverted): Fix incorrect not
+ ascii upper check.
+
+2008-09-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Mark Rowe.
+
+ Parse octal escapes in character classes fixing one mozilla test.
+
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::parseCharacterClass):
+ (KJS::WRECompiler::parseOctalEscape):
+ * wrec/WREC.h:
+ (KJS::WRECompiler::consumeOctal):
+
+2008-09-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Oliver Hunt.
+
+ Fixes two mozilla tests with WREC enabled.
+
+ * wrec/WREC.cpp:
+ (KJS::CharacterClassConstructor::append): Keep the character class sorted
+ when appending another character class.
+
+2008-09-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Mark Rowe.
+
+ Fixes two mozilla tests with WREC enabled.
+
+ * wrec/WREC.cpp:
+ (KJS::CharacterClassConstructor::addSortedRange): Insert the range at the correct position
+ instead of appending it to the end.
+
+2008-09-01 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Move cross-compilation unit call into NEVER_INLINE function.
+
+ * VM/Machine.cpp:
+ (KJS::doSetReturnAddressVmThrowTrampoline):
+
+2008-09-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Geoff Garen.
+
+ Fix one test in fast/js.
+
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_construct_NotJSConstruct): Throw a createNotAConstructorError,
+ instead of a createNotAFunctionError.
+
+2008-08-31 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Zero-cost exception handling. This patch takes the exception checking
+ back of the hot path. When an exception occurs in a Machine::cti*
+ method, the return address to JIT code is recorded, and is then
+ overwritten with a pointer to a trampoline routine. When the method
+ returns the trampoline will cause the cti_vm_throw method to be invoked.
+
+ cti_vm_throw uses the return address preserved above, to discover the
+ vPC of the bytecode that raised the exception (using a map build during
+ translation). From the VPC of the faulting bytecode the vPC of a catch
+ routine may be discovered (unwinding the stack where necesary), and then
+ a bytecode address for the catch routine is looked up. Final cti_vm_throw
+ overwrites its return address to JIT code again, to trampoline directly
+ to the catch routine.
+
+ cti_op_throw is handled in a similar fashion.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::emitPutCTIParam):
+ (KJS::CTI::emitPutToCallFrameHeader):
+ (KJS::CTI::emitGetFromCallFrameHeader):
+ (KJS::ctiSetReturnAddressForArgs):
+ (KJS::CTI::emitDebugExceptionCheck):
+ (KJS::CTI::printOpcodeOperandTypes):
+ (KJS::CTI::emitCall):
+ (KJS::CTI::compileOpCall):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile):
+ * VM/CTI.h:
+ (KJS::CallRecord::CallRecord):
+ (KJS::):
+ (KJS::CTI::execute):
+ * VM/CodeBlock.h:
+ * VM/Machine.cpp:
+ (KJS::Machine::privateExecute):
+ (KJS::Machine::cti_op_instanceof):
+ (KJS::Machine::cti_op_call_NotJSFunction):
+ (KJS::Machine::cti_op_resolve):
+ (KJS::Machine::cti_op_resolve_func):
+ (KJS::Machine::cti_op_resolve_skip):
+ (KJS::Machine::cti_op_resolve_with_base):
+ (KJS::Machine::cti_op_throw):
+ (KJS::Machine::cti_op_in):
+ (KJS::Machine::cti_vm_throw):
+ * VM/RegisterFile.h:
+ (KJS::RegisterFile::):
+ * kjs/ExecState.h:
+ (KJS::ExecState::setCtiReturnAddress):
+ (KJS::ExecState::ctiReturnAddress):
+ * masm/IA32MacroAsm.h:
+ (KJS::IA32MacroAssembler::):
+ (KJS::IA32MacroAssembler::emitPushl_m):
+ (KJS::IA32MacroAssembler::emitPopl_m):
+ (KJS::IA32MacroAssembler::getRelocatedAddress):
+
+2008-08-31 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Fall back to PCRE for any regexp containing parentheses until we correctly backtrack within them.
+
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::parseParentheses):
+ * wrec/WREC.h:
+ (KJS::WRECompiler::):
+
+2008-08-31 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Fix several issues within ecma_3/RegExp/perlstress-001.js with WREC enabled.
+
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::generateNonGreedyQuantifier): Compare with the maximum quantifier count rather than the minimum.
+ (KJS::WRECompiler::generateAssertionEOL): Do a register-to-register comparison rather than immediate-to-register.
+ (KJS::WRECompiler::parseCharacterClass): Pass through the correct inversion flag.
+
+2008-08-30 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Re-fix the six remaining failures in the Mozilla JavaScript tests in a manner that does not kill performance.
+ This shows up as a 0.6% progression on SunSpider on my machine.
+
+ Grow the JITCodeBuffer's underlying buffer when we run out of space rather than just bailing out.
+
+ * VM/CodeBlock.h:
+ (KJS::CodeBlock::~CodeBlock): Switch to using fastFree now that JITCodeBuffer::copy uses fastMalloc.
+ * kjs/regexp.cpp: Ditto.
+ * masm/IA32MacroAsm.h:
+ (KJS::JITCodeBuffer::growBuffer):
+ (KJS::JITCodeBuffer::JITCodeBuffer):
+ (KJS::JITCodeBuffer::~JITCodeBuffer):
+ (KJS::JITCodeBuffer::putByte):
+ (KJS::JITCodeBuffer::putShort):
+ (KJS::JITCodeBuffer::putInt):
+ (KJS::JITCodeBuffer::reset):
+ (KJS::JITCodeBuffer::copy):
+
+2008-08-29 Oliver Hunt <oliver@apple.com>
+
+ RS=Maciej
+
+ Roll out previous patch as it causes a 5% performance regression
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * VM/CTI.cpp:
+ (KJS::getJCB):
+ (KJS::CTI::privateCompile):
+ * VM/CodeBlock.h:
+ (KJS::CodeBlock::~CodeBlock):
+ * masm/IA32MacroAsm.h:
+ (KJS::JITCodeBuffer::JITCodeBuffer):
+ (KJS::JITCodeBuffer::putByte):
+ (KJS::JITCodeBuffer::putShort):
+ (KJS::JITCodeBuffer::putInt):
+ (KJS::JITCodeBuffer::getEIP):
+ (KJS::JITCodeBuffer::start):
+ (KJS::JITCodeBuffer::getOffset):
+ (KJS::JITCodeBuffer::reset):
+ (KJS::JITCodeBuffer::copy):
+ (KJS::IA32MacroAssembler::emitModRm_rr):
+ (KJS::IA32MacroAssembler::emitModRm_rm):
+ (KJS::IA32MacroAssembler::emitModRm_rmsib):
+ (KJS::IA32MacroAssembler::IA32MacroAssembler):
+ (KJS::IA32MacroAssembler::emitInt3):
+ (KJS::IA32MacroAssembler::emitPushl_r):
+ (KJS::IA32MacroAssembler::emitPopl_r):
+ (KJS::IA32MacroAssembler::emitMovl_rr):
+ (KJS::IA32MacroAssembler::emitAddl_rr):
+ (KJS::IA32MacroAssembler::emitAddl_i8r):
+ (KJS::IA32MacroAssembler::emitAddl_i32r):
+ (KJS::IA32MacroAssembler::emitAddl_mr):
+ (KJS::IA32MacroAssembler::emitAndl_rr):
+ (KJS::IA32MacroAssembler::emitAndl_i32r):
+ (KJS::IA32MacroAssembler::emitCmpl_i8r):
+ (KJS::IA32MacroAssembler::emitCmpl_rr):
+ (KJS::IA32MacroAssembler::emitCmpl_rm):
+ (KJS::IA32MacroAssembler::emitCmpl_i32r):
+ (KJS::IA32MacroAssembler::emitCmpl_i32m):
+ (KJS::IA32MacroAssembler::emitCmpw_rm):
+ (KJS::IA32MacroAssembler::emitOrl_rr):
+ (KJS::IA32MacroAssembler::emitOrl_i8r):
+ (KJS::IA32MacroAssembler::emitSubl_rr):
+ (KJS::IA32MacroAssembler::emitSubl_i8r):
+ (KJS::IA32MacroAssembler::emitSubl_i32r):
+ (KJS::IA32MacroAssembler::emitSubl_mr):
+ (KJS::IA32MacroAssembler::emitTestl_i32r):
+ (KJS::IA32MacroAssembler::emitTestl_rr):
+ (KJS::IA32MacroAssembler::emitXorl_i8r):
+ (KJS::IA32MacroAssembler::emitXorl_rr):
+ (KJS::IA32MacroAssembler::emitSarl_i8r):
+ (KJS::IA32MacroAssembler::emitSarl_CLr):
+ (KJS::IA32MacroAssembler::emitShl_i8r):
+ (KJS::IA32MacroAssembler::emitShll_CLr):
+ (KJS::IA32MacroAssembler::emitMull_rr):
+ (KJS::IA32MacroAssembler::emitIdivl_r):
+ (KJS::IA32MacroAssembler::emitCdq):
+ (KJS::IA32MacroAssembler::emitMovl_mr):
+ (KJS::IA32MacroAssembler::emitMovzwl_mr):
+ (KJS::IA32MacroAssembler::emitMovl_rm):
+ (KJS::IA32MacroAssembler::emitMovl_i32r):
+ (KJS::IA32MacroAssembler::emitMovl_i32m):
+ (KJS::IA32MacroAssembler::emitLeal_mr):
+ (KJS::IA32MacroAssembler::emitRet):
+ (KJS::IA32MacroAssembler::emitJmpN_r):
+ (KJS::IA32MacroAssembler::emitJmpN_m):
+ (KJS::IA32MacroAssembler::emitCall):
+ (KJS::IA32MacroAssembler::label):
+ (KJS::IA32MacroAssembler::emitUnlinkedJmp):
+ (KJS::IA32MacroAssembler::emitUnlinkedJne):
+ (KJS::IA32MacroAssembler::emitUnlinkedJe):
+ (KJS::IA32MacroAssembler::emitUnlinkedJl):
+ (KJS::IA32MacroAssembler::emitUnlinkedJle):
+ (KJS::IA32MacroAssembler::emitUnlinkedJge):
+ (KJS::IA32MacroAssembler::emitUnlinkedJae):
+ (KJS::IA32MacroAssembler::emitUnlinkedJo):
+ (KJS::IA32MacroAssembler::link):
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::compilePattern):
+ (KJS::WRECompiler::compile):
+ * wrec/WREC.h:
+
+2008-08-29 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Have JITCodeBuffer manage a Vector containing the generated code so that it can grow
+ as needed when generating code for a large function. This fixes all six remaining failures
+ in Mozilla tests in both debug and release builds.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile):
+ * VM/CodeBlock.h:
+ (KJS::CodeBlock::~CodeBlock):
+ * masm/IA32MacroAsm.h:
+ (KJS::JITCodeBuffer::putByte):
+ (KJS::JITCodeBuffer::putShort):
+ (KJS::JITCodeBuffer::putInt):
+ (KJS::JITCodeBuffer::getEIP):
+ (KJS::JITCodeBuffer::start):
+ (KJS::JITCodeBuffer::getOffset):
+ (KJS::JITCodeBuffer::getCode):
+ (KJS::IA32MacroAssembler::emitModRm_rr):
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::compilePattern):
+ * wrec/WREC.h:
+
+2008-08-29 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Implement parsing of octal escapes in regular expressions. This fixes three Mozilla tests.
+
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::parseOctalEscape):
+ (KJS::WRECompiler::parseEscape): Parse the escape sequence as an octal escape if it has a leading zero.
+ Add a FIXME about treating invalid backreferences as octal escapes in the future.
+ * wrec/WREC.h:
+ (KJS::WRECompiler::consumeNumber): Multiply by 10 rather than 0 so that we handle numbers with more than
+ one digit.
+ * wtf/ASCIICType.h:
+ (WTF::isASCIIOctalDigit):
+
+2008-08-29 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Pass vPC to instanceof method. Fixes 2 mozilla tests in debug.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_instanceof):
+
+2008-08-29 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Pass vPCs to resolve methods for correct exception creation. Fixes
+ 17 mozilla tests in debug.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/CTI.h:
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_resolve):
+ (KJS::Machine::cti_op_resolve_func):
+ (KJS::Machine::cti_op_resolve_skip):
+ (KJS::Machine::cti_op_resolve_with_base):
+
+2008-08-29 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Remembering to actually throw the exception passed to op throw helps.
+ Regressions 19 -> 6.
+
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_throw):
+ (KJS::Machine::cti_vm_throw):
+
+2008-08-29 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Support for exception unwinding the stack.
+
+ Once upon a time, Sam asked me for a bettr ChangeLog entry. The return address
+ is now preserved on entry to a JIT code function (if we preserve lazily we need
+ restore the native return address during exception stack unwind). This takes
+ the number of regressions down from ~150 to 19.
+
+ * VM/CTI.cpp:
+ (KJS::getJCB):
+ (KJS::CTI::emitExceptionCheck):
+ (KJS::CTI::compileOpCall):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile):
+ * VM/CTI.h:
+ (KJS::):
+ * VM/Machine.cpp:
+ (KJS::Machine::throwException):
+ (KJS::Machine::cti_op_call_JSFunction):
+ (KJS::Machine::cti_op_call_NotJSFunction):
+ (KJS::Machine::cti_op_construct_JSConstruct):
+ (KJS::Machine::cti_op_construct_NotJSConstruct):
+ (KJS::Machine::cti_op_throw):
+ (KJS::Machine::cti_vm_throw):
+
+2008-08-29 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Fix js1_2/regexp/word_boundary.js and four other Mozilla tests with WREC enabled.
+
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::generateCharacterClassInvertedRange): If none of the exact matches
+ succeeded, jump to failure.
+ (KJS::WRECompiler::compilePattern): Restore and increment the current position stored
+ on the stack to ensure that it will be reset to the correct position after a failed
+ match has consumed input.
+
+2008-08-29 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Fix a hang in ecma_3/RegExp/15.10.2-1.js with WREC enabled.
+ A backreference with a quantifier would get stuck in an infinite
+ loop if the captured range was empty.
+
+ * wrec/WREC.cpp:
+ (KJS::WRECompiler::generateBackreferenceQuantifier): If the captured range
+ was empty, do not attempt to match the backreference.
+ (KJS::WRECompiler::parseBackreferenceQuantifier):
+ * wrec/WREC.h:
+ (KJS::Quantifier::):
+
+2008-08-28 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Oliver Hunt.
+
+ Implement op_debug.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::debug):
+ (KJS::Machine::privateExecute):
+ (KJS::Machine::cti_op_debug):
+ * VM/Machine.h:
+
+2008-08-28 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Geoff Garen.
+
+ Implement op_switch_string fixing 1 mozilla test and one test in fast/js.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile):
+ * VM/CTI.h:
+ (KJS::SwitchRecord::):
+ (KJS::SwitchRecord::SwitchRecord):
+ * VM/CodeBlock.cpp:
+ (KJS::CodeBlock::dump):
+ * VM/CodeBlock.h:
+ (KJS::ExpressionRangeInfo::):
+ (KJS::StringJumpTable::offsetForValue):
+ (KJS::StringJumpTable::ctiForValue):
+ (KJS::SimpleJumpTable::add):
+ (KJS::SimpleJumpTable::ctiForValue):
+ * VM/CodeGenerator.cpp:
+ (KJS::prepareJumpTableForStringSwitch):
+ * VM/Machine.cpp:
+ (KJS::Machine::privateExecute):
+ (KJS::Machine::cti_op_switch_string):
+ * VM/Machine.h:
+
+2008-08-28 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Do not recurse on the machine stack when executing op_call.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::emitGetPutArg):
+ (KJS::CTI::emitPutArg):
+ (KJS::CTI::emitPutArgConstant):
+ (KJS::CTI::compileOpCall):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile):
+ * VM/CTI.h:
+ (KJS::):
+ (KJS::CTI::compile):
+ (KJS::CTI::execute):
+ (KJS::CTI::):
+ * VM/Machine.cpp:
+ (KJS::Machine::Machine):
+ (KJS::Machine::execute):
+ (KJS::Machine::cti_op_call_JSFunction):
+ (KJS::Machine::cti_op_call_NotJSFunction):
+ (KJS::Machine::cti_op_ret):
+ (KJS::Machine::cti_op_construct_JSConstruct):
+ (KJS::Machine::cti_op_construct_NotJSConstruct):
+ (KJS::Machine::cti_op_call_eval):
+ * VM/Machine.h:
+ * VM/Register.h:
+ (KJS::Register::Register):
+ * VM/RegisterFile.h:
+ (KJS::RegisterFile::):
+ * kjs/InternalFunction.h:
+ (KJS::InternalFunction::InternalFunction):
+ * kjs/JSFunction.h:
+ (KJS::JSFunction::JSFunction):
+ * kjs/ScopeChain.h:
+ (KJS::ScopeChain::ScopeChain):
+ * masm/IA32MacroAsm.h:
+ (KJS::IA32MacroAssembler::):
+ (KJS::IA32MacroAssembler::emitModRm_opm):
+ (KJS::IA32MacroAssembler::emitCmpl_i32m):
+ (KJS::IA32MacroAssembler::emitCallN_r):
+
+2008-08-28 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Exit instead of crashing in ctiUnsupported and ctiTimedOut.
+
+ * VM/Machine.cpp:
+ (KJS::ctiUnsupported):
+ (KJS::ctiTimedOut):
+
+2008-08-28 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Implement codegen for op_jsr and op_sret.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile):
+ * VM/CTI.h:
+ (KJS::CTI::JSRInfo::JSRInfo):
+ * masm/IA32MacroAsm.h:
+ (KJS::IA32MacroAssembler::emitJmpN_m):
+ (KJS::IA32MacroAssembler::linkAbsoluteAddress):
+
+2008-08-28 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Initial support for exceptions (throw / catch must occur in same CodeBlock).
+
+ * VM/CTI.cpp:
+ (KJS::CTI::emitExceptionCheck):
+ (KJS::CTI::emitCall):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile_pass4_SlowCases):
+ (KJS::CTI::privateCompile):
+ * VM/CTI.h:
+ * VM/CodeBlock.cpp:
+ (KJS::CodeBlock::nativeExceptionCodeForHandlerVPC):
+ * VM/CodeBlock.h:
+ * VM/CodeGenerator.cpp:
+ (KJS::CodeGenerator::emitCatch):
+ * VM/Machine.cpp:
+ (KJS::Machine::throwException):
+ (KJS::Machine::privateExecute):
+ (KJS::ctiUnsupported):
+ (KJS::ctiTimedOut):
+ (KJS::Machine::cti_op_add):
+ (KJS::Machine::cti_op_pre_inc):
+ (KJS::Machine::cti_timeout_check):
+ (KJS::Machine::cti_op_loop_if_less):
+ (KJS::Machine::cti_op_put_by_id):
+ (KJS::Machine::cti_op_get_by_id):
+ (KJS::Machine::cti_op_instanceof):
+ (KJS::Machine::cti_op_del_by_id):
+ (KJS::Machine::cti_op_mul):
+ (KJS::Machine::cti_op_call):
+ (KJS::Machine::cti_op_resolve):
+ (KJS::Machine::cti_op_construct):
+ (KJS::Machine::cti_op_get_by_val):
+ (KJS::Machine::cti_op_resolve_func):
+ (KJS::Machine::cti_op_sub):
+ (KJS::Machine::cti_op_put_by_val):
+ (KJS::Machine::cti_op_lesseq):
+ (KJS::Machine::cti_op_loop_if_true):
+ (KJS::Machine::cti_op_negate):
+ (KJS::Machine::cti_op_resolve_skip):
+ (KJS::Machine::cti_op_div):
+ (KJS::Machine::cti_op_pre_dec):
+ (KJS::Machine::cti_op_jless):
+ (KJS::Machine::cti_op_not):
+ (KJS::Machine::cti_op_jtrue):
+ (KJS::Machine::cti_op_post_inc):
+ (KJS::Machine::cti_op_eq):
+ (KJS::Machine::cti_op_lshift):
+ (KJS::Machine::cti_op_bitand):
+ (KJS::Machine::cti_op_rshift):
+ (KJS::Machine::cti_op_bitnot):
+ (KJS::Machine::cti_op_resolve_with_base):
+ (KJS::Machine::cti_op_mod):
+ (KJS::Machine::cti_op_less):
+ (KJS::Machine::cti_op_neq):
+ (KJS::Machine::cti_op_post_dec):
+ (KJS::Machine::cti_op_urshift):
+ (KJS::Machine::cti_op_bitxor):
+ (KJS::Machine::cti_op_bitor):
+ (KJS::Machine::cti_op_call_eval):
+ (KJS::Machine::cti_op_throw):
+ (KJS::Machine::cti_op_push_scope):
+ (KJS::Machine::cti_op_stricteq):
+ (KJS::Machine::cti_op_nstricteq):
+ (KJS::Machine::cti_op_to_jsnumber):
+ (KJS::Machine::cti_op_in):
+ (KJS::Machine::cti_op_del_by_val):
+ (KJS::Machine::cti_vm_throw):
+ * VM/Machine.h:
+ * kjs/ExecState.h:
+ * masm/IA32MacroAsm.h:
+ (KJS::IA32MacroAssembler::emitCmpl_i32m):
+
+2008-08-28 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Oliver Hunt.
+
+ Print debugging info to stderr so that run-webkit-tests can capture it.
+ This makes it easy to check whether test failures are due to unimplemented
+ op codes, missing support for exceptions, etc.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::printOpcodeOperandTypes):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile_pass4_SlowCases):
+ (KJS::CTI::privateCompile):
+ * VM/Machine.cpp:
+ (KJS::Machine::privateExecute):
+ (KJS::ctiException):
+ (KJS::ctiUnsupported):
+ (KJS::Machine::cti_op_call):
+ (KJS::Machine::cti_op_resolve):
+ (KJS::Machine::cti_op_construct):
+ (KJS::Machine::cti_op_get_by_val):
+ (KJS::Machine::cti_op_resolve_func):
+ (KJS::Machine::cti_op_resolve_skip):
+ (KJS::Machine::cti_op_resolve_with_base):
+ (KJS::Machine::cti_op_call_eval):
+
+2008-08-27 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Gavin Barraclough and Maciej Stachowiak.
+
+ Fix fast/js/bitwise-and-on-undefined.html.
+
+ A temporary value in the slow path of op_bitand was being stored in edx, but was
+ being clobbered by emitGetPutArg before we used it. To fix this, emitGetPutArg
+ now takes a third argument that specifies the scratch register to use when loading
+ from memory. This allows us to avoid clobbering the temporary in op_bitand.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::emitGetPutArg):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile_pass4_SlowCases):
+ * VM/CTI.h:
+
+2008-08-27 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Oliver Hunt.
+
+ Switch CTI on by default.
+
+ * wtf/Platform.h:
+
+2008-08-27 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Fix the build of the full WebKit stack.
+
+ * JavaScriptCore.xcodeproj/project.pbxproj: Mark two new headers as private so they can be pulled in from WebCore.
+ * VM/CTI.h: Fix build issues that show up when compiled with GCC 4.2 as part of WebCore.
+ * wrec/WREC.h: Ditto.
+
+2008-08-27 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Implement op_new_error. Does not fix any tests as it is always followed by the unimplemented op_throw.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_new_error):
+ * VM/Machine.h:
+
+2008-08-27 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Geoff Garen.
+
+ Implement op_put_getter and op_put_setter.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_put_getter):
+ (KJS::Machine::cti_op_put_setter):
+ * VM/Machine.h:
+
+2008-08-27 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Geoff Garen.
+
+ Implement op_del_by_val fixing 3 mozilla tests.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_del_by_val):
+ * VM/Machine.h:
+
+2008-08-27 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Quick & dirty fix to get SamplingTool sampling op_call.
+
+ * VM/SamplingTool.h:
+ (KJS::SamplingTool::callingHostFunction):
+
+2008-08-27 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Geoff Garen.
+
+ Fix op_put_by_index.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass2_Main): Use emitPutArgConstant instead of emitGetPutArg
+ for the property value.
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_put_by_index): Get the property value from the correct argument.
+
+2008-08-27 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Geoff Garen.
+
+ Implement op_switch_imm in the CTI fixing 13 mozilla tests.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_switch_imm):
+ * VM/Machine.h:
+
+2008-08-27 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Implement op_switch_char in CTI.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::emitCall):
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile):
+ * VM/CTI.h:
+ (KJS::CallRecord::CallRecord):
+ (KJS::SwitchRecord::SwitchRecord):
+ * VM/CodeBlock.h:
+ (KJS::SimpleJumpTable::SimpleJumpTable::ctiForValue):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_switch_char):
+ * VM/Machine.h:
+ * masm/IA32MacroAsm.h:
+ (KJS::IA32MacroAssembler::):
+ (KJS::IA32MacroAssembler::emitJmpN_r):
+ (KJS::IA32MacroAssembler::getRelocatedAddress):
+ * wtf/Platform.h:
+
+2008-08-26 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Implement op_put_by_index to fix 1 mozilla test.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_put_by_index):
+ * VM/Machine.h:
+
+2008-08-26 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ More fixes from Geoff's review.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::emitGetArg):
+ (KJS::CTI::emitGetPutArg):
+ (KJS::CTI::emitPutArg):
+ (KJS::CTI::emitPutArgConstant):
+ (KJS::CTI::getConstantImmediateNumericArg):
+ (KJS::CTI::emitGetCTIParam):
+ (KJS::CTI::emitPutResult):
+ (KJS::CTI::emitCall):
+ (KJS::CTI::emitJumpSlowCaseIfNotImm):
+ (KJS::CTI::emitJumpSlowCaseIfNotImms):
+ (KJS::CTI::getDeTaggedConstantImmediate):
+ (KJS::CTI::emitFastArithDeTagImmediate):
+ (KJS::CTI::emitFastArithReTagImmediate):
+ (KJS::CTI::emitFastArithPotentiallyReTagImmediate):
+ (KJS::CTI::emitFastArithImmToInt):
+ (KJS::CTI::emitFastArithIntToImmOrSlowCase):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile_pass4_SlowCases):
+ (KJS::CTI::privateCompile):
+ * VM/CTI.h:
+
+2008-08-26 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Gavin Barraclough and Geoff Garen.
+
+ Implement op_jmp_scopes to fix 2 Mozilla tests.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_push_new_scope): Update ExecState::m_scopeChain after calling ARG_setScopeChain.
+ (KJS::Machine::cti_op_jmp_scopes):
+ * VM/Machine.h:
+
+2008-08-26 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ WebKit Regular Expression Compiler. (set ENABLE_WREC = 1 in Platform.h).
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * kjs/regexp.cpp:
+ * kjs/regexp.h:
+ * wrec: Added.
+ * wrec/WREC.cpp: Added.
+ * wrec/WREC.h: Added.
+ * wtf/Platform.h:
+
+2008-08-26 Sam Weinig <sam@webkit.org>
+
+ Rubber-stamped by Oliver Hunt.
+
+ Remove bogus assertion.
+
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_del_by_id):
+
+2008-08-26 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Implement op_push_new_scope and stub out op_catch. This fixes 11 Mozilla tests.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_push_new_scope):
+ (KJS::Machine::cti_op_catch):
+ * VM/Machine.h:
+
+2008-08-26 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Clean up op_resolve_base so that it shares its implementation with the bytecode interpreter.
+
+ * VM/Machine.cpp:
+ (KJS::inlineResolveBase):
+ (KJS::resolveBase):
+
+2008-08-26 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Add codegen support for op_instanceof, fixing 15 mozilla tests.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_instanceof):
+ (KJS::Machine::cti_op_del_by_id):
+ * VM/Machine.h:
+ * wtf/Platform.h:
+
+2008-08-26 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ Fixes for initial review comments.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::ctiCompileGetArg):
+ (KJS::CTI::ctiCompileGetPutArg):
+ (KJS::CTI::ctiCompilePutResult):
+ (KJS::CTI::ctiCompileCall):
+ (KJS::CTI::CTI):
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::printOpcodeOperandTypes):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile_pass4_SlowCases):
+ (KJS::CTI::privateCompile):
+ * VM/CTI.h:
+ * VM/Register.h:
+ * kjs/JSValue.h:
+
+2008-08-26 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Geoff Garen.
+
+ Fix up exception checking code.
+
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_call):
+ (KJS::Machine::cti_op_resolve):
+ (KJS::Machine::cti_op_construct):
+ (KJS::Machine::cti_op_resolve_func):
+ (KJS::Machine::cti_op_resolve_skip):
+ (KJS::Machine::cti_op_resolve_with_base):
+ (KJS::Machine::cti_op_call_eval):
+
+2008-08-26 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Oliver Hunt.
+
+ Fix slowcase for op_post_inc and op_post_dec fixing 2 mozilla tests.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass4_SlowCases):
+
+2008-08-26 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Implement op_in, fixing 8 mozilla tests.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_in):
+ * VM/Machine.h:
+
+2008-08-26 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Oliver Hunt.
+
+ Don't hardcode the size of a Register for op_new_array. Fixes a crash
+ seen during the Mozilla tests.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass2_Main):
+
+2008-08-26 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Geoff Garen.
+
+ Add support for op_push_scope and op_pop_scope, fixing 20 mozilla tests.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/CTI.h:
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_push_scope):
+ (KJS::Machine::cti_op_pop_scope):
+ * VM/Machine.h:
+
+2008-08-26 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Add codegen support for op_del_by_id, fixing 49 mozilla tests.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+ * VM/Machine.cpp:
+ (KJS::Machine::cti_op_del_by_id):
+ * VM/Machine.h:
+
+2008-08-26 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough and Geoff Garen.
+
+ Don't hardcode the size of a Register for op_get_scoped_var and op_put_scoped_var
+ fixing 513 mozilla tests in debug build.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass2_Main):
+
+2008-08-26 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Added code generator support for op_loop, fixing around 60 mozilla tests.
+
+ * VM/CTI.cpp:
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::privateCompile_pass2_Main):
+
+2008-08-26 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Set -fomit-frame-pointer in the correct location.
+
+ * Configurations/JavaScriptCore.xcconfig:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+
+2008-08-26 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ Inital cut of CTI, Geoff's review fixes to follow.
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * VM/CTI.cpp: Added.
+ (KJS::getJCB):
+ (KJS::CTI::ctiCompileGetArg):
+ (KJS::CTI::ctiCompileGetPutArg):
+ (KJS::CTI::ctiCompilePutArg):
+ (KJS::CTI::ctiCompilePutArgImm):
+ (KJS::CTI::ctiImmediateNumericArg):
+ (KJS::CTI::ctiCompileGetCTIParam):
+ (KJS::CTI::ctiCompilePutResult):
+ (KJS::CTI::ctiCompileCall):
+ (KJS::CTI::slowCaseIfNotImm):
+ (KJS::CTI::slowCaseIfNotImms):
+ (KJS::CTI::ctiFastArithDeTagConstImmediate):
+ (KJS::CTI::ctiFastArithDeTagImmediate):
+ (KJS::CTI::ctiFastArithReTagImmediate):
+ (KJS::CTI::ctiFastArithPotentiallyReTagImmediate):
+ (KJS::CTI::ctiFastArithImmToInt):
+ (KJS::CTI::ctiFastArithIntToImmOrSlowCase):
+ (KJS::CTI::CTI):
+ (KJS::CTI::privateCompile_pass1_Scan):
+ (KJS::CTI::ctiCompileAdd):
+ (KJS::CTI::ctiCompileAddImm):
+ (KJS::CTI::ctiCompileAddImmNotInt):
+ (KJS::CTI::TEMP_HACK_PRINT_TYPES):
+ (KJS::CTI::privateCompile_pass2_Main):
+ (KJS::CTI::privateCompile_pass3_Link):
+ (KJS::CTI::privateCompile_pass4_SlowCases):
+ (KJS::CTI::privateCompile):
+ * VM/CTI.h: Added.
+ (KJS::CTI2Result::CTI2Result):
+ (KJS::CallRecord::CallRecord):
+ (KJS::JmpTable::JmpTable):
+ (KJS::SlowCaseEntry::SlowCaseEntry):
+ (KJS::CTI::compile):
+ (KJS::CTI::LabelInfo::LabelInfo):
+ * VM/CodeBlock.h:
+ (KJS::CodeBlock::CodeBlock):
+ (KJS::CodeBlock::~CodeBlock):
+ * VM/Machine.cpp:
+ (KJS::Machine::execute):
+ (KJS::Machine::privateExecute):
+ (KJS::ctiException):
+ (KJS::ctiUnsupported):
+ (KJS::ctiTimedOut):
+ (KJS::Machine::cti_op_end):
+ (KJS::Machine::cti_op_add):
+ (KJS::Machine::cti_op_pre_inc):
+ (KJS::Machine::cti_timeout_check):
+ (KJS::Machine::cti_op_loop_if_less):
+ (KJS::Machine::cti_op_new_object):
+ (KJS::Machine::cti_op_put_by_id):
+ (KJS::Machine::cti_op_get_by_id):
+ (KJS::Machine::cti_op_mul):
+ (KJS::Machine::cti_op_new_func):
+ (KJS::Machine::cti_op_call):
+ (KJS::Machine::cti_op_ret):
+ (KJS::Machine::cti_op_new_array):
+ (KJS::Machine::cti_op_resolve):
+ (KJS::Machine::cti_op_construct):
+ (KJS::Machine::cti_op_get_by_val):
+ (KJS::Machine::cti_op_resolve_func):
+ (KJS::Machine::cti_op_sub):
+ (KJS::Machine::cti_op_put_by_val):
+ (KJS::Machine::cti_op_lesseq):
+ (KJS::Machine::cti_op_loop_if_true):
+ (KJS::Machine::cti_op_negate):
+ (KJS::Machine::cti_op_resolve_base):
+ (KJS::Machine::cti_op_resolve_skip):
+ (KJS::Machine::cti_op_div):
+ (KJS::Machine::cti_op_pre_dec):
+ (KJS::Machine::cti_op_jless):
+ (KJS::Machine::cti_op_not):
+ (KJS::Machine::cti_op_jtrue):
+ (KJS::Machine::cti_op_post_inc):
+ (KJS::Machine::cti_op_eq):
+ (KJS::Machine::cti_op_lshift):
+ (KJS::Machine::cti_op_bitand):
+ (KJS::Machine::cti_op_rshift):
+ (KJS::Machine::cti_op_bitnot):
+ (KJS::Machine::cti_op_resolve_with_base):
+ (KJS::Machine::cti_op_new_func_exp):
+ (KJS::Machine::cti_op_mod):
+ (KJS::Machine::cti_op_less):
+ (KJS::Machine::cti_op_neq):
+ (KJS::Machine::cti_op_post_dec):
+ (KJS::Machine::cti_op_urshift):
+ (KJS::Machine::cti_op_bitxor):
+ (KJS::Machine::cti_op_new_regexp):
+ (KJS::Machine::cti_op_bitor):
+ (KJS::Machine::cti_op_call_eval):
+ (KJS::Machine::cti_op_throw):
+ (KJS::Machine::cti_op_get_pnames):
+ (KJS::Machine::cti_op_next_pname):
+ (KJS::Machine::cti_op_typeof):
+ (KJS::Machine::cti_op_stricteq):
+ (KJS::Machine::cti_op_nstricteq):
+ (KJS::Machine::cti_op_to_jsnumber):
+ * VM/Machine.h:
+ * VM/Register.h:
+ (KJS::Register::jsValue):
+ (KJS::Register::getJSValue):
+ (KJS::Register::codeBlock):
+ (KJS::Register::scopeChain):
+ (KJS::Register::i):
+ (KJS::Register::r):
+ (KJS::Register::vPC):
+ (KJS::Register::jsPropertyNameIterator):
+ * VM/SamplingTool.cpp:
+ (KJS::):
+ (KJS::SamplingTool::run):
+ (KJS::SamplingTool::dump):
+ * VM/SamplingTool.h:
+ * kjs/JSImmediate.h:
+ (KJS::JSImmediate::zeroImmediate):
+ (KJS::JSImmediate::oneImmediate):
+ * kjs/JSValue.h:
+ * kjs/JSVariableObject.h:
+ (KJS::JSVariableObject::JSVariableObjectData::offsetOf_registers):
+ (KJS::JSVariableObject::offsetOf_d):
+ (KJS::JSVariableObject::offsetOf_Data_registers):
+ * masm: Added.
+ * masm/IA32MacroAsm.h: Added.
+ (KJS::JITCodeBuffer::JITCodeBuffer):
+ (KJS::JITCodeBuffer::putByte):
+ (KJS::JITCodeBuffer::putShort):
+ (KJS::JITCodeBuffer::putInt):
+ (KJS::JITCodeBuffer::getEIP):
+ (KJS::JITCodeBuffer::start):
+ (KJS::JITCodeBuffer::getOffset):
+ (KJS::JITCodeBuffer::reset):
+ (KJS::JITCodeBuffer::copy):
+ (KJS::IA32MacroAssembler::):
+ (KJS::IA32MacroAssembler::emitModRm_rr):
+ (KJS::IA32MacroAssembler::emitModRm_rm):
+ (KJS::IA32MacroAssembler::emitModRm_rmsib):
+ (KJS::IA32MacroAssembler::emitModRm_opr):
+ (KJS::IA32MacroAssembler::emitModRm_opm):
+ (KJS::IA32MacroAssembler::IA32MacroAssembler):
+ (KJS::IA32MacroAssembler::emitInt3):
+ (KJS::IA32MacroAssembler::emitPushl_r):
+ (KJS::IA32MacroAssembler::emitPopl_r):
+ (KJS::IA32MacroAssembler::emitMovl_rr):
+ (KJS::IA32MacroAssembler::emitAddl_rr):
+ (KJS::IA32MacroAssembler::emitAddl_i8r):
+ (KJS::IA32MacroAssembler::emitAddl_i32r):
+ (KJS::IA32MacroAssembler::emitAddl_mr):
+ (KJS::IA32MacroAssembler::emitAndl_rr):
+ (KJS::IA32MacroAssembler::emitAndl_i32r):
+ (KJS::IA32MacroAssembler::emitCmpl_i8r):
+ (KJS::IA32MacroAssembler::emitCmpl_rr):
+ (KJS::IA32MacroAssembler::emitCmpl_rm):
+ (KJS::IA32MacroAssembler::emitCmpl_i32r):
+ (KJS::IA32MacroAssembler::emitCmpw_rm):
+ (KJS::IA32MacroAssembler::emitOrl_rr):
+ (KJS::IA32MacroAssembler::emitOrl_i8r):
+ (KJS::IA32MacroAssembler::emitSubl_rr):
+ (KJS::IA32MacroAssembler::emitSubl_i8r):
+ (KJS::IA32MacroAssembler::emitSubl_i32r):
+ (KJS::IA32MacroAssembler::emitSubl_mr):
+ (KJS::IA32MacroAssembler::emitTestl_i32r):
+ (KJS::IA32MacroAssembler::emitTestl_rr):
+ (KJS::IA32MacroAssembler::emitXorl_i8r):
+ (KJS::IA32MacroAssembler::emitXorl_rr):
+ (KJS::IA32MacroAssembler::emitSarl_i8r):
+ (KJS::IA32MacroAssembler::emitSarl_CLr):
+ (KJS::IA32MacroAssembler::emitShl_i8r):
+ (KJS::IA32MacroAssembler::emitShll_CLr):
+ (KJS::IA32MacroAssembler::emitMull_rr):
+ (KJS::IA32MacroAssembler::emitIdivl_r):
+ (KJS::IA32MacroAssembler::emitCdq):
+ (KJS::IA32MacroAssembler::emitMovl_mr):
+ (KJS::IA32MacroAssembler::emitMovzwl_mr):
+ (KJS::IA32MacroAssembler::emitMovl_rm):
+ (KJS::IA32MacroAssembler::emitMovl_i32r):
+ (KJS::IA32MacroAssembler::emitMovl_i32m):
+ (KJS::IA32MacroAssembler::emitLeal_mr):
+ (KJS::IA32MacroAssembler::emitRet):
+ (KJS::IA32MacroAssembler::JmpSrc::JmpSrc):
+ (KJS::IA32MacroAssembler::JmpDst::JmpDst):
+ (KJS::IA32MacroAssembler::emitCall):
+ (KJS::IA32MacroAssembler::label):
+ (KJS::IA32MacroAssembler::emitUnlinkedJmp):
+ (KJS::IA32MacroAssembler::emitUnlinkedJne):
+ (KJS::IA32MacroAssembler::emitUnlinkedJe):
+ (KJS::IA32MacroAssembler::emitUnlinkedJl):
+ (KJS::IA32MacroAssembler::emitUnlinkedJle):
+ (KJS::IA32MacroAssembler::emitUnlinkedJge):
+ (KJS::IA32MacroAssembler::emitUnlinkedJae):
+ (KJS::IA32MacroAssembler::emitUnlinkedJo):
+ (KJS::IA32MacroAssembler::emitPredictionNotTaken):
+ (KJS::IA32MacroAssembler::link):
+ (KJS::IA32MacroAssembler::copy):
+ * wtf/Platform.h:
+
+2008-08-26 Oliver Hunt <oliver@apple.com>
+
+ RS=Maciej.
+
+ Enabled -fomit-frame-pointer on Release and Production builds, add additional Profiling build config for shark, etc.
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+
+=== Start merge of squirrelfish-extreme ===
+
2008-09-06 Cameron Zwarich <cwzwarich@uwaterloo.ca>
Reviewed by Maciej Stachowiak.
// This needs to be kept sorted, and in sync with FEATURE_DEFINES in WebCore.xcconfig, WebKit.xcconfig and the default settings of build-webkit.
FEATURE_DEFINES = ENABLE_CROSS_DOCUMENT_MESSAGING ENABLE_DATABASE ENABLE_DOM_STORAGE ENABLE_ICONDATABASE ENABLE_OFFLINE_WEB_APPLICATIONS ENABLE_SVG ENABLE_SVG_ANIMATION ENABLE_SVG_AS_IMAGE ENABLE_SVG_FONTS ENABLE_SVG_FOREIGN_OBJECT ENABLE_SVG_USE ENABLE_VIDEO ENABLE_XPATH ENABLE_XSLT;
+
+OTHER_CFLAGS = $(OTHER_CFLAGS_$(CONFIGURATION)_$(CURRENT_VARIANT));
+OTHER_CFLAGS_Release_normal = -fomit-frame-pointer;
+OTHER_CFLAGS_Production_normal = -fomit-frame-pointer;
/>\r
<Tool\r
Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../pcre/;../../kjs/;../../VM/;../../wtf/;../../profiler;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";../../../icu/include;"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders\GNUCompatibility""\r
+ AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../pcre/;../../kjs/;../../VM/;../../wtf/;../../profiler;../../masm/;../../wrec/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";../../../icu/include;"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders\GNUCompatibility""\r
PreprocessorDefinitions="__STD_C"\r
ForcedIncludeFiles=""\r
/>\r
/>\r
<Tool\r
Name="VCPostBuildEventTool"\r
- CommandLine="mkdir 2>NUL "$(WebKitOutputDir)\include\JavaScriptCore"

xcopy /y /d "$(ProjectDir)\..\..\wtf\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\icu\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\VM\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\profiler\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\create_hash_table" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\pcre\pcre.h" "$(WebKitOutputDir)\include\JavaScriptCore"

if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"
"\r
+ CommandLine="mkdir 2>NUL "$(WebKitOutputDir)\include\JavaScriptCore"

xcopy /y /d "$(ProjectDir)\..\..\wtf\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\icu\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\VM\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\masm\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wrec\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\profiler\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\create_hash_table" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\pcre\pcre.h" "$(WebKitOutputDir)\include\JavaScriptCore"

if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"
"\r
/>\r
</Configuration>\r
<Configuration\r
/>\r
<Tool\r
Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../pcre/;../../kjs/;../../VM/;../../wtf/;../../profiler;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";../../../icu/include;"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders\GNUCompatibility""\r
+ AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../pcre/;../../kjs/;../../VM/;../../wtf/;../../profiler;../../masm/;../../wrec/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";../../../icu/include;"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders\GNUCompatibility""\r
PreprocessorDefinitions="__STD_C"\r
ForcedIncludeFiles=""\r
/>\r
/>\r
<Tool\r
Name="VCPostBuildEventTool"\r
- CommandLine="mkdir 2>NUL "$(WebKitOutputDir)\include\JavaScriptCore"

xcopy /y /d "$(ProjectDir)\..\..\wtf\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\icu\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\VM\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\profiler\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\create_hash_table" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\pcre\pcre.h" "$(WebKitOutputDir)\include\JavaScriptCore"

if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"
"\r
+ CommandLine="mkdir 2>NUL "$(WebKitOutputDir)\include\JavaScriptCore"

xcopy /y /d "$(ProjectDir)\..\..\wtf\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\icu\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\VM\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\masm\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wrec\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\profiler\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\create_hash_table" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\pcre\pcre.h" "$(WebKitOutputDir)\include\JavaScriptCore"

if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"
"\r
/>\r
</Configuration>\r
<Configuration\r
/>\r
<Tool\r
Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../pcre/;../../kjs/;../../VM/;../../wtf/;../../profiler;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";../../../icu/include;"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders\GNUCompatibility""\r
+ AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../pcre/;../../kjs/;../../VM/;../../wtf/;../../profiler;../../masm/;../../wrec/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";../../../icu/include;"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders\GNUCompatibility""\r
PreprocessorDefinitions="__STD_C"\r
ForcedIncludeFiles=""\r
/>\r
/>\r
<Tool\r
Name="VCPostBuildEventTool"\r
- CommandLine="mkdir 2>NUL "$(WebKitOutputDir)\include\JavaScriptCore"

xcopy /y /d "$(ProjectDir)\..\..\wtf\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\icu\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\VM\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\profiler\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\create_hash_table" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\pcre\pcre.h" "$(WebKitOutputDir)\include\JavaScriptCore"

if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"
"\r
+ CommandLine="mkdir 2>NUL "$(WebKitOutputDir)\include\JavaScriptCore"

xcopy /y /d "$(ProjectDir)\..\..\wtf\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\icu\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\VM\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\masm\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wrec\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\profiler\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\create_hash_table" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\pcre\pcre.h" "$(WebKitOutputDir)\include\JavaScriptCore"

if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"
"\r
/>\r
</Configuration>\r
<Configuration\r
/>\r
<Tool\r
Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../pcre/;../../kjs/;../../VM/;../../wtf/;../../profiler;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";../../../icu/include;"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders\GNUCompatibility""\r
+ AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../pcre/;../../kjs/;../../VM/;../../wtf/;../../profiler;../../masm/;../../wrec/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";../../../icu/include;"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders\GNUCompatibility""\r
PreprocessorDefinitions="__STD_C"\r
ForcedIncludeFiles=""\r
/>\r
/>\r
<Tool\r
Name="VCPostBuildEventTool"\r
- CommandLine="mkdir 2>NUL "$(WebKitOutputDir)\include\JavaScriptCore"

xcopy /y /d "$(ProjectDir)\..\..\wtf\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\icu\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\VM\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\profiler\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\create_hash_table" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\pcre\pcre.h" "$(WebKitOutputDir)\include\JavaScriptCore"

if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"
"\r
+ CommandLine="mkdir 2>NUL "$(WebKitOutputDir)\include\JavaScriptCore"

xcopy /y /d "$(ProjectDir)\..\..\wtf\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\icu\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\VM\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\masm\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wrec\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\profiler\*.h" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\kjs\create_hash_table" "$(WebKitOutputDir)\include\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\pcre\pcre.h" "$(WebKitOutputDir)\include\JavaScriptCore"

if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"
"\r
/>\r
</Configuration>\r
</Configurations>\r
>\r
</File>\r
<File\r
+ RelativePath="..\..\VM\CTI.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\..\VM\CTI.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath="..\..\VM\ExceptionHelpers.cpp"\r
>\r
</File>\r
>\r
</File>\r
</Filter>\r
+ <Filter\r
+ Name="masm"\r
+ >\r
+ <File\r
+ RelativePath="..\..\masm\IA32MacroAsm.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\..\masm\MacroAssembler.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\..\masm\MacroAssemblerWin.cpp"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="wrec"\r
+ >\r
+ <File\r
+ RelativePath="..\..\wrec\WREC.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\..\wrec\WREC.h"\r
+ >\r
+ </File>\r
+ </Filter>\r
</Files>\r
<Globals>\r
</Globals>\r
65FDE49C0BDD1D4A00E80111 /* Assertions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65E217B808E7EECC0023E5F6 /* Assertions.cpp */; };
8613F45A0E3A433E00C948FD /* SamplingTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8613F4580E3A433E00C948FD /* SamplingTool.cpp */; };
8613F45B0E3A433E00C948FD /* SamplingTool.h in Headers */ = {isa = PBXBuildFile; fileRef = 8613F4590E3A433E00C948FD /* SamplingTool.h */; };
+ 8683B02E0E636482004C19EE /* CTI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8683B02B0E636482004C19EE /* CTI.cpp */; };
+ 8683B02F0E636482004C19EE /* CTI.h in Headers */ = {isa = PBXBuildFile; fileRef = 8683B02C0E636482004C19EE /* CTI.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 869081410E640C89000D36ED /* IA32MacroAsm.h in Headers */ = {isa = PBXBuildFile; fileRef = 869081400E640C89000D36ED /* IA32MacroAsm.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 869083150E6518D7000D36ED /* WREC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 869083130E6518D7000D36ED /* WREC.cpp */; };
+ 869083160E6518D7000D36ED /* WREC.h in Headers */ = {isa = PBXBuildFile; fileRef = 869083140E6518D7000D36ED /* WREC.h */; settings = {ATTRIBUTES = (Private, ); }; };
905B02AE0E28640F006DF882 /* RefCountedLeakCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 905B02AD0E28640F006DF882 /* RefCountedLeakCounter.cpp */; };
90D3469C0E285280009492EE /* RefCountedLeakCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D3469B0E285280009492EE /* RefCountedLeakCounter.h */; settings = {ATTRIBUTES = (Private, ); }; };
930754C108B0F68000AB3056 /* pcre_compile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 930754BF08B0F68000AB3056 /* pcre_compile.cpp */; };
A72701B60DADE94900E548D7 /* ExceptionHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A72701B40DADE94900E548D7 /* ExceptionHelpers.cpp */; };
A72701B90DADE94900E548D7 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; };
A727FF6B0DA3092200E548D7 /* JSPropertyNameIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */; };
+ A763F79D0E70E0FE00BC151E /* MacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = A763F79C0E70E0FE00BC151E /* MacroAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
A7C31DAA0DBEBA4300FDF8EB /* SegmentedVector.h in Headers */ = {isa = PBXBuildFile; fileRef = A7C31DA80DBEBA4300FDF8EB /* SegmentedVector.h */; };
BC02E90D0E1839DB000F9297 /* ErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9050E1839DB000F9297 /* ErrorConstructor.h */; };
BC02E90F0E1839DB000F9297 /* ErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9070E1839DB000F9297 /* ErrorPrototype.h */; };
7E6D517E0E729AF400778C37 /* JavaScriptCore.Debug.exp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.exports; path = JavaScriptCore.Debug.exp; sourceTree = "<group>"; };
8613F4580E3A433E00C948FD /* SamplingTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SamplingTool.cpp; path = VM/SamplingTool.cpp; sourceTree = "<group>"; };
8613F4590E3A433E00C948FD /* SamplingTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SamplingTool.h; path = VM/SamplingTool.h; sourceTree = "<group>"; };
+ 8683B02B0E636482004C19EE /* CTI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CTI.cpp; path = VM/CTI.cpp; sourceTree = "<group>"; };
+ 8683B02C0E636482004C19EE /* CTI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CTI.h; path = VM/CTI.h; sourceTree = "<group>"; };
+ 869081400E640C89000D36ED /* IA32MacroAsm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IA32MacroAsm.h; sourceTree = "<group>"; };
+ 869083130E6518D7000D36ED /* WREC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WREC.cpp; sourceTree = "<group>"; };
+ 869083140E6518D7000D36ED /* WREC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WREC.h; sourceTree = "<group>"; };
905B02AD0E28640F006DF882 /* RefCountedLeakCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RefCountedLeakCounter.cpp; sourceTree = "<group>"; };
90D3469B0E285280009492EE /* RefCountedLeakCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefCountedLeakCounter.h; sourceTree = "<group>"; };
9303F567099118FA00AD71B8 /* OwnPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OwnPtr.h; sourceTree = "<group>"; };
A72701B40DADE94900E548D7 /* ExceptionHelpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExceptionHelpers.cpp; path = VM/ExceptionHelpers.cpp; sourceTree = "<group>"; };
A727FF650DA3053B00E548D7 /* JSPropertyNameIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSPropertyNameIterator.h; path = VM/JSPropertyNameIterator.h; sourceTree = "<group>"; };
A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSPropertyNameIterator.cpp; path = VM/JSPropertyNameIterator.cpp; sourceTree = "<group>"; };
+ A763F79C0E70E0FE00BC151E /* MacroAssembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssembler.h; sourceTree = "<group>"; };
A7C31DA80DBEBA4300FDF8EB /* SegmentedVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SegmentedVector.h; path = VM/SegmentedVector.h; sourceTree = "<group>"; };
A7E42C180E3938830065A544 /* JSStaticScopeObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStaticScopeObject.h; sourceTree = "<group>"; };
A7E42C190E3938830065A544 /* JSStaticScopeObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStaticScopeObject.cpp; sourceTree = "<group>"; };
7E6D517E0E729AF400778C37 /* JavaScriptCore.Debug.exp */,
F5C290E60284F98E018635CA /* JavaScriptCorePrefix.h */,
1432EBD70A34CAD400717B9F /* API */,
- 65162EF108E6A21C007556CD /* wtf */,
- 65417203039E01F90058BFEB /* pcre */,
- 65417200039E01BA0058BFEB /* kjs */,
149B15DF0D81F887009CB8C7 /* compiler */,
- 149B15E00D81F88D009CB8C7 /* vm */,
1480DB9A0DDC2231003CFDF2 /* debugger */,
+ 65417200039E01BA0058BFEB /* kjs */,
+ 8690813F0E640C89000D36ED /* masm */,
+ 65417203039E01F90058BFEB /* pcre */,
95AB831A0DA42C6900BC83F3 /* profiler */,
+ 141211000A48772600480255 /* tests */,
+ 149B15E00D81F88D009CB8C7 /* vm */,
+ 869083120E6518D7000D36ED /* wrec */,
+ 65162EF108E6A21C007556CD /* wtf */,
+ 1C90513E0BA9E8830081E9D0 /* Configurations */,
650FDF8D09D0FCA700769E54 /* Derived Sources */,
+ 0867D69AFE84028FC02AAC07 /* Frameworks */,
034768DFFF38A50411DB9C8B /* Products */,
932FC3C20824BB70005B3C75 /* Resources */,
- 0867D69AFE84028FC02AAC07 /* Frameworks */,
- 1C90513E0BA9E8830081E9D0 /* Configurations */,
- 141211000A48772600480255 /* tests */,
);
name = JavaScriptCore;
sourceTree = "<group>";
149B15E00D81F88D009CB8C7 /* vm */ = {
isa = PBXGroup;
children = (
+ 8683B02B0E636482004C19EE /* CTI.cpp */,
+ 8683B02C0E636482004C19EE /* CTI.h */,
8613F4580E3A433E00C948FD /* SamplingTool.cpp */,
8613F4590E3A433E00C948FD /* SamplingTool.h */,
149B1A9E0D86ED73009CB8C7 /* CodeBlock.cpp */,
tabWidth = 4;
usesTabs = 0;
};
+ 8690813F0E640C89000D36ED /* masm */ = {
+ isa = PBXGroup;
+ children = (
+ A763F79C0E70E0FE00BC151E /* MacroAssembler.h */,
+ 869081400E640C89000D36ED /* IA32MacroAsm.h */,
+ );
+ path = masm;
+ sourceTree = "<group>";
+ };
+ 869083120E6518D7000D36ED /* wrec */ = {
+ isa = PBXGroup;
+ children = (
+ 869083130E6518D7000D36ED /* WREC.cpp */,
+ 869083140E6518D7000D36ED /* WREC.h */,
+ );
+ path = wrec;
+ sourceTree = "<group>";
+ };
932FC3C20824BB70005B3C75 /* Resources */ = {
isa = PBXGroup;
children = (
C0A272630E50A06300E96E15 /* NotFound.h in Headers */,
E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */,
9534AAFB0E5B7A9600B8A45B /* JSProfilerPrivate.h in Headers */,
+ 8683B02F0E636482004C19EE /* CTI.h in Headers */,
+ 869081410E640C89000D36ED /* IA32MacroAsm.h in Headers */,
+ 869083160E6518D7000D36ED /* WREC.h in Headers */,
933040040E6A749400786E6A /* SmallStrings.h in Headers */,
BCDE3AB80E6C82F5001453A7 /* StructureID.h in Headers */,
+ A763F79D0E70E0FE00BC151E /* MacroAssembler.h in Headers */,
147B83AC0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h in Headers */,
147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */,
);
8613F45A0E3A433E00C948FD /* SamplingTool.cpp in Sources */,
E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */,
95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */,
+ 8683B02E0E636482004C19EE /* CTI.cpp in Sources */,
+ 869083150E6518D7000D36ED /* WREC.cpp in Sources */,
9330402C0E6A764000786E6A /* SmallStrings.cpp in Sources */,
BCDE3B430E6C832D001453A7 /* StructureID.cpp in Sources */,
);
};
name = Production;
};
+ A761483D0E6402F700E357FA /* Profiling */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 1C9051440BA9E8A70081E9D0 /* DebugRelease.xcconfig */;
+ buildSettings = {
+ STRIP_INSTALLED_PRODUCT = NO;
+ };
+ name = Profiling;
+ };
+ A761483E0E6402F700E357FA /* Profiling */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = All;
+ };
+ name = Profiling;
+ };
+ A761483F0E6402F700E357FA /* Profiling */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */;
+ buildSettings = {
+ INSTALL_PATH = "$(BUILT_PRODUCTS_DIR)";
+ };
+ name = Profiling;
+ };
+ A76148400E6402F700E357FA /* Profiling */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "Generate Derived Sources";
+ };
+ name = Profiling;
+ };
+ A76148410E6402F700E357FA /* Profiling */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = minidom;
+ };
+ name = Profiling;
+ };
+ A76148420E6402F700E357FA /* Profiling */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = testapi;
+ };
+ name = Profiling;
+ };
+ A76148430E6402F700E357FA /* Profiling */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = jsc;
+ };
+ name = Profiling;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
buildConfigurations = (
1412113A0A48798400480255 /* Debug */,
1412113B0A48798400480255 /* Release */,
+ A76148410E6402F700E357FA /* Profiling */,
1412113C0A48798400480255 /* Production */,
);
defaultConfigurationIsVisible = 0;
buildConfigurations = (
149C275E08902AFE008A9EFC /* Debug */,
149C275F08902AFE008A9EFC /* Release */,
+ A761483F0E6402F700E357FA /* Profiling */,
149C276108902AFE008A9EFC /* Production */,
);
defaultConfigurationIsVisible = 0;
buildConfigurations = (
149C276808902AFE008A9EFC /* Debug */,
149C276908902AFE008A9EFC /* Release */,
+ A76148430E6402F700E357FA /* Profiling */,
149C276B08902AFE008A9EFC /* Production */,
);
defaultConfigurationIsVisible = 0;
buildConfigurations = (
149C276D08902AFE008A9EFC /* Debug */,
149C276E08902AFE008A9EFC /* Release */,
+ A761483E0E6402F700E357FA /* Profiling */,
149C277008902AFE008A9EFC /* Production */,
);
defaultConfigurationIsVisible = 0;
buildConfigurations = (
149C277208902AFE008A9EFC /* Debug */,
149C277308902AFE008A9EFC /* Release */,
+ A761483D0E6402F700E357FA /* Profiling */,
149C277508902AFE008A9EFC /* Production */,
);
defaultConfigurationIsVisible = 0;
buildConfigurations = (
14BD59D70A3E8FC900BAF59C /* Debug */,
14BD59D80A3E8FC900BAF59C /* Release */,
+ A76148420E6402F700E357FA /* Profiling */,
14BD59D90A3E8FC900BAF59C /* Production */,
);
defaultConfigurationIsVisible = 0;
buildConfigurations = (
65FB3F7809D11EBD00F49DEB /* Debug */,
65FB3F7909D11EBD00F49DEB /* Release */,
+ A76148400E6402F700E357FA /* Profiling */,
65FB3F7A09D11EBD00F49DEB /* Production */,
);
defaultConfigurationIsVisible = 0;
--- /dev/null
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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.
+ */
+
+#include "config.h"
+#include "CTI.h"
+
+#if ENABLE(CTI)
+
+#include "CodeBlock.h"
+#include "JSArray.h"
+#include "Machine.h"
+#include "wrec/WREC.h"
+
+using namespace std;
+
+namespace KJS {
+
+#if COMPILER(GCC) && PLATFORM(X86)
+asm(
+".globl _ctiTrampoline" "\n"
+"_ctiTrampoline:" "\n"
+ "pushl %esi" "\n"
+ "pushl %edi" "\n"
+ "subl $0x24, %esp" "\n"
+ "movl $512, %esi" "\n"
+ "call *0x30(%esp)" "\n" //Ox30 = 0x0C * 4, 0x0C = CTI_ARGS_code
+ "addl $0x24, %esp" "\n"
+ "popl %edi" "\n"
+ "popl %esi" "\n"
+ "ret" "\n"
+);
+
+asm(
+".globl _ctiVMThrowTrampoline" "\n"
+"_ctiVMThrowTrampoline:" "\n"
+#ifndef NDEBUG
+ "movl 0x34(%esp), %ecx" "\n" //Ox34 = 0x0D * 4, 0x0D = CTI_ARGS_exec
+ "cmpl $0, 8(%ecx)" "\n"
+ "jne 1f" "\n"
+ "int3" "\n"
+ "1:" "\n"
+#endif
+ "call __ZN3KJS7Machine12cti_vm_throwEPv" "\n"
+ "addl $0x24, %esp" "\n"
+ "popl %edi" "\n"
+ "popl %esi" "\n"
+ "ret" "\n"
+);
+
+#elif COMPILER(MSVC)
+extern "C"
+{
+
+ __declspec(naked) JSValue* ctiTrampoline(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception, Profiler**)
+ {
+ __asm {
+ push esi;
+ push edi;
+ sub esp, 0x24;
+ mov esi, 512;
+ mov [esp], esp;
+ call [esp + 0x30];
+ add esp, 0x24;
+ pop edi;
+ pop esi;
+ ret;
+ }
+ }
+
+ __declspec(naked) void ctiVMThrowTrampoline()
+ {
+ __asm {
+ mov [esp], esp;
+ call KJS::Machine::cti_vm_throw;
+ add esp, 0x24;
+ pop edi;
+ pop esi;
+ ret;
+ }
+ }
+
+}
+
+#endif
+
+
+// get arg puts an arg from the SF register array into a h/w register
+ALWAYS_INLINE void CTI::emitGetArg(unsigned src, MacroAssembler::RegisterID dst)
+{
+ // TODO: we want to reuse values that are already in registers if we can - add a register allocator!
+ if (src < m_codeBlock->constantRegisters.size()) {
+ JSValue* js = m_codeBlock->constantRegisters[src].jsValue(m_exec);
+ m_jit.emitMovl_i32r((unsigned)js, dst);
+ } else
+ m_jit.emitMovl_mr(src * sizeof(Register), MacroAssembler::edi, dst);
+}
+
+// get arg puts an arg from the SF register array onto the stack, as an arg to a context threaded function.
+ALWAYS_INLINE void CTI::emitGetPutArg(unsigned src, unsigned offset, MacroAssembler::RegisterID scratch)
+{
+ if (src < m_codeBlock->constantRegisters.size()) {
+ JSValue* js = m_codeBlock->constantRegisters[src].jsValue(m_exec);
+ m_jit.emitMovl_i32m((unsigned)js, offset + sizeof(void*), MacroAssembler::esp);
+ } else {
+ m_jit.emitMovl_mr(src * sizeof(Register), MacroAssembler::edi, scratch);
+ m_jit.emitMovl_rm(scratch, offset + sizeof(void*), MacroAssembler::esp);
+ }
+}
+
+// puts an arg onto the stack, as an arg to a context threaded function.
+ALWAYS_INLINE void CTI::emitPutArg(MacroAssembler::RegisterID src, unsigned offset)
+{
+ m_jit.emitMovl_rm(src, offset + sizeof(void*), MacroAssembler::esp);
+}
+
+ALWAYS_INLINE void CTI::emitPutArgConstant(unsigned value, unsigned offset)
+{
+ m_jit.emitMovl_i32m(value, offset + sizeof(void*), MacroAssembler::esp);
+}
+
+ALWAYS_INLINE JSValue* CTI::getConstantImmediateNumericArg(unsigned src)
+{
+ if (src < m_codeBlock->constantRegisters.size()) {
+ JSValue* js = m_codeBlock->constantRegisters[src].jsValue(m_exec);
+ return JSImmediate::isNumber(js) ? js : 0;
+ }
+ return 0;
+}
+
+ALWAYS_INLINE void CTI::emitPutCTIParam(MacroAssembler::RegisterID from, unsigned name)
+{
+ m_jit.emitMovl_rm(from, name * sizeof(void*), MacroAssembler::esp);
+}
+
+ALWAYS_INLINE void CTI::emitGetCTIParam(unsigned name, MacroAssembler::RegisterID to)
+{
+ m_jit.emitMovl_mr(name * sizeof(void*), MacroAssembler::esp, to);
+}
+
+ALWAYS_INLINE void CTI::emitPutToCallFrameHeader(MacroAssembler::RegisterID from, RegisterFile::CallFrameHeaderEntry entry)
+{
+ m_jit.emitMovl_rm(from, -((m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) - entry) * sizeof(Register), MacroAssembler::edi);
+}
+
+ALWAYS_INLINE void CTI::emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, MacroAssembler::RegisterID to)
+{
+ m_jit.emitMovl_mr(-((m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) - entry) * sizeof(Register), MacroAssembler::edi, to);
+}
+
+ALWAYS_INLINE void CTI::emitPutResult(unsigned dst, MacroAssembler::RegisterID from)
+{
+ m_jit.emitMovl_rm(from, dst * sizeof(Register), MacroAssembler::edi);
+ // FIXME: #ifndef NDEBUG, Write the correct m_type to the register.
+}
+
+#if ENABLE(SAMPLING_TOOL)
+unsigned incall = 0;
+#endif
+
+void ctiSetReturnAddress(void** where, void* what)
+{
+ *where = what;
+}
+
+void ctiRepatchCallByReturnAddress(void* where, void* what)
+{
+ ((void**)where)[-1] = (void*)((uintptr_t)what - (uintptr_t)where);
+}
+
+#ifdef NDEBUG
+
+ALWAYS_INLINE void CTI::emitDebugExceptionCheck()
+{
+}
+
+#else
+
+ALWAYS_INLINE void CTI::emitDebugExceptionCheck()
+{
+ emitGetCTIParam(CTI_ARGS_exec, MacroAssembler::ecx);
+ m_jit.emitCmpl_i32m(0, OBJECT_OFFSET(ExecState, m_exception), MacroAssembler::ecx);
+ MacroAssembler::JmpSrc noException = m_jit.emitUnlinkedJe();
+ m_jit.emitInt3();
+ m_jit.link(noException, m_jit.label());
+}
+
+void CTI::printOpcodeOperandTypes(unsigned src1, unsigned src2)
+{
+ char which1 = '*';
+ if (src1 < m_codeBlock->constantRegisters.size()) {
+ JSValue* js = m_codeBlock->constantRegisters[src1].jsValue(m_exec);
+ which1 =
+ JSImmediate::isImmediate(js) ?
+ (JSImmediate::isNumber(js) ? 'i' :
+ JSImmediate::isBoolean(js) ? 'b' :
+ js->isUndefined() ? 'u' :
+ js->isNull() ? 'n' : '?')
+ :
+ (js->isString() ? 's' :
+ js->isObject() ? 'o' :
+ 'k');
+ }
+ char which2 = '*';
+ if (src2 < m_codeBlock->constantRegisters.size()) {
+ JSValue* js = m_codeBlock->constantRegisters[src2].jsValue(m_exec);
+ which2 =
+ JSImmediate::isImmediate(js) ?
+ (JSImmediate::isNumber(js) ? 'i' :
+ JSImmediate::isBoolean(js) ? 'b' :
+ js->isUndefined() ? 'u' :
+ js->isNull() ? 'n' : '?')
+ :
+ (js->isString() ? 's' :
+ js->isObject() ? 'o' :
+ 'k');
+ }
+ if ((which1 != '*') | (which2 != '*'))
+ fprintf(stderr, "Types %c %c\n", which1, which2);
+}
+
+#endif
+
+ALWAYS_INLINE void CTI::emitCall(unsigned opcodeIndex, CTIHelper_j helper)
+{
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(1, &incall);
+#endif
+ m_calls.append(CallRecord(m_jit.emitCall(), helper, opcodeIndex));
+ emitDebugExceptionCheck();
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(0, &incall);
+#endif
+}
+
+ALWAYS_INLINE void CTI::emitCall(unsigned opcodeIndex, CTIHelper_p helper)
+{
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(1, &incall);
+#endif
+ m_calls.append(CallRecord(m_jit.emitCall(), helper, opcodeIndex));
+ emitDebugExceptionCheck();
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(0, &incall);
+#endif
+}
+
+ALWAYS_INLINE void CTI::emitCall(unsigned opcodeIndex, CTIHelper_b helper)
+{
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(1, &incall);
+#endif
+ m_calls.append(CallRecord(m_jit.emitCall(), helper, opcodeIndex));
+ emitDebugExceptionCheck();
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(0, &incall);
+#endif
+}
+
+ALWAYS_INLINE void CTI::emitCall(unsigned opcodeIndex, CTIHelper_v helper)
+{
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(1, &incall);
+#endif
+ m_calls.append(CallRecord(m_jit.emitCall(), helper, opcodeIndex));
+ emitDebugExceptionCheck();
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(0, &incall);
+#endif
+}
+
+ALWAYS_INLINE void CTI::emitCall(unsigned opcodeIndex, CTIHelper_s helper)
+{
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(1, &incall);
+#endif
+ m_calls.append(CallRecord(m_jit.emitCall(), helper, opcodeIndex));
+ emitDebugExceptionCheck();
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(0, &incall);
+#endif
+}
+
+ALWAYS_INLINE void CTI::emitJumpSlowCaseIfNotImm(MacroAssembler::RegisterID reg, unsigned opcodeIndex)
+{
+ m_jit.emitTestl_i32r(JSImmediate::TagBitTypeInteger, reg);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), opcodeIndex));
+}
+
+ALWAYS_INLINE void CTI::emitJumpSlowCaseIfNotImms(MacroAssembler::RegisterID reg1, MacroAssembler::RegisterID reg2, unsigned opcodeIndex)
+{
+ m_jit.emitMovl_rr(reg1, MacroAssembler::ecx);
+ m_jit.emitAndl_rr(reg2, MacroAssembler::ecx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::ecx, opcodeIndex);
+}
+
+ALWAYS_INLINE unsigned CTI::getDeTaggedConstantImmediate(JSValue* imm)
+{
+ ASSERT(JSImmediate::isNumber(imm));
+ return reinterpret_cast<unsigned>(imm) & ~JSImmediate::TagBitTypeInteger;
+}
+
+ALWAYS_INLINE void CTI::emitFastArithDeTagImmediate(MacroAssembler::RegisterID reg)
+{
+ // op_mod relies on this being a sub - setting zf if result is 0.
+ m_jit.emitSubl_i8r(JSImmediate::TagBitTypeInteger, reg);
+}
+
+ALWAYS_INLINE void CTI::emitFastArithReTagImmediate(MacroAssembler::RegisterID reg)
+{
+ m_jit.emitAddl_i8r(JSImmediate::TagBitTypeInteger, reg);
+}
+
+ALWAYS_INLINE void CTI::emitFastArithPotentiallyReTagImmediate(MacroAssembler::RegisterID reg)
+{
+ m_jit.emitOrl_i8r(JSImmediate::TagBitTypeInteger, reg);
+}
+
+ALWAYS_INLINE void CTI::emitFastArithImmToInt(MacroAssembler::RegisterID reg)
+{
+ m_jit.emitSarl_i8r(1, reg);
+}
+
+ALWAYS_INLINE void CTI::emitFastArithIntToImmOrSlowCase(MacroAssembler::RegisterID reg, unsigned opcodeIndex)
+{
+ m_jit.emitAddl_rr(reg, reg);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), opcodeIndex));
+ emitFastArithReTagImmediate(reg);
+}
+
+ALWAYS_INLINE void CTI::emitFastArithIntToImmNoCheck(MacroAssembler::RegisterID reg)
+{
+ m_jit.emitAddl_rr(reg, reg);
+ emitFastArithReTagImmediate(reg);
+}
+
+CTI::CTI(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
+ : m_jit(machine->jitCodeBuffer())
+ , m_machine(machine)
+ , m_exec(exec)
+ , m_codeBlock(codeBlock)
+ , m_labels(codeBlock ? codeBlock->instructions.size() : 0)
+{
+}
+
+#define CTI_COMPILE_BINARY_OP(name) \
+ case name: { \
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx); \
+ emitGetPutArg(instruction[i + 3].u.operand, 4, MacroAssembler::ecx); \
+ emitCall(i, Machine::cti_##name); \
+ emitPutResult(instruction[i + 1].u.operand); \
+ i += 4; \
+ break; \
+ }
+
+#if ENABLE(SAMPLING_TOOL)
+OpcodeID what = (OpcodeID)-1;
+#endif
+
+void CTI::compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType type)
+{
+ if (type == OpConstruct) {
+ emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 12);
+ emitPutArgConstant(instruction[i + 4].u.operand, 8);
+ emitPutArgConstant(instruction[i + 3].u.operand, 4);
+ } else {
+ emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 16);
+ emitPutArgConstant(instruction[i + 5].u.operand, 12);
+ emitPutArgConstant(instruction[i + 4].u.operand, 8);
+ // FIXME: should this be loaded dynamically off m_exec?
+ int thisVal = instruction[i + 3].u.operand;
+ if (thisVal == missingThisObjectMarker()) {
+ emitPutArgConstant((unsigned)(m_exec->globalThisValue()), 4);
+ } else
+ emitGetPutArg(thisVal, 4, MacroAssembler::ecx);
+ }
+
+ MacroAssembler::JmpSrc wasEval;
+ if (type == OpCallEval) {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_call_eval);
+ m_jit.emitRestoreArgumentReference();
+
+ emitGetCTIParam(CTI_ARGS_r, MacroAssembler::edi); // edi := r
+
+ m_jit.emitCmpl_i32r(reinterpret_cast<unsigned>(JSImmediate::impossibleValue()), MacroAssembler::eax);
+ wasEval = m_jit.emitUnlinkedJne();
+
+ // this reloads the first arg into ecx (checked just below).
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::ecx);
+ } else {
+ // this sets up the first arg, and explicitly leaves the value in ecx (checked just below).
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::ecx);
+ emitPutArg(MacroAssembler::ecx, 0);
+ }
+
+ // Fast check for JS function.
+ m_jit.emitTestl_i32r(JSImmediate::TagMask, MacroAssembler::ecx);
+ MacroAssembler::JmpSrc isNotObject = m_jit.emitUnlinkedJne();
+ m_jit.emitCmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsFunctionVptr), MacroAssembler::ecx);
+ MacroAssembler::JmpSrc isJSFunction = m_jit.emitUnlinkedJe();
+ m_jit.link(isNotObject, m_jit.label());
+
+ // This handles host functions
+ emitCall(i, ((type == OpConstruct) ? Machine::cti_op_construct_NotJSConstruct : Machine::cti_op_call_NotJSFunction));
+ emitGetCTIParam(CTI_ARGS_r, MacroAssembler::edi); // edi := r
+
+ MacroAssembler::JmpSrc wasNotJSFunction = m_jit.emitUnlinkedJmp();
+ m_jit.link(isJSFunction, m_jit.label());
+
+ // This handles JSFunctions
+ emitCall(i, ((type == OpConstruct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction));
+ m_jit.emitCallN_r(MacroAssembler::eax);
+ emitGetCTIParam(CTI_ARGS_r, MacroAssembler::edi); // edi := r
+
+ MacroAssembler::JmpDst end = m_jit.label();
+ m_jit.link(wasNotJSFunction, end);
+ if (type == OpCallEval)
+ m_jit.link(wasEval, end);
+
+ emitPutResult(instruction[i + 1].u.operand);
+}
+
+void CTI::privateCompileMainPass()
+{
+ Instruction* instruction = m_codeBlock->instructions.begin();
+ unsigned instructionCount = m_codeBlock->instructions.size();
+
+ for (unsigned i = 0; i < instructionCount; ) {
+ m_labels[i] = m_jit.label();
+
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(m_machine->getOpcodeID(instruction[i].u.opcode), &what);
+#endif
+
+ ASSERT_WITH_MESSAGE(m_machine->isOpcode(instruction[i].u.opcode), "privateCompileMainPass gone bad @ %d", i);
+ m_jit.emitRestoreArgumentReference();
+ switch (m_machine->getOpcodeID(instruction[i].u.opcode)) {
+ case op_mov: {
+ unsigned src = instruction[i + 2].u.operand;
+ if (src < m_codeBlock->constantRegisters.size())
+ m_jit.emitMovl_i32r((unsigned)(m_codeBlock->constantRegisters[src].jsValue(m_exec)), MacroAssembler::edx);
+ else
+ emitGetArg(src, MacroAssembler::edx);
+ emitPutResult(instruction[i + 1].u.operand, MacroAssembler::edx);
+ i += 3;
+ break;
+ }
+ case op_add: {
+ unsigned dst = instruction[i + 1].u.operand;
+ unsigned src1 = instruction[i + 2].u.operand;
+ unsigned src2 = instruction[i + 3].u.operand;
+ if (src2 < m_codeBlock->constantRegisters.size()) {
+ JSValue* value = m_codeBlock->constantRegisters[src2].jsValue(m_exec);
+ if (JSImmediate::isNumber(value)) {
+ emitGetArg(src1, MacroAssembler::eax);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ m_jit.emitAddl_i32r(getDeTaggedConstantImmediate(value), MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
+ emitPutResult(dst);
+ i += 4;
+ break;
+ }
+ } else if (!(src1 < m_codeBlock->constantRegisters.size())) {
+ emitGetArg(src1, MacroAssembler::eax);
+ emitGetArg(src2, MacroAssembler::edx);
+ emitJumpSlowCaseIfNotImms(MacroAssembler::eax, MacroAssembler::edx, i);
+ emitFastArithDeTagImmediate(MacroAssembler::eax);
+ m_jit.emitAddl_rr(MacroAssembler::edx, MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
+ emitPutResult(dst);
+ i += 4;
+ break;
+ }
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ emitGetPutArg(instruction[i + 3].u.operand, 4, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_add);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_end: {
+ if (m_codeBlock->needsFullScopeChain)
+ emitCall(i, Machine::cti_op_end);
+ emitGetArg(instruction[i + 1].u.operand, MacroAssembler::eax);
+#if ENABLE(SAMPLING_TOOL)
+ m_jit.emitMovl_i32m(-1, &what);
+#endif
+ m_jit.emitPushl_m(-((m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) - RegisterFile::CTIReturnEIP) * sizeof(Register), MacroAssembler::edi);
+ m_jit.emitRet();
+ i += 2;
+ break;
+ }
+ case op_jmp: {
+ unsigned target = instruction[i + 1].u.operand;
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 1 + target));
+ i += 2;
+ break;
+ }
+ case op_pre_inc: {
+ int srcDst = instruction[i + 1].u.operand;
+ emitGetArg(srcDst, MacroAssembler::eax);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ m_jit.emitAddl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
+ emitPutResult(srcDst, MacroAssembler::eax);
+ i += 2;
+ break;
+ }
+ case op_loop: {
+ m_jit.emitSubl_i8r(1, MacroAssembler::esi);
+ MacroAssembler::JmpSrc skipTimeout = m_jit.emitUnlinkedJne();
+ emitCall(i, Machine::cti_timeout_check);
+
+ emitGetCTIParam(CTI_ARGS_exec, MacroAssembler::ecx);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(ExecState, m_globalData) + OBJECT_OFFSET(JSGlobalData, machine), MacroAssembler::ecx, MacroAssembler::ecx);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(Machine, m_ticksUntilNextTimeoutCheck), MacroAssembler::ecx, MacroAssembler::esi);
+ m_jit.link(skipTimeout, m_jit.label());
+
+ unsigned target = instruction[i + 1].u.operand;
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 1 + target));
+ i += 2;
+ break;
+ }
+ case op_loop_if_less: {
+ m_jit.emitSubl_i8r(1, MacroAssembler::esi);
+ MacroAssembler::JmpSrc skipTimeout = m_jit.emitUnlinkedJne();
+ emitCall(i, Machine::cti_timeout_check);
+
+ emitGetCTIParam(CTI_ARGS_exec, MacroAssembler::ecx);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(ExecState, m_globalData) + OBJECT_OFFSET(JSGlobalData, machine), MacroAssembler::ecx, MacroAssembler::ecx);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(Machine, m_ticksUntilNextTimeoutCheck), MacroAssembler::ecx, MacroAssembler::esi);
+ m_jit.link(skipTimeout, m_jit.label());
+
+ unsigned target = instruction[i + 3].u.operand;
+ JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
+ if (src2imm) {
+ emitGetArg(instruction[i + 1].u.operand, MacroAssembler::edx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::edx, i);
+ m_jit.emitCmpl_i32r((unsigned)src2imm, MacroAssembler::edx);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJl(), i + 3 + target));
+ } else {
+ emitGetArg(instruction[i + 1].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::edx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::edx, i);
+ m_jit.emitCmpl_rr(MacroAssembler::edx, MacroAssembler::eax);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJl(), i + 3 + target));
+ }
+ i += 4;
+ break;
+ }
+ case op_new_object: {
+ emitCall(i, Machine::cti_op_new_object);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 2;
+ break;
+ }
+ case op_put_by_id: {
+ Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
+ emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
+ emitGetArg(instruction[i + 1].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 3].u.operand, MacroAssembler::edx);
+ emitPutArg(MacroAssembler::eax, 0); // leave the base in eax
+ emitPutArg(MacroAssembler::edx, 8); // leave the base in edx
+ emitCall(i, Machine::cti_op_put_by_id);
+ i += 6;
+ break;
+ }
+ case op_get_by_id: {
+ Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
+ emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::eax);
+ emitPutArg(MacroAssembler::eax, 0); // leave the base in eax
+ emitCall(i, Machine::cti_op_get_by_id);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 8;
+ break;
+ }
+ case op_instanceof: {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ emitGetPutArg(instruction[i + 3].u.operand, 4, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_instanceof);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_del_by_id: {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
+ emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
+ emitCall(i, Machine::cti_op_del_by_id);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ CTI_COMPILE_BINARY_OP(op_mul);
+ case op_new_func: {
+ FuncDeclNode* func = (m_codeBlock->functions[instruction[i + 2].u.operand]).get();
+ emitPutArgConstant(reinterpret_cast<unsigned>(func), 0);
+ emitCall(i, Machine::cti_op_new_func);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_call: {
+ compileOpCall(instruction, i);
+ i += 6;
+ break;
+ }
+ case op_get_scoped_var: {
+ int skip = instruction[i + 3].u.operand + m_codeBlock->needsFullScopeChain;
+
+ emitGetCTIParam(CTI_ARGS_scopeChain, MacroAssembler::eax);
+ while (skip--)
+ m_jit.emitMovl_mr(OBJECT_OFFSET(ScopeChainNode, next), MacroAssembler::eax, MacroAssembler::eax);
+
+ m_jit.emitMovl_mr(OBJECT_OFFSET(ScopeChainNode, object), MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.emitMovl_mr(JSVariableObject::offsetOf_d(), MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.emitMovl_mr(JSVariableObject::offsetOf_Data_registers(), MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.emitMovl_mr((instruction[i + 2].u.operand) * sizeof(Register), MacroAssembler::eax, MacroAssembler::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_put_scoped_var: {
+ int skip = instruction[i + 2].u.operand + m_codeBlock->needsFullScopeChain;
+
+ emitGetCTIParam(CTI_ARGS_scopeChain, MacroAssembler::edx);
+ emitGetArg(instruction[i + 3].u.operand, MacroAssembler::eax);
+ while (skip--)
+ m_jit.emitMovl_mr(OBJECT_OFFSET(ScopeChainNode, next), MacroAssembler::edx, MacroAssembler::edx);
+
+ m_jit.emitMovl_mr(OBJECT_OFFSET(ScopeChainNode, object), MacroAssembler::edx, MacroAssembler::edx);
+ m_jit.emitMovl_mr(JSVariableObject::offsetOf_d(), MacroAssembler::edx, MacroAssembler::edx);
+ m_jit.emitMovl_mr(JSVariableObject::offsetOf_Data_registers(), MacroAssembler::edx, MacroAssembler::edx);
+ m_jit.emitMovl_rm(MacroAssembler::eax, (instruction[i + 1].u.operand) * sizeof(Register), MacroAssembler::edx);
+ i += 4;
+ break;
+ }
+ case op_ret: {
+ emitGetPutArg(instruction[i + 1].u.operand, 0, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_ret);
+
+ m_jit.emitPushl_m(-((m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) - RegisterFile::CTIReturnEIP) * sizeof(Register), MacroAssembler::edi);
+ m_jit.emitRet();
+ i += 2;
+ break;
+ }
+ case op_new_array: {
+ m_jit.emitLeal_mr(sizeof(Register) * instruction[i + 2].u.operand, MacroAssembler::edi, MacroAssembler::edx);
+ emitPutArg(MacroAssembler::edx, 0);
+ emitPutArgConstant(instruction[i + 3].u.operand, 4);
+ emitCall(i, Machine::cti_op_new_array);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_resolve: {
+ Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
+ emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
+ emitCall(i, Machine::cti_op_resolve);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_construct: {
+ compileOpCall(instruction, i, OpConstruct);
+ i += 5;
+ break;
+ }
+ case op_get_by_val: {
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 3].u.operand, MacroAssembler::edx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::edx, i);
+ emitFastArithImmToInt(MacroAssembler::edx);
+ m_jit.emitTestl_i32r(JSImmediate::TagMask, MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+ m_jit.emitCmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsArrayVptr), MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+ m_jit.emitCmpl_rm(MacroAssembler::edx, OBJECT_OFFSET(JSArray, m_fastAccessCutoff), MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJbe(), i));
+
+ m_jit.emitMovl_mr(OBJECT_OFFSET(JSArray, m_storage), MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(ArrayStorage, m_vector[0]), MacroAssembler::eax, MacroAssembler::edx, sizeof(JSValue*), MacroAssembler::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_resolve_func: {
+ Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
+ emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
+ emitCall(i, Machine::cti_op_resolve_func);
+ emitPutResult(instruction[i + 1].u.operand);
+ emitGetCTIParam(CTI_ARGS_2ndResult, MacroAssembler::eax);
+ emitPutResult(instruction[i + 2].u.operand);
+ i += 4;
+ break;
+ }
+ case op_sub: {
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 3].u.operand, MacroAssembler::edx);
+ emitJumpSlowCaseIfNotImms(MacroAssembler::eax, MacroAssembler::edx, i);
+ m_jit.emitSubl_rr(MacroAssembler::edx, MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
+ emitFastArithReTagImmediate(MacroAssembler::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_put_by_val: {
+ emitGetArg(instruction[i + 1].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::edx);
+ emitGetArg(instruction[i + 3].u.operand, MacroAssembler::ecx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::edx, i);
+ emitFastArithImmToInt(MacroAssembler::edx);
+ m_jit.emitTestl_i32r(JSImmediate::TagMask, MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+ m_jit.emitCmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsArrayVptr), MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+ m_jit.emitCmpl_rm(MacroAssembler::edx, OBJECT_OFFSET(JSArray, m_fastAccessCutoff), MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJbe(), i));
+
+ m_jit.emitMovl_mr(OBJECT_OFFSET(JSArray, m_storage), MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.emitMovl_rm(MacroAssembler::ecx, OBJECT_OFFSET(ArrayStorage, m_vector[0]), MacroAssembler::eax, MacroAssembler::edx, sizeof(JSValue*));
+ i += 4;
+ break;
+ }
+ CTI_COMPILE_BINARY_OP(op_lesseq)
+ case op_loop_if_true: {
+ m_jit.emitSubl_i8r(1, MacroAssembler::esi);
+ MacroAssembler::JmpSrc skipTimeout = m_jit.emitUnlinkedJne();
+ emitCall(i, Machine::cti_timeout_check);
+
+ emitGetCTIParam(CTI_ARGS_exec, MacroAssembler::ecx);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(ExecState, m_globalData) + OBJECT_OFFSET(JSGlobalData, machine), MacroAssembler::ecx, MacroAssembler::ecx);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(Machine, m_ticksUntilNextTimeoutCheck), MacroAssembler::ecx, MacroAssembler::esi);
+ m_jit.link(skipTimeout, m_jit.label());
+
+ unsigned target = instruction[i + 2].u.operand;
+ emitGetArg(instruction[i + 1].u.operand, MacroAssembler::eax);
+
+ m_jit.emitCmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::zeroImmediate()), MacroAssembler::eax);
+ MacroAssembler::JmpSrc isZero = m_jit.emitUnlinkedJe();
+ m_jit.emitTestl_i32r(JSImmediate::TagBitTypeInteger, MacroAssembler::eax);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJne(), i + 2 + target));
+
+ m_jit.emitCmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), MacroAssembler::eax);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
+ m_jit.emitCmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+
+ m_jit.link(isZero, m_jit.label());
+ i += 3;
+ break;
+ };
+ case op_resolve_base: {
+ Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
+ emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
+ emitCall(i, Machine::cti_op_resolve_base);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_negate: {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_negate);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_resolve_skip: {
+ Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
+ emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
+ emitPutArgConstant(instruction[i + 3].u.operand + m_codeBlock->needsFullScopeChain, 4);
+ emitCall(i, Machine::cti_op_resolve_skip);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ CTI_COMPILE_BINARY_OP(op_div)
+ case op_pre_dec: {
+ int srcDst = instruction[i + 1].u.operand;
+ emitGetArg(srcDst, MacroAssembler::eax);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ m_jit.emitSubl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
+ emitPutResult(srcDst, MacroAssembler::eax);
+ i += 2;
+ break;
+ }
+ case op_jnless: {
+ unsigned target = instruction[i + 3].u.operand;
+ JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
+ if (src2imm) {
+ emitGetArg(instruction[i + 1].u.operand, MacroAssembler::edx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::edx, i);
+ m_jit.emitCmpl_i32r((unsigned)src2imm, MacroAssembler::edx);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJge(), i + 3 + target));
+ } else {
+ emitGetArg(instruction[i + 1].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::edx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::edx, i);
+ m_jit.emitCmpl_rr(MacroAssembler::edx, MacroAssembler::eax);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJge(), i + 3 + target));
+ }
+ i += 4;
+ break;
+ }
+ case op_not: {
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::eax);
+ m_jit.emitXorl_i8r(JSImmediate::FullTagTypeBool, MacroAssembler::eax);
+ m_jit.emitTestl_i32r(JSImmediate::FullTagTypeMask, MacroAssembler::eax); // i8?
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+ m_jit.emitXorl_i8r((JSImmediate::FullTagTypeBool | JSImmediate::ExtendedPayloadBitBoolValue), MacroAssembler::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_jfalse: {
+ unsigned target = instruction[i + 2].u.operand;
+ emitGetArg(instruction[i + 1].u.operand, MacroAssembler::eax);
+
+ m_jit.emitCmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::zeroImmediate()), MacroAssembler::eax);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
+ m_jit.emitTestl_i32r(JSImmediate::TagBitTypeInteger, MacroAssembler::eax);
+ MacroAssembler::JmpSrc isNonZero = m_jit.emitUnlinkedJne();
+
+ m_jit.emitCmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), MacroAssembler::eax);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
+ m_jit.emitCmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+
+ m_jit.link(isNonZero, m_jit.label());
+ i += 3;
+ break;
+ };
+ case op_post_inc: {
+ int srcDst = instruction[i + 2].u.operand;
+ emitGetArg(srcDst, MacroAssembler::eax);
+ m_jit.emitMovl_rr(MacroAssembler::eax, MacroAssembler::edx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ m_jit.emitAddl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), MacroAssembler::edx);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
+ emitPutResult(srcDst, MacroAssembler::edx);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_unexpected_load: {
+ JSValue* v = m_codeBlock->unexpectedConstants[instruction[i + 2].u.operand];
+ m_jit.emitMovl_i32r((unsigned)v, MacroAssembler::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_jsr: {
+ int retAddrDst = instruction[i + 1].u.operand;
+ int target = instruction[i + 2].u.operand;
+ m_jit.emitMovl_i32m(0, sizeof(Register) * retAddrDst, MacroAssembler::edi);
+ MacroAssembler::JmpDst addrPosition = m_jit.label();
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 2 + target));
+ MacroAssembler::JmpDst sretTarget = m_jit.label();
+ m_jsrSites.append(JSRInfo(addrPosition, sretTarget));
+ i += 3;
+ break;
+ }
+ case op_sret: {
+ m_jit.emitJmpN_m(sizeof(Register) * instruction[i + 1].u.operand, MacroAssembler::edi);
+ i += 2;
+ break;
+ }
+ CTI_COMPILE_BINARY_OP(op_eq)
+ case op_lshift: {
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 3].u.operand, MacroAssembler::ecx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::ecx, i);
+ emitFastArithImmToInt(MacroAssembler::eax);
+ emitFastArithImmToInt(MacroAssembler::ecx);
+ m_jit.emitShll_CLr(MacroAssembler::eax);
+ emitFastArithIntToImmOrSlowCase(MacroAssembler::eax, i);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_bitand: {
+ unsigned src1 = instruction[i + 2].u.operand;
+ unsigned src2 = instruction[i + 3].u.operand;
+ unsigned dst = instruction[i + 1].u.operand;
+ if (JSValue* value = getConstantImmediateNumericArg(src1)) {
+ emitGetArg(src2, MacroAssembler::eax);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ m_jit.emitAndl_i32r((unsigned)value, MacroAssembler::eax); // FIXME: make it more obvious this is relying on the format of JSImmediate
+ emitPutResult(dst);
+ } else if (JSValue* value = getConstantImmediateNumericArg(src2)) {
+ emitGetArg(src1, MacroAssembler::eax);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ m_jit.emitAndl_i32r((unsigned)value, MacroAssembler::eax);
+ emitPutResult(dst);
+ } else {
+ emitGetArg(src1, MacroAssembler::eax);
+ emitGetArg(src2, MacroAssembler::edx);
+ m_jit.emitAndl_rr(MacroAssembler::edx, MacroAssembler::eax);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ emitPutResult(dst);
+ }
+ i += 4;
+ break;
+ }
+ case op_rshift: {
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 3].u.operand, MacroAssembler::ecx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::ecx, i);
+ emitFastArithImmToInt(MacroAssembler::ecx);
+ m_jit.emitSarl_CLr(MacroAssembler::eax);
+ emitFastArithPotentiallyReTagImmediate(MacroAssembler::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_bitnot: {
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::eax);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ m_jit.emitXorl_i8r(~JSImmediate::TagBitTypeInteger, MacroAssembler::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_resolve_with_base: {
+ Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
+ emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
+ emitCall(i, Machine::cti_op_resolve_with_base);
+ emitPutResult(instruction[i + 1].u.operand);
+ emitGetCTIParam(CTI_ARGS_2ndResult, MacroAssembler::eax);
+ emitPutResult(instruction[i + 2].u.operand);
+ i += 4;
+ break;
+ }
+ case op_new_func_exp: {
+ FuncExprNode* func = (m_codeBlock->functionExpressions[instruction[i + 2].u.operand]).get();
+ emitPutArgConstant(reinterpret_cast<unsigned>(func), 0);
+ emitCall(i, Machine::cti_op_new_func_exp);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_mod: {
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 3].u.operand, MacroAssembler::ecx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::ecx, i);
+ emitFastArithDeTagImmediate(MacroAssembler::eax);
+ emitFastArithDeTagImmediate(MacroAssembler::ecx);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), i)); // This is checking if the last detag resulted in a value 0.
+ m_jit.emitCdq();
+ m_jit.emitIdivl_r(MacroAssembler::ecx);
+ emitFastArithReTagImmediate(MacroAssembler::edx);
+ m_jit.emitMovl_rr(MacroAssembler::edx, MacroAssembler::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_jtrue: {
+ unsigned target = instruction[i + 2].u.operand;
+ emitGetArg(instruction[i + 1].u.operand, MacroAssembler::eax);
+
+ m_jit.emitCmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::zeroImmediate()), MacroAssembler::eax);
+ MacroAssembler::JmpSrc isZero = m_jit.emitUnlinkedJe();
+ m_jit.emitTestl_i32r(JSImmediate::TagBitTypeInteger, MacroAssembler::eax);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJne(), i + 2 + target));
+
+ m_jit.emitCmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), MacroAssembler::eax);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
+ m_jit.emitCmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), MacroAssembler::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+
+ m_jit.link(isZero, m_jit.label());
+ i += 3;
+ break;
+ }
+ CTI_COMPILE_BINARY_OP(op_less)
+ CTI_COMPILE_BINARY_OP(op_neq)
+ case op_post_dec: {
+ int srcDst = instruction[i + 2].u.operand;
+ emitGetArg(srcDst, MacroAssembler::eax);
+ m_jit.emitMovl_rr(MacroAssembler::eax, MacroAssembler::edx);
+ emitJumpSlowCaseIfNotImm(MacroAssembler::eax, i);
+ m_jit.emitSubl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), MacroAssembler::edx);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
+ emitPutResult(srcDst, MacroAssembler::edx);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ CTI_COMPILE_BINARY_OP(op_urshift)
+ case op_bitxor: {
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 3].u.operand, MacroAssembler::edx);
+ emitJumpSlowCaseIfNotImms(MacroAssembler::eax, MacroAssembler::edx, i);
+ m_jit.emitXorl_rr(MacroAssembler::edx, MacroAssembler::eax);
+ emitFastArithReTagImmediate(MacroAssembler::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_new_regexp: {
+ RegExp* regExp = m_codeBlock->regexps[instruction[i + 2].u.operand].get();
+ emitPutArgConstant(reinterpret_cast<unsigned>(regExp), 0);
+ emitCall(i, Machine::cti_op_new_regexp);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_bitor: {
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 3].u.operand, MacroAssembler::edx);
+ emitJumpSlowCaseIfNotImms(MacroAssembler::eax, MacroAssembler::edx, i);
+ m_jit.emitOrl_rr(MacroAssembler::edx, MacroAssembler::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_call_eval: {
+ compileOpCall(instruction, i, OpCallEval);
+ i += 6;
+ break;
+ }
+ case op_throw: {
+ emitGetPutArg(instruction[i + 1].u.operand, 0, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_throw);
+ m_jit.emitAddl_i8r(0x24, MacroAssembler::esp);
+ m_jit.emitPopl_r(MacroAssembler::edi);
+ m_jit.emitPopl_r(MacroAssembler::esi);
+ m_jit.emitRet();
+ i += 2;
+ break;
+ }
+ case op_get_pnames: {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_get_pnames);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_next_pname: {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ unsigned target = instruction[i + 3].u.operand;
+ emitCall(i, Machine::cti_op_next_pname);
+ m_jit.emitTestl_rr(MacroAssembler::eax, MacroAssembler::eax);
+ MacroAssembler::JmpSrc endOfIter = m_jit.emitUnlinkedJe();
+ emitPutResult(instruction[i + 1].u.operand);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 3 + target));
+ m_jit.link(endOfIter, m_jit.label());
+ i += 4;
+ break;
+ }
+ case op_push_scope: {
+ emitGetPutArg(instruction[i + 1].u.operand, 0, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_push_scope);
+ i += 2;
+ break;
+ }
+ case op_pop_scope: {
+ emitCall(i, Machine::cti_op_pop_scope);
+ i += 1;
+ break;
+ }
+ case op_typeof: {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_typeof);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ CTI_COMPILE_BINARY_OP(op_stricteq)
+ CTI_COMPILE_BINARY_OP(op_nstricteq)
+ case op_to_jsnumber: {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_to_jsnumber);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_in: {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ emitGetPutArg(instruction[i + 3].u.operand, 4, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_in);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_push_new_scope: {
+ Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
+ emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
+ emitGetPutArg(instruction[i + 3].u.operand, 4, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_push_new_scope);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_catch: {
+ emitGetCTIParam(CTI_ARGS_r, MacroAssembler::edi); // edi := r
+ emitGetCTIParam(CTI_ARGS_exec, MacroAssembler::ecx);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(ExecState, m_exception), MacroAssembler::ecx, MacroAssembler::eax);
+ m_jit.emitMovl_i32m(0, OBJECT_OFFSET(ExecState, m_exception), MacroAssembler::ecx);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 2;
+ break;
+ }
+ case op_jmp_scopes: {
+ unsigned count = instruction[i + 1].u.operand;
+ emitPutArgConstant(count, 0);
+ emitCall(i, Machine::cti_op_jmp_scopes);
+ unsigned target = instruction[i + 2].u.operand;
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 2 + target));
+ i += 3;
+ break;
+ }
+ case op_put_by_index: {
+ emitGetPutArg(instruction[i + 1].u.operand, 0, MacroAssembler::ecx);
+ emitPutArgConstant(instruction[i + 2].u.operand, 4);
+ emitGetPutArg(instruction[i + 3].u.operand, 8, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_put_by_index);
+ i += 4;
+ break;
+ }
+ case op_switch_imm: {
+ unsigned tableIndex = instruction[i + 1].u.operand;
+ unsigned defaultOffset = instruction[i + 2].u.operand;
+ unsigned scrutinee = instruction[i + 3].u.operand;
+
+ // create jump table for switch destinations, track this switch statement.
+ SimpleJumpTable* jumpTable = &m_codeBlock->immediateSwitchJumpTables[tableIndex];
+ m_switches.append(SwitchRecord(jumpTable, i, defaultOffset, SwitchRecord::Immediate));
+ jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
+
+ emitGetPutArg(scrutinee, 0, MacroAssembler::ecx);
+ emitPutArgConstant(tableIndex, 4);
+ emitCall(i, Machine::cti_op_switch_imm);
+ m_jit.emitJmpN_r(MacroAssembler::eax);
+ i += 4;
+ break;
+ }
+ case op_switch_char: {
+ unsigned tableIndex = instruction[i + 1].u.operand;
+ unsigned defaultOffset = instruction[i + 2].u.operand;
+ unsigned scrutinee = instruction[i + 3].u.operand;
+
+ // create jump table for switch destinations, track this switch statement.
+ SimpleJumpTable* jumpTable = &m_codeBlock->characterSwitchJumpTables[tableIndex];
+ m_switches.append(SwitchRecord(jumpTable, i, defaultOffset, SwitchRecord::Character));
+ jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
+
+ emitGetPutArg(scrutinee, 0, MacroAssembler::ecx);
+ emitPutArgConstant(tableIndex, 4);
+ emitCall(i, Machine::cti_op_switch_char);
+ m_jit.emitJmpN_r(MacroAssembler::eax);
+ i += 4;
+ break;
+ }
+ case op_switch_string: {
+ unsigned tableIndex = instruction[i + 1].u.operand;
+ unsigned defaultOffset = instruction[i + 2].u.operand;
+ unsigned scrutinee = instruction[i + 3].u.operand;
+
+ // create jump table for switch destinations, track this switch statement.
+ StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTables[tableIndex];
+ m_switches.append(SwitchRecord(jumpTable, i, defaultOffset));
+
+ emitGetPutArg(scrutinee, 0, MacroAssembler::ecx);
+ emitPutArgConstant(tableIndex, 4);
+ emitCall(i, Machine::cti_op_switch_string);
+ m_jit.emitJmpN_r(MacroAssembler::eax);
+ i += 4;
+ break;
+ }
+ case op_del_by_val: {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ emitGetPutArg(instruction[i + 3].u.operand, 4, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_del_by_val);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_put_getter: {
+ emitGetPutArg(instruction[i + 1].u.operand, 0, MacroAssembler::ecx);
+ Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
+ emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
+ emitGetPutArg(instruction[i + 3].u.operand, 8, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_put_getter);
+ i += 4;
+ break;
+ }
+ case op_put_setter: {
+ emitGetPutArg(instruction[i + 1].u.operand, 0, MacroAssembler::ecx);
+ Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
+ emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
+ emitGetPutArg(instruction[i + 3].u.operand, 8, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_put_setter);
+ i += 4;
+ break;
+ }
+ case op_new_error: {
+ JSValue* message = m_codeBlock->unexpectedConstants[instruction[i + 3].u.operand];
+ emitPutArgConstant(instruction[i + 2].u.operand, 0);
+ emitPutArgConstant(reinterpret_cast<unsigned>(message), 4);
+ emitPutArgConstant(m_codeBlock->lineNumberForVPC(&instruction[i]), 8);
+ emitCall(i, Machine::cti_op_new_error);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_debug: {
+ emitPutArgConstant(instruction[i + 1].u.operand, 0);
+ emitPutArgConstant(instruction[i + 2].u.operand, 4);
+ emitPutArgConstant(instruction[i + 3].u.operand, 8);
+ emitCall(i, Machine::cti_op_debug);
+ i += 4;
+ break;
+ }
+ case op_eq_null: {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_eq_null);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_neq_null: {
+ emitGetPutArg(instruction[i + 2].u.operand, 0, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_neq_null);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_get_array_length:
+ case op_get_by_id_chain:
+ case op_get_by_id_generic:
+ case op_get_by_id_proto:
+ case op_get_by_id_self:
+ case op_get_string_length:
+ case op_put_by_id_generic:
+ case op_put_by_id_replace:
+ ASSERT_NOT_REACHED();
+ }
+ }
+}
+
+
+void CTI::privateCompileLinkPass()
+{
+ unsigned jmpTableCount = m_jmpTable.size();
+ for (unsigned i = 0; i < jmpTableCount; ++i)
+ m_jit.link(m_jmpTable[i].from, m_labels[m_jmpTable[i].to]);
+ m_jmpTable.clear();
+}
+
+void CTI::privateCompileSlowCases()
+{
+ Instruction* instruction = m_codeBlock->instructions.begin();
+ for (Vector<SlowCaseEntry>::iterator iter = m_slowCases.begin(); iter != m_slowCases.end(); ++iter) {
+ int i = iter->to;
+ m_jit.emitRestoreArgumentReference();
+ switch (m_machine->getOpcodeID(instruction[i].u.opcode)) {
+ case op_add: {
+ unsigned dst = instruction[i + 1].u.operand;
+ unsigned src2 = instruction[i + 3].u.operand;
+ if (src2 < m_codeBlock->constantRegisters.size()) {
+ JSValue* value = m_codeBlock->constantRegisters[src2].jsValue(m_exec);
+ if (JSImmediate::isNumber(value)) {
+ MacroAssembler::JmpSrc notImm = iter->from;
+ m_jit.link((++iter)->from, m_jit.label());
+ m_jit.emitSubl_i32r(getDeTaggedConstantImmediate(value), MacroAssembler::eax);
+ m_jit.link(notImm, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitGetPutArg(src2, 4, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_add);
+ emitPutResult(dst);
+ i += 4;
+ break;
+ }
+ }
+
+ ASSERT(!(static_cast<unsigned>(instruction[i + 2].u.operand) < m_codeBlock->constantRegisters.size()));
+
+ MacroAssembler::JmpSrc notImm = iter->from;
+ m_jit.link((++iter)->from, m_jit.label());
+ m_jit.emitSubl_rr(MacroAssembler::edx, MacroAssembler::eax);
+ emitFastArithReTagImmediate(MacroAssembler::eax);
+ m_jit.link(notImm, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitPutArg(MacroAssembler::edx, 4);
+ emitCall(i, Machine::cti_op_add);
+ emitPutResult(dst);
+ i += 4;
+ break;
+ }
+ case op_get_by_val: {
+ MacroAssembler::JmpSrc notImm = iter->from;
+ m_jit.link((++iter)->from, m_jit.label());
+ m_jit.link((++iter)->from, m_jit.label());
+ m_jit.link((++iter)->from, m_jit.label());
+ emitFastArithIntToImmNoCheck(MacroAssembler::edx);
+ m_jit.link(notImm, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitPutArg(MacroAssembler::edx, 4);
+ emitCall(i, Machine::cti_op_get_by_val);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_sub: {
+ MacroAssembler::JmpSrc notImm = iter->from;
+ m_jit.link((++iter)->from, m_jit.label());
+ m_jit.emitAddl_rr(MacroAssembler::edx, MacroAssembler::eax);
+ m_jit.link(notImm, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitPutArg(MacroAssembler::edx, 4);
+ emitCall(i, Machine::cti_op_sub);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_rshift: {
+ m_jit.link(iter->from, m_jit.label());
+ m_jit.link((++iter)->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitPutArg(MacroAssembler::ecx, 4);
+ emitCall(i, Machine::cti_op_rshift);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_lshift: {
+ MacroAssembler::JmpSrc notImm1 = iter->from;
+ MacroAssembler::JmpSrc notImm2 = (++iter)->from;
+ m_jit.link((++iter)->from, m_jit.label());
+ emitGetArg(instruction[i + 2].u.operand, MacroAssembler::eax);
+ emitGetArg(instruction[i + 3].u.operand, MacroAssembler::ecx);
+ m_jit.link(notImm1, m_jit.label());
+ m_jit.link(notImm2, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitPutArg(MacroAssembler::ecx, 4);
+ emitCall(i, Machine::cti_op_lshift);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_loop_if_less: {
+ unsigned target = instruction[i + 3].u.operand;
+ JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
+ if (src2imm) {
+ m_jit.link(iter->from, m_jit.label());
+ emitPutArg(MacroAssembler::edx, 0);
+ emitGetPutArg(instruction[i + 2].u.operand, 4, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_loop_if_less);
+ m_jit.emitTestl_rr(MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
+ } else {
+ m_jit.link(iter->from, m_jit.label());
+ m_jit.link((++iter)->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitPutArg(MacroAssembler::edx, 4);
+ emitCall(i, Machine::cti_op_loop_if_less);
+ m_jit.emitTestl_rr(MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
+ }
+ i += 4;
+ break;
+ }
+ case op_pre_inc: {
+ unsigned srcDst = instruction[i + 1].u.operand;
+ MacroAssembler::JmpSrc notImm = iter->from;
+ m_jit.link((++iter)->from, m_jit.label());
+ m_jit.emitSubl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), MacroAssembler::eax);
+ m_jit.link(notImm, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitCall(i, Machine::cti_op_pre_inc);
+ emitPutResult(srcDst);
+ i += 2;
+ break;
+ }
+ case op_put_by_val: {
+ MacroAssembler::JmpSrc notImm = iter->from;
+ m_jit.link((++iter)->from, m_jit.label());
+ m_jit.link((++iter)->from, m_jit.label());
+ m_jit.link((++iter)->from, m_jit.label());
+ emitFastArithIntToImmNoCheck(MacroAssembler::edx);
+ m_jit.link(notImm, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitPutArg(MacroAssembler::edx, 4);
+ emitPutArg(MacroAssembler::ecx, 8);
+ emitCall(i, Machine::cti_op_put_by_val);
+ i += 4;
+ break;
+ }
+ case op_loop_if_true: {
+ m_jit.link(iter->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitCall(i, Machine::cti_op_jtrue);
+ m_jit.emitTestl_rr(MacroAssembler::eax, MacroAssembler::eax);
+ unsigned target = instruction[i + 2].u.operand;
+ m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 2 + target]);
+ i += 3;
+ break;
+ }
+ case op_pre_dec: {
+ unsigned srcDst = instruction[i + 1].u.operand;
+ MacroAssembler::JmpSrc notImm = iter->from;
+ m_jit.link((++iter)->from, m_jit.label());
+ m_jit.emitAddl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), MacroAssembler::eax);
+ m_jit.link(notImm, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitCall(i, Machine::cti_op_pre_dec);
+ emitPutResult(srcDst);
+ i += 2;
+ break;
+ }
+ case op_jnless: {
+ unsigned target = instruction[i + 3].u.operand;
+ JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
+ if (src2imm) {
+ m_jit.link(iter->from, m_jit.label());
+ emitPutArg(MacroAssembler::edx, 0);
+ emitGetPutArg(instruction[i + 2].u.operand, 4, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_jless);
+ m_jit.emitTestl_rr(MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 3 + target]);
+ } else {
+ m_jit.link(iter->from, m_jit.label());
+ m_jit.link((++iter)->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitPutArg(MacroAssembler::edx, 4);
+ emitCall(i, Machine::cti_op_jless);
+ m_jit.emitTestl_rr(MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 3 + target]);
+ }
+ i += 4;
+ break;
+ }
+ case op_not: {
+ m_jit.link(iter->from, m_jit.label());
+ m_jit.emitXorl_i8r(JSImmediate::FullTagTypeBool, MacroAssembler::eax);
+ emitPutArg(MacroAssembler::eax, 0);
+ emitCall(i, Machine::cti_op_not);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_jfalse: {
+ m_jit.link(iter->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitCall(i, Machine::cti_op_jtrue);
+ m_jit.emitTestl_rr(MacroAssembler::eax, MacroAssembler::eax);
+ unsigned target = instruction[i + 2].u.operand;
+ m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 2 + target]); // inverted!
+ i += 3;
+ break;
+ }
+ case op_post_inc: {
+ unsigned srcDst = instruction[i + 2].u.operand;
+ m_jit.link(iter->from, m_jit.label());
+ m_jit.link((++iter)->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitCall(i, Machine::cti_op_post_inc);
+ emitPutResult(instruction[i + 1].u.operand);
+ emitGetCTIParam(CTI_ARGS_2ndResult, MacroAssembler::eax);
+ emitPutResult(srcDst);
+ i += 3;
+ break;
+ }
+ case op_bitnot: {
+ m_jit.link(iter->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitCall(i, Machine::cti_op_bitnot);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
+ case op_bitand: {
+ unsigned src1 = instruction[i + 2].u.operand;
+ unsigned src2 = instruction[i + 3].u.operand;
+ unsigned dst = instruction[i + 1].u.operand;
+ if (getConstantImmediateNumericArg(src1)) {
+ m_jit.link(iter->from, m_jit.label());
+ emitGetPutArg(src1, 0, MacroAssembler::ecx);
+ emitPutArg(MacroAssembler::eax, 4);
+ emitCall(i, Machine::cti_op_bitand);
+ emitPutResult(dst);
+ } else if (getConstantImmediateNumericArg(src2)) {
+ m_jit.link(iter->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitGetPutArg(src2, 4, MacroAssembler::ecx);
+ emitCall(i, Machine::cti_op_bitand);
+ emitPutResult(dst);
+ } else {
+ m_jit.link(iter->from, m_jit.label());
+ emitGetPutArg(src1, 0, MacroAssembler::ecx);
+ emitPutArg(MacroAssembler::edx, 4);
+ emitCall(i, Machine::cti_op_bitand);
+ emitPutResult(dst);
+ }
+ i += 4;
+ break;
+ }
+ case op_jtrue: {
+ m_jit.link(iter->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitCall(i, Machine::cti_op_jtrue);
+ m_jit.emitTestl_rr(MacroAssembler::eax, MacroAssembler::eax);
+ unsigned target = instruction[i + 2].u.operand;
+ m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 2 + target]);
+ i += 3;
+ break;
+ }
+ case op_post_dec: {
+ unsigned srcDst = instruction[i + 2].u.operand;
+ m_jit.link(iter->from, m_jit.label());
+ m_jit.link((++iter)->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitCall(i, Machine::cti_op_post_dec);
+ emitPutResult(instruction[i + 1].u.operand);
+ emitGetCTIParam(CTI_ARGS_2ndResult, MacroAssembler::eax);
+ emitPutResult(srcDst);
+ i += 3;
+ break;
+ }
+ case op_bitxor: {
+ m_jit.link(iter->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitPutArg(MacroAssembler::edx, 4);
+ emitCall(i, Machine::cti_op_bitxor);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_bitor: {
+ m_jit.link(iter->from, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitPutArg(MacroAssembler::edx, 4);
+ emitCall(i, Machine::cti_op_bitor);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ case op_mod: {
+ MacroAssembler::JmpSrc notImm1 = iter->from;
+ MacroAssembler::JmpSrc notImm2 = (++iter)->from;
+ m_jit.link((++iter)->from, m_jit.label());
+ emitFastArithReTagImmediate(MacroAssembler::eax);
+ emitFastArithReTagImmediate(MacroAssembler::ecx);
+ m_jit.link(notImm1, m_jit.label());
+ m_jit.link(notImm2, m_jit.label());
+ emitPutArg(MacroAssembler::eax, 0);
+ emitPutArg(MacroAssembler::ecx, 4);
+ emitCall(i, Machine::cti_op_mod);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ m_jit.link(m_jit.emitUnlinkedJmp(), m_labels[i]);
+ }
+}
+
+void CTI::privateCompile()
+{
+ // Could use a emitPopl_m, but would need to offset the following instruction if so.
+ m_jit.emitPopl_r(MacroAssembler::ecx);
+ emitGetCTIParam(CTI_ARGS_r, MacroAssembler::edi); // edi := r
+ emitPutToCallFrameHeader(MacroAssembler::ecx, RegisterFile::CTIReturnEIP);
+
+ privateCompileMainPass();
+ privateCompileLinkPass();
+ privateCompileSlowCases();
+
+ ASSERT(m_jmpTable.isEmpty());
+
+ void* code = m_jit.copy();
+ ASSERT(code);
+
+ // Translate vPC offsets into addresses in JIT generated code, for switch tables.
+ for (unsigned i = 0; i < m_switches.size(); ++i) {
+ SwitchRecord record = m_switches[i];
+ unsigned opcodeIndex = record.m_opcodeIndex;
+
+ if (record.m_type != SwitchRecord::String) {
+ ASSERT(record.m_type == SwitchRecord::Immediate || record.m_type == SwitchRecord::Character);
+ ASSERT(record.m_jumpTable.m_simpleJumpTable->branchOffsets.size() == record.m_jumpTable.m_simpleJumpTable->ctiOffsets.size());
+
+ record.m_jumpTable.m_simpleJumpTable->ctiDefault = m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + record.m_defaultOffset]);
+
+ for (unsigned j = 0; j < record.m_jumpTable.m_simpleJumpTable->branchOffsets.size(); ++j) {
+ unsigned offset = record.m_jumpTable.m_simpleJumpTable->branchOffsets[j];
+ record.m_jumpTable.m_simpleJumpTable->ctiOffsets[j] = offset ? m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + offset]) : record.m_jumpTable.m_simpleJumpTable->ctiDefault;
+ }
+ } else {
+ ASSERT(record.m_type == SwitchRecord::String);
+
+ record.m_jumpTable.m_stringJumpTable->ctiDefault = m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + record.m_defaultOffset]);
+
+ StringJumpTable::StringOffsetTable::iterator end = record.m_jumpTable.m_stringJumpTable->offsetTable.end();
+ for (StringJumpTable::StringOffsetTable::iterator it = record.m_jumpTable.m_stringJumpTable->offsetTable.begin(); it != end; ++it) {
+ unsigned offset = it->second.branchOffset;
+ it->second.ctiOffset = offset ? m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + offset]) : record.m_jumpTable.m_stringJumpTable->ctiDefault;
+ }
+ }
+ }
+
+ for (Vector<HandlerInfo>::iterator iter = m_codeBlock->exceptionHandlers.begin(); iter != m_codeBlock->exceptionHandlers.end(); ++iter)
+ iter->nativeCode = m_jit.getRelocatedAddress(code, m_labels[iter->target]);
+
+ // FIXME: There doesn't seem to be a way to hint to a hashmap that it should make a certain capacity available;
+ // could be faster if we could do something like this:
+ // m_codeBlock->ctiReturnAddressVPCMap.grow(m_calls.size());
+ for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
+ MacroAssembler::link(code, iter->from, iter->to);
+ m_codeBlock->ctiReturnAddressVPCMap.add(m_jit.getRelocatedAddress(code, iter->from), iter->opcodeIndex);
+ }
+
+ // Link absolute addresses for jsr
+ for (Vector<JSRInfo>::iterator iter = m_jsrSites.begin(); iter != m_jsrSites.end(); ++iter)
+ MacroAssembler::linkAbsoluteAddress(code, iter->addrPosition, iter->target);
+
+ m_codeBlock->ctiCode = code;
+}
+
+void* CTI::privateCompileGetByIdSelf(StructureID* structureID, size_t cachedOffset)
+{
+ // Check eax is an object of the right StructureID.
+ m_jit.emitTestl_i32r(JSImmediate::TagMask, MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
+ m_jit.emitCmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
+
+ // Checks out okay! - getDirectOffset
+ m_jit.emitMovl_mr(OBJECT_OFFSET(JSObject, m_propertyMap) + OBJECT_OFFSET(PropertyMap, m_u.table), MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(PropertyMapHashTable, entryIndices[0]) + (cachedOffset * sizeof(JSValue*)), MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.emitRet();
+
+ void* code = m_jit.copy();
+ ASSERT(code);
+
+ MacroAssembler::link(code, failureCases1, (void*)Machine::cti_op_get_by_id_fail);
+ MacroAssembler::link(code, failureCases2, (void*)Machine::cti_op_get_by_id_fail);
+
+ m_codeBlock->structureIDAccessStubs.append(code);
+
+ return code;
+}
+
+void* CTI::privateCompileGetByIdProto(StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset)
+{
+ // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a StructureID that is
+ // referencing the prototype object - let's speculatively load it's table nice and early!)
+ JSObject* protoObject = static_cast<JSObject*>(structureID->prototype());
+ PropertyMapHashTable** protoTableAddress = &(protoObject->m_propertyMap.m_u.table);
+ m_jit.emitMovl_mr((void*)protoTableAddress, MacroAssembler::edx);
+
+ // check eax is an object of the right StructureID.
+ m_jit.emitTestl_i32r(JSImmediate::TagMask, MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
+ m_jit.emitCmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
+
+ // Check the prototype object's StructureID had not changed.
+ StructureID** protoStructureIDAddress = &(protoObject->m_structureID);
+ m_jit.emitCmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructureID), (void*)protoStructureIDAddress);
+ MacroAssembler::JmpSrc failureCases3 = m_jit.emitUnlinkedJne();
+
+ // Checks out okay! - getDirectOffset
+
+ m_jit.emitMovl_mr(OBJECT_OFFSET(PropertyMapHashTable, entryIndices[0]) + (cachedOffset * sizeof(JSValue*)), MacroAssembler::edx, MacroAssembler::eax);
+
+ m_jit.emitRet();
+
+ void* code = m_jit.copy();
+ ASSERT(code);
+
+ MacroAssembler::link(code, failureCases1, (void*)Machine::cti_op_get_by_id_fail);
+ MacroAssembler::link(code, failureCases2, (void*)Machine::cti_op_get_by_id_fail);
+ MacroAssembler::link(code, failureCases3, (void*)Machine::cti_op_get_by_id_fail);
+
+ m_codeBlock->structureIDAccessStubs.append(code);
+
+ return code;
+}
+
+void* CTI::privateCompileGetByIdChain(StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset)
+{
+ ASSERT(count);
+
+ Vector<MacroAssembler::JmpSrc> bucketsOfFail;
+
+ // Check eax is an object of the right StructureID.
+ m_jit.emitTestl_i32r(JSImmediate::TagMask, MacroAssembler::eax);
+ bucketsOfFail.append(m_jit.emitUnlinkedJne());
+ m_jit.emitCmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), MacroAssembler::eax);
+ bucketsOfFail.append(m_jit.emitUnlinkedJne());
+
+ StructureID* currStructureID = structureID;
+ RefPtr<StructureID>* chainEntries = chain->head();
+ JSCell* protoObject = 0;
+ for (unsigned i = 0; i<count; ++i) {
+ protoObject = static_cast<JSCell*>(currStructureID->prototype());
+ currStructureID = chainEntries[i].get();
+
+ // Check the prototype object's StructureID had not changed.
+ StructureID** protoStructureIDAddress = &(protoObject->m_structureID);
+ m_jit.emitCmpl_i32m(reinterpret_cast<uint32_t>(currStructureID), (void*)protoStructureIDAddress);
+ bucketsOfFail.append(m_jit.emitUnlinkedJne());
+ }
+ ASSERT(protoObject);
+
+ PropertyMapHashTable** protoTableAddress = &(reinterpret_cast<JSObject*>(protoObject)->m_propertyMap.m_u.table);
+ m_jit.emitMovl_mr((void*)protoTableAddress, MacroAssembler::edx);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(PropertyMapHashTable, entryIndices[0]) + (cachedOffset * sizeof(JSValue*)), MacroAssembler::edx, MacroAssembler::eax);
+ m_jit.emitRet();
+
+ bucketsOfFail.append(m_jit.emitUnlinkedJmp());
+
+ void* code = m_jit.copy();
+ ASSERT(code);
+
+ for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
+ MacroAssembler::link(code, bucketsOfFail[i], (void*)Machine::cti_op_get_by_id_fail);
+ m_codeBlock->structureIDAccessStubs.append(code);
+ return code;
+}
+
+void* CTI::privateCompilePutByIdReplace(StructureID* structureID, size_t cachedOffset)
+{
+ // check eax is an object of the right StructureID.
+ m_jit.emitTestl_i32r(JSImmediate::TagMask, MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
+ m_jit.emitCmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
+
+ // checks out okay! - putDirectOffset
+ m_jit.emitMovl_mr(OBJECT_OFFSET(JSObject, m_propertyMap) + OBJECT_OFFSET(PropertyMap, m_u.table), MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.emitMovl_rm(MacroAssembler::edx, OBJECT_OFFSET(PropertyMapHashTable, entryIndices[0]) + (cachedOffset * sizeof(JSValue*)), MacroAssembler::eax);
+ m_jit.emitRet();
+
+ void* code = m_jit.copy();
+ ASSERT(code);
+
+ MacroAssembler::link(code, failureCases1, (void*)Machine::cti_op_put_by_id_fail);
+ MacroAssembler::link(code, failureCases2, (void*)Machine::cti_op_put_by_id_fail);
+
+ m_codeBlock->structureIDAccessStubs.append(code);
+
+ return code;
+}
+
+void* CTI::privateArrayLengthTrampoline()
+{
+ // Check eax is an array
+ m_jit.emitTestl_i32r(JSImmediate::TagMask, MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
+ m_jit.emitCmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsArrayVptr), MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
+
+ // Checks out okay! - get the length from the storage
+ m_jit.emitMovl_mr(OBJECT_OFFSET(JSArray, m_storage), MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(ArrayStorage, m_length), MacroAssembler::eax, MacroAssembler::eax);
+
+ m_jit.emitAddl_rr(MacroAssembler::eax, MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases3 = m_jit.emitUnlinkedJo();
+ m_jit.emitAddl_i8r(1, MacroAssembler::eax);
+
+ m_jit.emitRet();
+
+ void* code = m_jit.copy();
+ ASSERT(code);
+
+ MacroAssembler::link(code, failureCases1, (void*)Machine::cti_op_get_by_id_fail);
+ MacroAssembler::link(code, failureCases2, (void*)Machine::cti_op_get_by_id_fail);
+ MacroAssembler::link(code, failureCases3, (void*)Machine::cti_op_get_by_id_fail);
+
+ return code;
+}
+
+void* CTI::privateStringLengthTrampoline()
+{
+ // Check eax is a string
+ m_jit.emitTestl_i32r(JSImmediate::TagMask, MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
+ m_jit.emitCmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsStringVptr), MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
+
+ // Checks out okay! - get the length from the Ustring.
+ m_jit.emitMovl_mr(OBJECT_OFFSET(JSString, m_value) + OBJECT_OFFSET(UString, m_rep), MacroAssembler::eax, MacroAssembler::eax);
+ m_jit.emitMovl_mr(OBJECT_OFFSET(UString::Rep, len), MacroAssembler::eax, MacroAssembler::eax);
+
+ m_jit.emitAddl_rr(MacroAssembler::eax, MacroAssembler::eax);
+ MacroAssembler::JmpSrc failureCases3 = m_jit.emitUnlinkedJo();
+ m_jit.emitAddl_i8r(1, MacroAssembler::eax);
+
+ m_jit.emitRet();
+
+ void* code = m_jit.copy();
+ ASSERT(code);
+
+ MacroAssembler::link(code, failureCases1, (void*)Machine::cti_op_get_by_id_fail);
+ MacroAssembler::link(code, failureCases2, (void*)Machine::cti_op_get_by_id_fail);
+ MacroAssembler::link(code, failureCases3, (void*)Machine::cti_op_get_by_id_fail);
+
+ return code;
+}
+
+void* CTI::compileRegExp(ExecState* exec, const UString& pattern, unsigned* numSubpatterns_ptr, const char** error_ptr, bool ignoreCase, bool multiline)
+{
+ // TODO: better error messages
+ if (pattern.size() > MaxPatternSize) {
+ *error_ptr = "regular expression too large";
+ return 0;
+ }
+
+ MacroAssembler jit(exec->machine()->jitCodeBuffer());
+ WRECParser parser(pattern, ignoreCase, multiline, jit);
+
+ jit.emitConvertToFastCall();
+ // (0) Setup:
+ // Preserve regs & initialize OUTPUT_REG.
+ jit.emitPushl_r(WRECGenerator::OUTPUT_REG);
+ jit.emitPushl_r(WRECGenerator::CURR_VAL_REG);
+ // push pos onto the stack, both to preserve and as a parameter available to parseDisjunction
+ jit.emitPushl_r(WRECGenerator::CURR_POS_REG);
+ // load output pointer
+ jit.emitMovl_mr(16
+#if COMPILER(MSVC)
+ + 3 * sizeof(void*)
+#endif
+ , MacroAssembler::esp, WRECGenerator::OUTPUT_REG);
+
+ // restart point on match fail.
+ WRECGenerator::JmpDst nextLabel = jit.label();
+
+ // (1) Parse Disjunction:
+
+ // Parsing the disjunction should fully consume the pattern.
+ JmpSrcVector failures;
+ parser.parseDisjunction(failures);
+ if (parser.isEndOfPattern()) {
+ parser.m_err = WRECParser::Error_malformedPattern;
+ }
+ if (parser.m_err) {
+ // TODO: better error messages
+ *error_ptr = "TODO: better error messages";
+ return 0;
+ }
+
+ // (2) Success:
+ // Set return value & pop registers from the stack.
+
+ jit.emitTestl_rr(WRECGenerator::OUTPUT_REG, WRECGenerator::OUTPUT_REG);
+ WRECGenerator::JmpSrc noOutput = jit.emitUnlinkedJe();
+
+ jit.emitMovl_rm(WRECGenerator::CURR_POS_REG, 4, WRECGenerator::OUTPUT_REG);
+ jit.emitPopl_r(MacroAssembler::eax);
+ jit.emitMovl_rm(MacroAssembler::eax, WRECGenerator::OUTPUT_REG);
+ jit.emitPopl_r(WRECGenerator::CURR_VAL_REG);
+ jit.emitPopl_r(WRECGenerator::OUTPUT_REG);
+ jit.emitRet();
+
+ jit.link(noOutput, jit.label());
+
+ jit.emitPopl_r(MacroAssembler::eax);
+ jit.emitMovl_rm(MacroAssembler::eax, WRECGenerator::OUTPUT_REG);
+ jit.emitPopl_r(WRECGenerator::CURR_VAL_REG);
+ jit.emitPopl_r(WRECGenerator::OUTPUT_REG);
+ jit.emitRet();
+
+ // (3) Failure:
+ // All fails link to here. Progress the start point & if it is within scope, loop.
+ // Otherwise, return fail value.
+ WRECGenerator::JmpDst here = jit.label();
+ for (unsigned i = 0; i < failures.size(); ++i)
+ jit.link(failures[i], here);
+ failures.clear();
+
+ jit.emitMovl_mr(MacroAssembler::esp, WRECGenerator::CURR_POS_REG);
+ jit.emitAddl_i8r(1, WRECGenerator::CURR_POS_REG);
+ jit.emitMovl_rm(WRECGenerator::CURR_POS_REG, MacroAssembler::esp);
+ jit.emitCmpl_rr(WRECGenerator::LENGTH_REG, WRECGenerator::CURR_POS_REG);
+ jit.link(jit.emitUnlinkedJle(), nextLabel);
+
+ jit.emitAddl_i8r(4, MacroAssembler::esp);
+
+ jit.emitMovl_i32r(-1, MacroAssembler::eax);
+ jit.emitPopl_r(WRECGenerator::CURR_VAL_REG);
+ jit.emitPopl_r(WRECGenerator::OUTPUT_REG);
+ jit.emitRet();
+
+ *numSubpatterns_ptr = parser.m_numSubpatterns;
+
+ void* code = jit.copy();
+ ASSERT(code);
+ return code;
+}
+
+} // namespace KJS
+
+#endif // ENABLE(CTI)
--- /dev/null
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 CTI_h
+#define CTI_h
+
+#if ENABLE(CTI)
+
+#include "Opcode.h"
+#include "Opcode.h"
+#include "RegisterFile.h"
+#include "RegisterFile.h"
+#include <masm/MacroAssembler.h>
+#include <profiler/Profiler.h>
+#include <wtf/AlwaysInline.h>
+#include <wtf/Vector.h>
+
+#if COMPILER(MSVC)
+#define CTI_ARGS void** args
+#define ARGS (args)
+#else
+#define CTI_ARGS void* args
+#define ARGS (&args)
+#endif
+
+#define CTI_ARGS_2ndResult 0x08
+
+#define CTI_ARGS_code 0x0C
+#define CTI_ARGS_exec 0x0D
+#define CTI_ARGS_registerFile 0x0E
+#define CTI_ARGS_r 0x0F
+#define CTI_ARGS_scopeChain 0x10
+#define CTI_ARGS_codeBlock 0x11
+#define CTI_ARGS_exception 0x12
+#define CTI_ARGS_profilerReference 0x13
+#define ARG_exec ((ExecState*)(ARGS)[CTI_ARGS_exec])
+#define ARG_registerFile ((RegisterFile*)(ARGS)[CTI_ARGS_registerFile])
+#define ARG_r ((Register*)(ARGS)[CTI_ARGS_r])
+#define ARG_scopeChain ((ScopeChainNode*)(ARGS)[CTI_ARGS_scopeChain])
+#define ARG_codeBlock ((CodeBlock*)(ARGS)[CTI_ARGS_codeBlock])
+#define ARG_exception ((JSValue**)(ARGS)[CTI_ARGS_exception])
+#define ARG_profilerReference ((Profiler**)(ARGS)[CTI_ARGS_profilerReference])
+
+#define ARG_setScopeChain(newScopeChain) (*(volatile ScopeChainNode**)&(ARGS)[CTI_ARGS_scopeChain] = newScopeChain)
+#define ARG_setCodeBlock(newCodeBlock) (*(volatile CodeBlock**)&(ARGS)[CTI_ARGS_codeBlock] = newCodeBlock)
+#define ARG_setR(newR) (*(volatile Register**)&(ARGS)[CTI_ARGS_r] = newR)
+#define ARG_set2ndResult(new2ndResult) (*(volatile JSValue**)&(ARGS)[CTI_ARGS_2ndResult] = new2ndResult)
+
+#define ARG_src1 ((JSValue*)((ARGS)[1]))
+#define ARG_src2 ((JSValue*)((ARGS)[2]))
+#define ARG_src3 ((JSValue*)((ARGS)[3]))
+#define ARG_src4 ((JSValue*)((ARGS)[4]))
+#define ARG_id1 ((Identifier*)((ARGS)[1]))
+#define ARG_id2 ((Identifier*)((ARGS)[2]))
+#define ARG_id3 ((Identifier*)((ARGS)[3]))
+#define ARG_id4 ((Identifier*)((ARGS)[4]))
+#define ARG_int1 ((int)((ARGS)[1]))
+#define ARG_int2 ((int)((ARGS)[2]))
+#define ARG_int3 ((int)((ARGS)[3]))
+#define ARG_int4 ((int)((ARGS)[4]))
+#define ARG_func1 ((FuncDeclNode*)((ARGS)[1]))
+#define ARG_funcexp1 ((FuncExprNode*)((ARGS)[1]))
+#define ARG_registers1 ((Register*)((ARGS)[1]))
+#define ARG_regexp1 ((RegExp*)((ARGS)[1]))
+#define ARG_pni1 ((JSPropertyNameIterator*)((ARGS)[1]))
+#define ARG_instr4 ((Instruction*)((ARGS)[4]))
+#define ARG_instr5 ((Instruction*)((ARGS)[5]))
+
+#define CTI_RETURN_ADDRESS ((ARGS)[-1])
+
+namespace KJS {
+
+ class CodeBlock;
+ class ExecState;
+ class JSPropertyNameIterator;
+ class JSValue;
+ class Machine;
+ class Register;
+ class RegisterFile;
+ class ScopeChainNode;
+ class SimpleJumpTable;
+ class StringJumpTable;
+ class StructureIDChain;
+ struct Instruction;
+
+ typedef JSValue* (*CTIHelper_j)(CTI_ARGS);
+ typedef JSPropertyNameIterator* (*CTIHelper_p)(CTI_ARGS);
+ typedef void (*CTIHelper_v)(CTI_ARGS);
+ typedef void* (*CTIHelper_s)(CTI_ARGS);
+ typedef int (*CTIHelper_b)(CTI_ARGS);
+
+ extern OpcodeID what;
+
+ struct CallRecord {
+ MacroAssembler::JmpSrc from;
+ void* to;
+ unsigned opcodeIndex;
+
+ CallRecord()
+ {
+ }
+
+ CallRecord(MacroAssembler::JmpSrc f, CTIHelper_j t, unsigned i)
+ : from(f)
+ , to((void*)t)
+ , opcodeIndex(i)
+ {
+ }
+
+ CallRecord(MacroAssembler::JmpSrc f, CTIHelper_p t, unsigned i)
+ : from(f)
+ , to((void*)t)
+ , opcodeIndex(i)
+ {
+ }
+
+ CallRecord(MacroAssembler::JmpSrc f, CTIHelper_v t, unsigned i)
+ : from(f)
+ , to((void*)t)
+ , opcodeIndex(i)
+ {
+ }
+
+ CallRecord(MacroAssembler::JmpSrc f, CTIHelper_s t, unsigned i)
+ : from(f)
+ , to((void*)t)
+ , opcodeIndex(i)
+ {
+ }
+
+ CallRecord(MacroAssembler::JmpSrc f, CTIHelper_b t, unsigned i)
+ : from(f)
+ , to((void*)t)
+ , opcodeIndex(i)
+ {
+ }
+ };
+
+ struct JmpTable {
+ MacroAssembler::JmpSrc from;
+ unsigned to;
+
+ JmpTable(MacroAssembler::JmpSrc f, unsigned t)
+ : from(f)
+ , to(t)
+ {
+ }
+ };
+
+ struct SlowCaseEntry {
+ MacroAssembler::JmpSrc from;
+ unsigned to;
+ unsigned hint;
+
+ SlowCaseEntry(MacroAssembler::JmpSrc f, unsigned t, unsigned h = 0)
+ : from(f)
+ , to(t)
+ , hint(h)
+ {
+ }
+ };
+
+ struct SwitchRecord {
+ enum Type {
+ Immediate,
+ Character,
+ String
+ };
+
+ Type m_type;
+
+ union {
+ SimpleJumpTable* m_simpleJumpTable;
+ StringJumpTable* m_stringJumpTable;
+ } m_jumpTable;
+
+ unsigned m_opcodeIndex;
+ unsigned m_defaultOffset;
+
+ SwitchRecord(SimpleJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset, Type type)
+ : m_type(type)
+ , m_opcodeIndex(opcodeIndex)
+ , m_defaultOffset(defaultOffset)
+ {
+ m_jumpTable.m_simpleJumpTable = jumpTable;
+ }
+
+ SwitchRecord(StringJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset)
+ : m_type(String)
+ , m_opcodeIndex(opcodeIndex)
+ , m_defaultOffset(defaultOffset)
+ {
+ m_jumpTable.m_stringJumpTable = jumpTable;
+ }
+ };
+
+ extern "C" {
+ JSValue* ctiTrampoline(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception, Profiler**);
+ void ctiVMThrowTrampoline();
+ };
+
+ void ctiSetReturnAddress(void** where, void* what);
+ void ctiRepatchCallByReturnAddress(void* where, void* what);
+
+ class CTI {
+ public:
+ static void compile(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
+ {
+ CTI cti(machine, exec, codeBlock);
+ cti.privateCompile();
+ }
+
+ static void* compileRegExp(ExecState* exec, const UString& pattern, unsigned* numSubpatterns_ptr, const char** error_ptr, bool ignoreCase = false, bool multiline = false);
+
+ static void* compileGetByIdSelf(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset)
+ {
+ CTI cti(machine, exec, codeBlock);
+ return cti.privateCompileGetByIdSelf(structureID, cachedOffset);
+ }
+
+ static void* compileGetByIdProto(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset)
+ {
+ CTI cti(machine, exec, codeBlock);
+ return cti.privateCompileGetByIdProto(structureID, prototypeStructureID, cachedOffset);
+ }
+
+ static void* compileGetByIdChain(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset)
+ {
+ CTI cti(machine, exec, codeBlock);
+ return cti.privateCompileGetByIdChain(structureID, chain, count, cachedOffset);
+ }
+
+ static void* compilePutByIdReplace(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset)
+ {
+ CTI cti(machine, exec, codeBlock);
+ return cti.privateCompilePutByIdReplace(structureID, cachedOffset);
+ }
+
+ static void* compileArrayLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
+ {
+ CTI cti(machine, exec, codeBlock);
+ return cti.privateArrayLengthTrampoline();
+ }
+
+ static void* compileStringLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
+ {
+ CTI cti(machine, exec, codeBlock);
+ return cti.privateStringLengthTrampoline();
+ }
+
+ inline static JSValue* execute(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
+ {
+ JSValue* value = ctiTrampoline(code, exec, registerFile, r, scopeChain, codeBlock, exception, Profiler::enabledProfilerReference());
+#if ENABLE(SAMPLING_TOOL)
+ what = static_cast<OpcodeID>(-1);
+#endif
+ return value;
+ }
+
+ private:
+ CTI(Machine*, ExecState*, CodeBlock*);
+ void privateCompileMainPass();
+ void privateCompileLinkPass();
+ void privateCompileSlowCases();
+ void privateCompile();
+ void* privateCompileGetByIdSelf(StructureID*, size_t cachedOffset);
+ void* privateCompileGetByIdProto(StructureID*, StructureID* prototypeStructureID, size_t cachedOffset);
+ void* privateCompileGetByIdChain(StructureID*, StructureIDChain*, size_t count, size_t cachedOffset);
+ void* privateCompilePutByIdReplace(StructureID*, size_t cachedOffset);
+ void* privateArrayLengthTrampoline();
+ void* privateStringLengthTrampoline();
+
+ enum CompileOpCallType { OpCallNormal, OpCallEval, OpConstruct };
+ void compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType type = OpCallNormal);
+
+ void emitGetArg(unsigned src, MacroAssembler::RegisterID dst);
+ void emitGetPutArg(unsigned src, unsigned offset, MacroAssembler::RegisterID scratch);
+ void emitPutArg(MacroAssembler::RegisterID src, unsigned offset);
+ void emitPutArgConstant(unsigned value, unsigned offset);
+ void emitPutResult(unsigned dst, MacroAssembler::RegisterID from = MacroAssembler::eax);
+
+ void emitPutCTIParam(MacroAssembler::RegisterID from, unsigned name);
+ void emitGetCTIParam(unsigned name, MacroAssembler::RegisterID to);
+
+ void emitPutToCallFrameHeader(MacroAssembler::RegisterID from, RegisterFile::CallFrameHeaderEntry entry);
+ void emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, MacroAssembler::RegisterID to);
+
+ JSValue* getConstantImmediateNumericArg(unsigned src);
+ unsigned getDeTaggedConstantImmediate(JSValue* imm);
+
+ void emitJumpSlowCaseIfNotImm(MacroAssembler::RegisterID, unsigned opcodeIndex);
+ void emitJumpSlowCaseIfNotImms(MacroAssembler::RegisterID, MacroAssembler::RegisterID, unsigned opcodeIndex);
+
+ void emitFastArithDeTagImmediate(MacroAssembler::RegisterID);
+ void emitFastArithReTagImmediate(MacroAssembler::RegisterID);
+ void emitFastArithPotentiallyReTagImmediate(MacroAssembler::RegisterID);
+ void emitFastArithImmToInt(MacroAssembler::RegisterID);
+ void emitFastArithIntToImmOrSlowCase(MacroAssembler::RegisterID, unsigned opcodeIndex);
+ void emitFastArithIntToImmNoCheck(MacroAssembler::RegisterID);
+
+ void emitDebugExceptionCheck();
+
+ void emitCall(unsigned opcodeIndex, CTIHelper_j);
+ void emitCall(unsigned opcodeIndex, CTIHelper_p);
+ void emitCall(unsigned opcodeIndex, CTIHelper_b);
+ void emitCall(unsigned opcodeIndex, CTIHelper_v);
+ void emitCall(unsigned opcodeIndex, CTIHelper_s);
+
+#ifndef NDEBUG
+ void printOpcodeOperandTypes(unsigned src1, unsigned src2);
+#endif
+
+ MacroAssembler m_jit;
+ Machine* m_machine;
+ ExecState* m_exec;
+ CodeBlock* m_codeBlock;
+
+ Vector<CallRecord> m_calls;
+ Vector<MacroAssembler::JmpDst> m_labels;
+ Vector<JmpTable> m_jmpTable;
+
+ struct JSRInfo {
+ MacroAssembler::JmpDst addrPosition;
+ MacroAssembler::JmpDst target;
+
+ JSRInfo(const MacroAssembler::JmpDst& storeLocation, const MacroAssembler::JmpDst& targetLocation)
+ : addrPosition(storeLocation)
+ , target(targetLocation)
+ {
+ }
+ };
+
+ Vector<JSRInfo> m_jsrSites;
+ Vector<SlowCaseEntry> m_slowCases;
+ Vector<SwitchRecord> m_switches;
+
+ // This limit comes from the limit set in PCRE
+ static const int MaxPatternSize = (1 << 16);
+
+ };
+}
+
+#endif // ENABLE(CTI)
+
+#endif // CTI_h
printf("\nStructureIDs:\n");
size_t i = 0;
do {
- printStructureIDs(&instructions[structureIDInstructions[i]]);
- ++i;
+ printStructureIDs(&instructions[structureIDInstructions[i]]);
+ ++i;
} while (i < structureIDInstructions.size());
}
-
+
if (exceptionHandlers.size()) {
printf("\nException Handlers:\n");
unsigned i = 0;
ASSERT(!((i + characterSwitchJumpTables[i].min) & ~0xFFFF));
UChar ch = static_cast<UChar>(entry + characterSwitchJumpTables[i].min);
printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).ascii(), *iter);
- }
+ }
printf(" }\n");
++i;
} while (i < characterSwitchJumpTables.size());
unsigned i = 0;
do {
printf(" %1d = {\n", i);
- StringJumpTable::const_iterator end = stringSwitchJumpTables[i].end();
- for (StringJumpTable::const_iterator iter = stringSwitchJumpTables[i].begin(); iter != end; ++iter)
- printf("\t\t\"%s\" => %04d\n", UString(iter->first).ascii(), iter->second);
+ StringJumpTable::StringOffsetTable::const_iterator end = stringSwitchJumpTables[i].offsetTable.end();
+ for (StringJumpTable::StringOffsetTable::const_iterator iter = stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
+ printf("\t\t\"%s\" => %04d\n", UString(iter->first).ascii(), iter->second.branchOffset);
printf(" }\n");
++i;
} while (i < stringSwitchJumpTables.size());
size_t size = structureIDInstructions.size();
for (size_t i = 0; i < size; ++i)
derefStructureIDs(&instructions[structureIDInstructions[i]]);
+
+ size = structureIDAccessStubs.size();
+ for (size_t i = 0; i < size; ++i)
+ fastFree(structureIDAccessStubs[i]);
+
+#if ENABLE(CTI)
+ if (ctiCode)
+ fastFree(ctiCode);
+#endif
}
void CodeBlock::derefStructureIDs(Instruction* vPC) const
return false;
}
+void* CodeBlock::nativeExceptionCodeForHandlerVPC(const Instruction* handlerVPC)
+{
+ Vector<HandlerInfo>::iterator ptr = exceptionHandlers.begin();
+ Vector<HandlerInfo>::iterator end = exceptionHandlers.end();
+
+ for (; ptr != end; ++ptr) {
+ Instruction*target = instructions.begin() + ptr->target;
+ if (handlerVPC == target)
+ return ptr->nativeCode;
+ }
+
+ return 0;
+}
+
int CodeBlock::lineNumberForVPC(const Instruction* vPC)
{
ASSERT(lineInfo.size());
uint32_t end;
uint32_t target;
uint32_t scopeDepth;
+ void* nativeCode;
};
struct ExpressionRangeInfo {
- enum { MaxOffset = (1 << 7) - 1,
- MaxDivot = (1 << 25) - 1
+ enum {
+ MaxOffset = (1 << 7) - 1,
+ MaxDivot = (1 << 25) - 1
};
uint32_t instructionOffset : 25;
uint32_t divotPoint : 25;
int32_t lineNumber;
};
- typedef HashMap<RefPtr<UString::Rep>, int32_t> StringJumpTable;
+ struct OffsetLocation {
+ int32_t branchOffset;
+#if ENABLE(CTI)
+ void* ctiOffset;
+#endif
+ };
+
+ struct StringJumpTable {
+ typedef HashMap<RefPtr<UString::Rep>, OffsetLocation> StringOffsetTable;
+ StringOffsetTable offsetTable;
+#if ENABLE(CTI)
+ void* ctiDefault; // FIXME: it should not be necessary to store this.
+#endif
+
+ inline int32_t offsetForValue(UString::Rep* value, int32_t defaultOffset)
+ {
+ StringOffsetTable::const_iterator end = offsetTable.end();
+ StringOffsetTable::const_iterator loc = offsetTable.find(value);
+ if (loc == end)
+ return defaultOffset;
+ return loc->second.branchOffset;
+ }
+
+#if ENABLE(CTI)
+ inline void* ctiForValue(UString::Rep* value)
+ {
+ StringOffsetTable::const_iterator end = offsetTable.end();
+ StringOffsetTable::const_iterator loc = offsetTable.find(value);
+ if (loc == end)
+ return ctiDefault;
+ return loc->second.ctiOffset;
+ }
+#endif
+ };
+
struct SimpleJumpTable {
+ // FIXME: The two Vectors can be combind into one Vector<OffsetLocation>
Vector<int32_t> branchOffsets;
int32_t min;
+#if ENABLE(CTI)
+ Vector<void*> ctiOffsets;
+ void* ctiDefault;
+#endif
+
int32_t offsetForValue(int32_t value, int32_t defaultOffset);
- void add(int32_t key, int32_t offset) {
+ void add(int32_t key, int32_t offset)
+ {
if (!branchOffsets[key])
branchOffsets[key] = offset;
}
+
+#if ENABLE(CTI)
+ inline void* ctiForValue(int32_t value)
+ {
+ if (value >= min && static_cast<uint32_t>(value - min) < ctiOffsets.size())
+ return ctiOffsets[value - min];
+ return ctiDefault;
+ }
+#endif
};
struct CodeBlock {
CodeBlock(ScopeNode* ownerNode_, CodeType codeType_, PassRefPtr<SourceProvider> source_, unsigned sourceOffset_)
: ownerNode(ownerNode_)
, globalData(0)
+#if ENABLE(CTI)
+ , ctiCode(0)
+#endif
, numTemporaries(0)
, numVars(0)
, numParameters(0)
, sourceOffset(sourceOffset_)
{
}
-
+
~CodeBlock();
-#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
+#if !defined(NDEBUG) || ENABLE_SAMPLING_TOOL
void dump(ExecState*) const;
void printStructureIDs(const Instruction*) const;
void printStructureID(const char* name, const Instruction*, int operand) const;
int expressionRangeForVPC(const Instruction*, int& divot, int& startOffset, int& endOffset);
int lineNumberForVPC(const Instruction* vPC);
bool getHandlerForVPC(const Instruction* vPC, Instruction*& target, int& scopeDepth);
+ void* nativeExceptionCodeForHandlerVPC(const Instruction* handlerVPC);
void mark();
void refStructureIDs(Instruction* vPC) const;
ScopeNode* ownerNode;
JSGlobalData* globalData;
+#if ENABLE(CTI)
+ void* ctiCode;
+#endif
int numConstants;
int numTemporaries;
Vector<Instruction> instructions;
Vector<size_t> structureIDInstructions;
+ Vector<void*> structureIDAccessStubs;
// Constant pool
Vector<Identifier> identifiers;
Vector<SimpleJumpTable> immediateSwitchJumpTables;
Vector<SimpleJumpTable> characterSwitchJumpTables;
Vector<StringJumpTable> stringSwitchJumpTables;
+
+ HashSet<unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > labels;
+
+#if ENABLE(CTI)
+ HashMap<void*, unsigned> ctiReturnAddressVPCMap;
+#endif
private:
#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
RegisterID* CodeGenerator::emitCatch(RegisterID* targetRegister, LabelID* start, LabelID* end)
{
- HandlerInfo info = { start->offsetFrom(0), end->offsetFrom(0), instructions().size(), m_dynamicScopeDepth };
+ HandlerInfo info = { start->offsetFrom(0), end->offsetFrom(0), instructions().size(), m_dynamicScopeDepth, 0 };
exceptionHandlers().append(info);
emitOpcode(op_catch);
instructions().append(targetRegister->index());
ASSERT(nodes[i]->isString());
UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().rep();
- jumpTable.add(clause, labels[i]->offsetFrom(switchAddress));
+ OffsetLocation location;
+ location.branchOffset = labels[i]->offsetFrom(switchAddress);
+#if ENABLE(CTI)
+ location.ctiOffset = 0;
+#endif
+ jumpTable.offsetTable.add(clause, location);
}
}
unsigned j = m_unresolvedJumps[i];
m_codeBlock->instructions[j].u.operand = m_location - j;
}
+
+ m_codeBlock->labels.add(location);
}
int offsetFrom(int location) const
namespace KJS {
-// Default number of ticks before a timeout check should be done.
-static const int initialTickCountThreshold = 255;
-
// Preferred number of milliseconds between each timeout check
static const int preferredScriptCheckTimeInterval = 1000;
return false;
}
-static void NEVER_INLINE resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
+ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain)
{
- int dst = (vPC + 1)->u.operand;
- int property = (vPC + 2)->u.operand;
-
ScopeChainIterator iter = scopeChain->begin();
ScopeChainIterator next = iter;
++next;
ASSERT(iter != end);
PropertySlot slot;
- Identifier& ident = codeBlock->identifiers[property];
JSObject* base;
while (true) {
base = *iter;
- if (next == end || base->getPropertySlot(exec, ident, slot)) {
- r[dst] = base;
- return;
- }
+ if (next == end || base->getPropertySlot(exec, property, slot))
+ return base;
+
iter = next;
++next;
}
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+NEVER_INLINE static void resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
+{
+ int dst = (vPC + 1)->u.operand;
+ int property = (vPC + 2)->u.operand;
+ r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain);
}
static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
(*it) = jsUndefined();
-
for (size_t i = 0; i < newCodeBlock->constantRegisters.size(); ++i)
r[i] = newCodeBlock->constantRegisters[i];
Machine::Machine()
: m_sampler(0)
+#if ENABLE(CTI)
+ , m_ctiArrayLengthTrampoline(0)
+ , m_ctiStringLengthTrampoline(0)
+ , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
+#endif
, m_reentryDepth(0)
, m_timeoutTime(0)
, m_timeAtLastCheckTimeout(0)
JSString* jsString = new (storage) JSString("");
m_jsStringVptr = jsString->vptr();
static_cast<JSCell*>(jsString)->~JSCell();
+
+ JSFunction* jsFunction = new (storage) JSFunction(StructureID::create(jsNull()));
+ m_jsFunctionVptr = jsFunction->vptr();
+ static_cast<JSCell*>(jsFunction)->~JSCell();
fastFree(storage);
}
+Machine::~Machine()
+{
+#if ENABLE(CTI)
+ if (m_ctiArrayLengthTrampoline)
+ fastFree(m_ctiArrayLengthTrampoline);
+ if (m_ctiStringLengthTrampoline)
+ fastFree(m_ctiStringLengthTrampoline);
+#endif
+}
+
#ifndef NDEBUG
void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
#endif
-#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
+//#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
bool Machine::isOpcode(Opcode opcode)
{
#endif
}
-#endif
+//#endif
NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
{
NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
{
// Set up the exception object
-
+
if (exceptionValue->isObject()) {
JSObject* exception = static_cast<JSObject*>(exceptionValue);
if (exception->isNotAnObjectErrorStub()) {
(*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
m_reentryDepth++;
+#if ENABLE(CTI)
+ if (!codeBlock->ctiCode)
+ CTI::compile(this, exec, codeBlock);
+ JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
+#else
JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
+#endif
m_reentryDepth--;
MACHINE_SAMPLING_privateExecuteReturned();
(*profiler)->willExecute(exec, function);
m_reentryDepth++;
+#if ENABLE(CTI)
+ if (!newCodeBlock->ctiCode)
+ CTI::compile(this, exec, newCodeBlock);
+ JSValue* result = CTI::execute(newCodeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
+#else
JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
+#endif
m_reentryDepth--;
MACHINE_SAMPLING_privateExecuteReturned();
(*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
m_reentryDepth++;
+#if ENABLE(CTI)
+ if (!codeBlock->ctiCode)
+ CTI::compile(this, exec, codeBlock);
+ JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
+#else
JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
+#endif
m_reentryDepth--;
MACHINE_SAMPLING_privateExecuteReturned();
exec->m_scopeChain = newScopeChain;
}
-NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r)
+NEVER_INLINE void Machine::debug(ExecState* exec, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r, DebugHookID debugHookID, int firstLine, int lastLine)
{
- int debugHookID = (++vPC)->u.operand;
- int firstLine = (++vPC)->u.operand;
- int lastLine = (++vPC)->u.operand;
-
Debugger* debugger = exec->dynamicGlobalObject()->debugger();
if (!debugger)
return;
DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
- switch((DebugHookID)debugHookID) {
- case DidEnterCallFrame: {
- debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
- return;
- }
- case WillLeaveCallFrame: {
- debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
- return;
- }
- case WillExecuteStatement: {
- debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
- return;
- }
- case WillExecuteProgram: {
- debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
- return;
- }
- case DidExecuteProgram: {
- debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
- return;
- }
- case DidReachBreakpoint: {
- debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
- return;
- }
+ switch (debugHookID) {
+ case DidEnterCallFrame:
+ debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
+ return;
+ case WillLeaveCallFrame:
+ debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
+ return;
+ case WillExecuteStatement:
+ debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
+ return;
+ case WillExecuteProgram:
+ debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
+ return;
+ case DidExecuteProgram:
+ debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
+ return;
+ case DidReachBreakpoint:
+ debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
+ return;
}
}
return 0;
}
-static int32_t offsetForStringSwitch(StringJumpTable& jumpTable, JSValue* scrutinee, int32_t defaultOffset) {
- StringJumpTable::const_iterator end = jumpTable.end();
- UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
- StringJumpTable::const_iterator loc = jumpTable.find(value);
- if (loc == end)
- return defaultOffset;
- return loc->second;
-}
-
static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
{
int dst = (++vPC)->u.operand;
if (slot.slotBase() == structureID->prototype()) {
ASSERT(slot.slotBase()->isObject());
- JSObject* slotBaseObject = static_cast<JSObject*>(slot.slotBase());
+ JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
// Heavy access to a prototype is a good indication that it's not being
// used as a dictionary.
- if (slotBaseObject->structureID()->isDictionary()) {
- RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(slotBaseObject->structureID());
- slotBaseObject->setStructureID(transition.release());
+ if (baseObject->structureID()->isDictionary()) {
+ RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
+ baseObject->setStructureID(transition.release());
static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
}
vPC[0] = getOpcode(op_get_by_id_proto);
- vPC[5] = slotBaseObject->structureID();
+ vPC[5] = baseObject->structureID();
vPC[6] = slot.cachedOffset();
codeBlock->refStructureIDs(vPC);
while (slot.slotBase() != o) {
JSValue* v = o->structureID()->prototype();
- // If we didn't find slotBase in baseValue's prototype chain, then baseValue
+ // If we didn't find base in baseValue's prototype chain, then baseValue
// must be a proxy for another object.
if (v->isNull()) {
vPC[0] = getOpcode(op_get_by_id_generic);
return 0;
}
+#if ENABLE(CTI)
+ // Currently with CTI enabled we never interpret functions
+ ASSERT_NOT_REACHED();
+#endif
+
JSValue* exceptionValue = 0;
Instruction* handlerVPC = 0;
unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
#define VM_CHECK_EXCEPTION() \
- do { \
+ do { \
if (UNLIKELY(exec->hadException())) { \
exceptionValue = exec->exception(); \
goto vm_throw; \
goto vm_throw; \
tickCount = m_ticksUntilNextTimeoutCheck; \
}
-
+
#if HAVE(COMPUTED_GOTO)
#define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
#if DUMP_OPCODE_STATS
int dst = (++vPC)->u.operand;
int base = (++vPC)->u.operand;
int property = (++vPC)->u.operand;
-
+
JSValue* baseValue = r[base].jsValue(exec);
JSValue* subscript = r[property].jsValue(exec);
if (!scrutinee->isString())
vPC += defaultOffset;
else
- vPC += offsetForStringSwitch(codeBlock->stringSwitchJumpTables[tableIndex], scrutinee, defaultOffset);
+ vPC += codeBlock->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset);
NEXT_OPCODE;
}
BEGIN_OPCODE(op_new_func) {
Notifies the debugger of the current state of execution. This opcode
is only generated while the debugger is attached.
*/
+ int debugHookID = (++vPC)->u.operand;
+ int firstLine = (++vPC)->u.operand;
+ int lastLine = (++vPC)->u.operand;
- debug(exec, vPC, codeBlock, scopeChain, r);
+ debug(exec, codeBlock, scopeChain, r, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
- vPC += 4;
+ ++vPC;
NEXT_OPCODE;
}
vm_throw: {
#undef NEXT_OPCODE
#undef BEGIN_OPCODE
#undef VM_CHECK_EXCEPTION
+ #undef CHECK_FOR_TIMEOUT
}
JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
argc = callFrame[RegisterFile::ArgumentCount].i() - 1; // - 1 to skip "this"
}
+#if ENABLE(CTI)
+
+NEVER_INLINE static void doSetReturnAddressVMThrowTrampoline(void** returnAddress)
+{
+ ctiSetReturnAddress(returnAddress, (void*)ctiVMThrowTrampoline);
+}
+
+NEVER_INLINE void Machine::tryCTICachePutByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const PutPropertySlot& slot)
+{
+ // The interpreter checks for recursion here; I do not believe this can occur in CTI.
+
+ if (JSImmediate::isImmediate(baseValue))
+ return;
+
+ // Uncacheable: give up.
+ if (!slot.isCacheable()) {
+ ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
+ return;
+ }
+
+ // FIXME: Cache new property transitions, too.
+ if (slot.type() == PutPropertySlot::NewProperty) {
+ ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
+ return;
+ }
+
+ JSCell* baseCell = static_cast<JSCell*>(baseValue);
+ StructureID* structureID = baseCell->structureID();
+
+ // FIXME: Remove this !structureID check once all objects have StructureIDs.
+ if (!structureID) {
+ ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
+ return;
+ }
+
+ if (structureID->isDictionary()) {
+ ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
+ return;
+ }
+
+ // In the interpreter the last structure is trapped here; in CTI we use the
+ // *_second method to achieve a similar (but not quite the same) effect.
+
+ unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress);
+ Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
+
+ // Cache hit: Specialize instruction and ref StructureIDs.
+
+ // If baseCell != base, then baseCell must be a proxy for another object.
+ if (baseCell != slot.base()) {
+ ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
+ return;
+ }
+ vPC[0] = getOpcode(op_put_by_id_replace);
+ vPC[4] = structureID;
+ vPC[5] = slot.cachedOffset();
+ codeBlock->refStructureIDs(vPC);
+
+ ctiRepatchCallByReturnAddress(returnAddress, CTI::compilePutByIdReplace(this, exec, codeBlock, structureID, slot.cachedOffset()));
+}
+
+void* Machine::getCTIArrayLengthTrampoline(ExecState* exec, CodeBlock* codeBlock)
+{
+ if (!m_ctiArrayLengthTrampoline)
+ m_ctiArrayLengthTrampoline = CTI::compileArrayLengthTrampoline(this, exec, codeBlock);
+
+ return m_ctiArrayLengthTrampoline;
+}
+
+void* Machine::getCTIStringLengthTrampoline(ExecState* exec, CodeBlock* codeBlock)
+{
+ if (!m_ctiStringLengthTrampoline)
+ m_ctiStringLengthTrampoline = CTI::compileStringLengthTrampoline(this, exec, codeBlock);
+
+ return m_ctiStringLengthTrampoline;
+}
+
+NEVER_INLINE void Machine::tryCTICacheGetByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
+{
+ // The interpreter checks for recursion here; I do not believe this can occur in CTI.
+
+ if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
+ ctiRepatchCallByReturnAddress(returnAddress, getCTIArrayLengthTrampoline(exec, codeBlock));
+ return;
+ }
+ if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
+ ctiRepatchCallByReturnAddress(returnAddress, getCTIStringLengthTrampoline(exec, codeBlock));
+ return;
+ }
+
+ // Uncacheable: give up.
+ if (!slot.isCacheable()) {
+ ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
+ return;
+ }
+
+ // FIXME: Cache property access for immediates.
+ if (JSImmediate::isImmediate(baseValue)) {
+ ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
+ return;
+ }
+
+ JSCell* baseCell = static_cast<JSCell*>(baseValue);
+ StructureID* structureID = baseCell->structureID();
+
+ // FIXME: Remove this !structureID check once all JSCells have StructureIDs.
+ if (!structureID) {
+ ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
+ return;
+ }
+
+ if (structureID->isDictionary()) {
+ ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
+ return;
+ }
+
+ // In the interpreter the last structure is trapped here; in CTI we use the
+ // *_second method to achieve a similar (but not quite the same) effect.
+
+ unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress);
+ Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
+
+ // Cache hit: Specialize instruction and ref StructureIDs.
+
+ if (slot.slotBase() == baseValue) {
+ // set this up, so derefStructureIDs can do it's job.
+ vPC[0] = getOpcode(op_get_by_id_self);
+ vPC[4] = structureID;
+ vPC[5] = slot.cachedOffset();
+ codeBlock->refStructureIDs(vPC);
+
+ ctiRepatchCallByReturnAddress(returnAddress, CTI::compileGetByIdSelf(this, exec, codeBlock, structureID, slot.cachedOffset()));
+ return;
+ }
+
+ if (slot.slotBase() == structureID->prototype()) {
+ ASSERT(slot.slotBase()->isObject());
+
+ JSObject* slotBaseObject = static_cast<JSObject*>(slot.slotBase());
+
+ // Heavy access to a prototype is a good indication that it's not being
+ // used as a dictionary.
+ if (slotBaseObject->structureID()->isDictionary()) {
+ RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(slotBaseObject->structureID());
+ slotBaseObject->setStructureID(transition.release());
+ static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
+ }
+
+ vPC[0] = getOpcode(op_get_by_id_proto);
+ vPC[4] = structureID;
+ vPC[5] = slotBaseObject->structureID();
+ vPC[6] = slot.cachedOffset();
+ codeBlock->refStructureIDs(vPC);
+
+ ctiRepatchCallByReturnAddress(returnAddress, CTI::compileGetByIdProto(this, exec, codeBlock, structureID, slotBaseObject->structureID(), slot.cachedOffset()));
+ return;
+ }
+
+ size_t count = 0;
+ JSObject* o = static_cast<JSObject*>(baseValue);
+ while (slot.slotBase() != o) {
+ JSValue* v = o->structureID()->prototype();
+
+ // If we didn't find slotBase in baseValue's prototype chain, then baseValue
+ // must be a proxy for another object.
+
+ if (v->isNull()) {
+ vPC[0] = getOpcode(op_get_by_id_generic);
+ return;
+ }
+
+ o = static_cast<JSObject*>(v);
+
+ // Heavy access to a prototype is a good indication that it's not being
+ // used as a dictionary.
+ if (o->structureID()->isDictionary()) {
+ RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
+ o->setStructureID(transition.release());
+ static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
+ }
+
+ ++count;
+ }
+
+ StructureIDChain* chain = structureID->cachedPrototypeChain();
+ if (!chain)
+ chain = cachePrototypeChain(structureID);
+
+ vPC[0] = getOpcode(op_get_by_id_chain);
+ vPC[4] = structureID;
+ vPC[5] = chain;
+ vPC[6] = count;
+ vPC[7] = slot.cachedOffset();
+ codeBlock->refStructureIDs(vPC);
+
+ ctiRepatchCallByReturnAddress(returnAddress, CTI::compileGetByIdChain(this, exec, codeBlock, structureID, chain, count, slot.cachedOffset()));
+}
+
+
+#define JSVALUE_VM_CHECK_EXCEPTION_ARG(exception) \
+ do { \
+ if (UNLIKELY(exception != 0)) { \
+ exec->setException(exception); \
+ exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
+ doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
+ return 0; \
+ } \
+ } while (0)
+#define VM_CHECK_EXCEPTION_v() \
+ do { \
+ if (UNLIKELY(exec->hadException())) { \
+ exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
+ doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
+ return; \
+ } \
+ } while (0)
+#define VM_CHECK_EXCEPTION(type) \
+ do { \
+ if (UNLIKELY(exec->hadException())) { \
+ exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
+ doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
+ return (type)0; \
+ } \
+ } while (0)
+#define VM_CHECK_EXCEPTION_AT_END() \
+ do { \
+ if (UNLIKELY(exec->hadException())) { \
+ /*printf("VM_CHECK_EXCEPTION_AT_END()\n");*/ \
+ exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
+ doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
+ } \
+ } while (0)
+
+void Machine::cti_op_end(CTI_ARGS)
+{
+ ASSERT(ARG_scopeChain->refCount > 1);
+ ARG_scopeChain->deref();
+}
+
+JSValue* Machine::cti_op_add(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+
+ ExecState* exec = ARG_exec;
+ JSValue* result = jsAdd(exec, src1, src2);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_pre_inc(CTI_ARGS)
+{
+ JSValue* v = ARG_src1;
+
+ ExecState* exec = ARG_exec;
+ JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+void Machine::cti_timeout_check(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+
+ if (exec->machine()->checkTimeout(exec->dynamicGlobalObject()))
+ exec->setException(createInterruptedExecutionException(exec));
+
+ VM_CHECK_EXCEPTION_AT_END();
+}
+
+
+int Machine::cti_op_loop_if_less(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+ ExecState* exec = ARG_exec;
+
+ bool result = jsLess(exec, src1, src2);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_new_object(CTI_ARGS)
+{
+ return constructEmptyObject(ARG_exec);;
+}
+
+void Machine::cti_op_put_by_id(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Identifier& ident = *ARG_id2;
+
+ PutPropertySlot slot;
+ ARG_src1->put(exec, ident, ARG_src3, slot);
+
+ ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_put_by_id_second);
+
+ VM_CHECK_EXCEPTION_AT_END();
+}
+
+void Machine::cti_op_put_by_id_second(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Identifier& ident = *ARG_id2;
+
+ JSValue* baseValue = ARG_src1;
+ PutPropertySlot slot;
+ baseValue->put(exec, ident, ARG_src3, slot);
+
+ exec->machine()->tryCTICachePutByID(exec, ARG_codeBlock, CTI_RETURN_ADDRESS, baseValue, slot);
+
+ VM_CHECK_EXCEPTION_AT_END();
+}
+
+void Machine::cti_op_put_by_id_generic(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Identifier& ident = *ARG_id2;
+
+ PutPropertySlot slot;
+ ARG_src1->put(exec, ident, ARG_src3, slot);
+
+ VM_CHECK_EXCEPTION_AT_END();
+}
+
+void Machine::cti_op_put_by_id_fail(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Identifier& ident = *ARG_id2;
+
+ PutPropertySlot slot;
+ ARG_src1->put(exec, ident, ARG_src3, slot);
+
+ // should probably uncachePutByID() ... this would mean doing a vPC lookup - might be worth just bleeding this until the end.
+ ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_put_by_id_generic);
+
+ VM_CHECK_EXCEPTION_AT_END();
+}
+
+JSValue* Machine::cti_op_get_by_id(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Identifier& ident = *ARG_id2;
+
+ JSValue* baseValue = ARG_src1;
+ PropertySlot slot(baseValue);
+ JSValue* result = baseValue->get(exec, ident, slot);
+
+ ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_get_by_id_second);
+
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_get_by_id_second(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Identifier& ident = *ARG_id2;
+
+ JSValue* baseValue = ARG_src1;
+ PropertySlot slot(baseValue);
+ JSValue* result = baseValue->get(exec, ident, slot);
+
+ exec->machine()->tryCTICacheGetByID(exec, ARG_codeBlock, CTI_RETURN_ADDRESS, baseValue, ident, slot);
+
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_get_by_id_generic(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Identifier& ident = *ARG_id2;
+
+ JSValue* baseValue = ARG_src1;
+ PropertySlot slot(baseValue);
+ JSValue* result = baseValue->get(exec, ident, slot);
+
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_get_by_id_fail(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Identifier& ident = *ARG_id2;
+
+ JSValue* baseValue = ARG_src1;
+ PropertySlot slot(baseValue);
+ JSValue* result = baseValue->get(exec, ident, slot);
+
+ // should probably uncacheGetByID() ... this would mean doing a vPC lookup - might be worth just bleeding this until the end.
+ ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_get_by_id_generic);
+
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_instanceof(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ JSValue* baseVal = ARG_src2;
+
+ if (!baseVal->isObject()) {
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
+ unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
+ exec->setException(createInvalidParamError(exec, "instanceof", baseVal, codeBlock->instructions.begin() + vPCIndex, codeBlock));
+ VM_CHECK_EXCEPTION(JSValue*);
+ }
+
+ JSObject* baseObj = static_cast<JSObject*>(baseVal);
+ JSValue* result = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, ARG_src1) : false);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_del_by_id(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Identifier& ident = *ARG_id2;
+
+ JSObject* baseObj = ARG_src1->toObject(exec);
+
+ JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_mul(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+
+ double left;
+ double right;
+ if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
+ return jsNumber(exec, left * right);
+ else {
+ JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+JSValue* Machine::cti_op_new_func(CTI_ARGS)
+{
+ return ARG_func1->makeFunction(ARG_exec, ARG_scopeChain);
+}
+
+void* Machine::cti_op_call_JSFunction(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ RegisterFile* registerFile = ARG_registerFile;
+ Register* r = ARG_r;
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+
+ Machine* machine = exec->machine();
+ JSValue* exceptionValue = 0;
+ Register* registerBase = registerFile->base();
+
+ JSValue* funcVal = ARG_src1;
+ JSValue* thisValue = ARG_src2;
+ int firstArg = ARG_int3;
+ int argCount = ARG_int4;
+
+ CallData callData;
+#ifndef NDEBUG
+ CallType callType =
+#endif
+ funcVal->getCallData(callData);
+
+ ASSERT(callType == CallTypeJS);
+
+ if (*ARG_profilerReference)
+ (*ARG_profilerReference)->willExecute(exec, static_cast<JSObject*>(funcVal));
+
+ ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
+ FunctionBodyNode* functionBodyNode = callData.js.functionBody;
+ CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
+
+ r[firstArg] = thisValue;
+
+ Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
+ machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, 0, funcVal);
+ exec->m_callFrame = callFrame;
+
+ r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
+ JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue);
+
+ codeBlock = newCodeBlock;
+ machine->setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
+
+ if (!codeBlock->ctiCode)
+ CTI::compile(machine, exec, codeBlock);
+
+ ARG_setScopeChain(scopeChain);
+ ARG_setCodeBlock(codeBlock);
+ ARG_setR(r);
+ return codeBlock->ctiCode;
+}
+
+JSValue* Machine::cti_op_call_NotJSFunction(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Register* r = ARG_r;
+
+ JSValue* funcVal = ARG_src1;
+ JSValue* thisValue = ARG_src2;
+ int firstArg = ARG_int3;
+ int argCount = ARG_int4;
+
+ CallData callData;
+ CallType callType = funcVal->getCallData(callData);
+
+ ASSERT(callType != CallTypeJS);
+
+ if (callType == CallTypeHost) {
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+ Machine* machine = exec->machine();
+
+ Register* oldCallFrame = exec->m_callFrame;
+ Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
+ machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, 0, funcVal);
+ exec->m_callFrame = callFrame;
+
+ if (*ARG_profilerReference)
+ (*ARG_profilerReference)->willExecute(exec, static_cast<JSObject*>(funcVal));
+
+ ArgList argList(r + firstArg + 1, argCount - 1);
+
+ CTI_MACHINE_SAMPLING_callingHostFunction();
+
+ JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(funcVal), thisValue, argList);
+ exec->m_callFrame = oldCallFrame;
+ VM_CHECK_EXCEPTION(JSValue*);
+
+ if (*ARG_profilerReference)
+ (*ARG_profilerReference)->didExecute(exec, static_cast<JSObject*>(funcVal));
+
+ return returnValue;
+
+ }
+
+ ASSERT(callType == CallTypeNone);
+
+ exec->setException(createNotAFunctionError(exec, funcVal, ARG_instr5, ARG_codeBlock));
+ VM_CHECK_EXCEPTION_AT_END();
+ return 0;
+}
+
+JSValue* Machine::cti_op_ret(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Register* r = ARG_r;
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+
+ Machine* machine = exec->machine();
+
+ Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
+ if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
+ ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
+ ASSERT(activation->isActivationObject());
+ activation->copyRegisters();
+ }
+
+ if (*ARG_profilerReference)
+ (*ARG_profilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
+
+ if (codeBlock->needsFullScopeChain)
+ scopeChain->deref();
+
+ JSValue* returnValue = ARG_src1;
+ if (callFrame[RegisterFile::CalledAsConstructor].i() && !returnValue->isObject()) {
+ JSValue* thisObject = callFrame[RegisterFile::CallFrameHeaderSize].jsValue(exec);
+ returnValue = thisObject;
+ }
+
+ codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
+ if (codeBlock) {
+ machine->setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
+ r = callFrame[RegisterFile::CallerRegisters].r();
+ exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
+ }
+
+ ARG_setScopeChain(scopeChain);
+ ARG_setCodeBlock(codeBlock);
+ ARG_setR(r);
+
+ return returnValue;
+}
+
+JSValue* Machine::cti_op_new_array(CTI_ARGS)
+{
+ ArgList argsList(ARG_registers1, ARG_int2);
+ return constructArray(ARG_exec, argsList);
+}
+
+JSValue* Machine::cti_op_resolve(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+
+ ScopeChainIterator iter = scopeChain->begin();
+ ScopeChainIterator end = scopeChain->end();
+ ASSERT(iter != end);
+
+ Identifier& ident = *ARG_id1;
+ do {
+ JSObject* o = *iter;
+ PropertySlot slot(o);
+ if (o->getPropertySlot(exec, ident, slot)) {
+ JSValue* result = slot.getValue(exec, ident);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+ } while (++iter != end);
+
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
+ unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
+ exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock));
+
+ VM_CHECK_EXCEPTION_AT_END();
+ return 0;
+}
+
+void* Machine::cti_op_construct_JSConstruct(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ RegisterFile* registerFile = ARG_registerFile;
+ Register* r = ARG_r;
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+
+ Machine* machine = exec->machine();
+ JSValue* exceptionValue = 0;
+ Register* registerBase = registerFile->base();
+
+ JSValue* constrVal = ARG_src1;
+ int firstArg = ARG_int2;
+ int argCount = ARG_int3;
+
+ ConstructData constructData;
+#ifndef NDEBUG
+ ConstructType constructType =
+#endif
+ constrVal->getConstructData(constructData);
+
+ // Removing this line of code causes a measurable regression on squirrelfish.
+ JSObject* constructor = static_cast<JSObject*>(constrVal);
+
+ ASSERT(constructType == ConstructTypeJS);
+
+ if (*ARG_profilerReference)
+ (*ARG_profilerReference)->willExecute(exec, constructor);
+
+ JSObject* prototype;
+ JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
+ if (p->isObject())
+ prototype = static_cast<JSObject*>(p);
+ else
+ prototype = scopeChain->globalObject()->objectPrototype();
+ JSObject* newObject = new (exec) JSObject(prototype);
+
+ ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
+ FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
+ CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
+
+ r[firstArg] = newObject; // "this" value
+
+ Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
+ machine->initializeCallFrame(callFrame, codeBlock, ARG_instr4, scopeChain, r, 0/*dst*/, firstArg, argCount, 1, constructor);
+ exec->m_callFrame = callFrame;
+
+ r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
+ JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue);
+
+ codeBlock = newCodeBlock;
+ machine->setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
+
+ if (!codeBlock->ctiCode)
+ CTI::compile(machine, exec, codeBlock);
+
+ ARG_setScopeChain(scopeChain);
+ ARG_setCodeBlock(codeBlock);
+ ARG_setR(r);
+ return codeBlock->ctiCode;
+}
+
+JSValue* Machine::cti_op_construct_NotJSConstruct(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Register* r = ARG_r;
+
+ JSValue* constrVal = ARG_src1;
+ int firstArg = ARG_int2;
+ int argCount = ARG_int3;
+
+ ConstructData constructData;
+ ConstructType constructType = constrVal->getConstructData(constructData);
+
+ // Removing this line of code causes a measurable regression on squirrelfish.
+ JSObject* constructor = static_cast<JSObject*>(constrVal);
+
+ ASSERT(constructType != ConstructTypeJS);
+
+ if (constructType == ConstructTypeHost) {
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+ Machine* machine = exec->machine();
+
+ Register* oldCallFrame = exec->m_callFrame;
+ Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
+ machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, 1, constrVal);
+ exec->m_callFrame = callFrame;
+
+ if (*ARG_profilerReference)
+ (*ARG_profilerReference)->willExecute(exec, constructor);
+
+ ArgList argList(r + firstArg + 1, argCount - 1);
+
+ CTI_MACHINE_SAMPLING_callingHostFunction();
+
+ JSValue* returnValue = constructData.native.function(exec, constructor, argList);
+ exec->m_callFrame = oldCallFrame;
+ VM_CHECK_EXCEPTION(JSValue*);
+
+ if (*ARG_profilerReference)
+ (*ARG_profilerReference)->didExecute(exec, constructor);
+
+ return returnValue;
+ }
+
+ ASSERT(constructType == ConstructTypeNone);
+
+ exec->setException(createNotAConstructorError(exec, constrVal, ARG_instr4, ARG_codeBlock));
+ VM_CHECK_EXCEPTION_AT_END();
+ return 0;
+}
+
+JSValue* Machine::cti_op_get_by_val(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Machine* machine = exec->machine();
+
+ JSValue* baseValue = ARG_src1;
+ JSValue* subscript = ARG_src2;
+
+ JSValue* result;
+ unsigned i;
+
+ bool isUInt32 = JSImmediate::getUInt32(subscript, i);
+ if (LIKELY(isUInt32)) {
+ if (machine->isJSArray(baseValue)) {
+ JSArray* jsArray = static_cast<JSArray*>(baseValue);
+ if (jsArray->canGetIndex(i))
+ result = jsArray->getIndex(i);
+ else
+ result = jsArray->JSArray::get(exec, i);
+ } else if (machine->isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
+ result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
+ else
+ result = baseValue->get(exec, i);
+ } else {
+ Identifier property(exec, subscript->toString(exec));
+ result = baseValue->get(exec, property);
+ }
+
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_resolve_func(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+
+ ScopeChainIterator iter = scopeChain->begin();
+ ScopeChainIterator end = scopeChain->end();
+
+ // FIXME: add scopeDepthIsZero optimization
+
+ ASSERT(iter != end);
+
+ Identifier& ident = *ARG_id1;
+ JSObject* base;
+ do {
+ base = *iter;
+ PropertySlot slot(base);
+ if (base->getPropertySlot(exec, ident, slot)) {
+ // ECMA 11.2.3 says that if we hit an activation the this value should be null.
+ // However, section 10.2.3 says that in the case where the value provided
+ // by the caller is null, the global object should be used. It also says
+ // that the section does not apply to internal functions, but for simplicity
+ // of implementation we use the global object anyway here. This guarantees
+ // that in host objects you always get a valid object for this.
+ // We also handle wrapper substitution for the global object at the same time.
+ JSObject* thisObj = base->toThisObject(exec);
+ JSValue* result = slot.getValue(exec, ident);
+ VM_CHECK_EXCEPTION_AT_END();
+
+ ARG_set2ndResult(result);
+ return thisObj;
+ }
+ ++iter;
+ } while (iter != end);
+
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
+ unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
+ exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock));
+
+ VM_CHECK_EXCEPTION_AT_END();
+ return 0;
+}
+
+JSValue* Machine::cti_op_sub(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+
+ double left;
+ double right;
+ if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
+ return jsNumber(ARG_exec, left - right);
+ else {
+ ExecState* exec = ARG_exec;
+ JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+void Machine::cti_op_put_by_val(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ Machine* machine = exec->machine();
+
+ JSValue* baseValue = ARG_src1;
+ JSValue* subscript = ARG_src2;
+ JSValue* value = ARG_src3;
+
+ unsigned i;
+
+ bool isUInt32 = JSImmediate::getUInt32(subscript, i);
+ if (LIKELY(isUInt32)) {
+ if (machine->isJSArray(baseValue)) {
+ JSArray* jsArray = static_cast<JSArray*>(baseValue);
+ if (jsArray->canSetIndex(i))
+ jsArray->setIndex(i, value);
+ else
+ jsArray->JSArray::put(exec, i, value);
+ } else
+ baseValue->put(exec, i, value);
+ } else {
+ Identifier property(exec, subscript->toString(exec));
+ if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
+ PutPropertySlot slot;
+ baseValue->put(exec, property, value, slot);
+ }
+ }
+
+ VM_CHECK_EXCEPTION_AT_END();
+}
+
+JSValue* Machine::cti_op_lesseq(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ JSValue* result = jsBoolean(jsLessEq(exec, ARG_src1, ARG_src2));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+int Machine::cti_op_loop_if_true(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+
+ ExecState* exec = ARG_exec;
+
+ bool result = src1->toBoolean(exec);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_negate(CTI_ARGS)
+{
+ JSValue* src = ARG_src1;
+
+ ExecState* exec = ARG_exec;
+
+ double v;
+ if (fastIsNumber(src, v))
+ return jsNumber(exec, -v);
+ else {
+ JSValue* result = jsNumber(exec, -src->toNumber(exec));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+JSValue* Machine::cti_op_resolve_base(CTI_ARGS)
+{
+ return inlineResolveBase(ARG_exec, *ARG_id1, ARG_scopeChain);
+}
+
+JSValue* Machine::cti_op_resolve_skip(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+
+ int skip = ARG_int2;
+
+ ScopeChainIterator iter = scopeChain->begin();
+ ScopeChainIterator end = scopeChain->end();
+ ASSERT(iter != end);
+ while (skip--) {
+ ++iter;
+ ASSERT(iter != end);
+ }
+ Identifier& ident = *ARG_id1;
+ do {
+ JSObject* o = *iter;
+ PropertySlot slot(o);
+ if (o->getPropertySlot(exec, ident, slot)) {
+ JSValue* result = slot.getValue(exec, ident);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+ } while (++iter != end);
+
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
+ unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
+ exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock));
+
+ VM_CHECK_EXCEPTION_AT_END();
+ return 0;
+}
+
+JSValue* Machine::cti_op_div(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+
+ double left;
+ double right;
+ if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
+ return jsNumber(exec, left / right);
+ else {
+ JSValue* result = jsNumber(exec, src1->toNumber(exec) / src2->toNumber(exec));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+JSValue* Machine::cti_op_pre_dec(CTI_ARGS)
+{
+ JSValue* v = ARG_src1;
+
+ ExecState* exec = ARG_exec;
+ JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+int Machine::cti_op_jless(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+ ExecState* exec = ARG_exec;
+
+ bool result = jsLess(exec, src1, src2);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_not(CTI_ARGS)
+{
+ JSValue* src = ARG_src1;
+
+ ExecState* exec = ARG_exec;
+
+ JSValue* result = jsBoolean(!src->toBoolean(exec));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+int SFX_CALL Machine::cti_op_jtrue(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+
+ ExecState* exec = ARG_exec;
+
+ bool result = src1->toBoolean(exec);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_post_inc(CTI_ARGS)
+{
+ JSValue* v = ARG_src1;
+
+ ExecState* exec = ARG_exec;
+
+ JSValue* number = v->toJSNumber(exec);
+ VM_CHECK_EXCEPTION(JSValue*);
+ ARG_set2ndResult(jsNumber(exec, number->uncheckedGetNumber() + 1));
+ return number;
+}
+
+JSValue* Machine::cti_op_eq(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+
+ if (JSImmediate::areBothImmediateNumbers(src1, src2))
+ return jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
+ else {
+ ExecState* exec = ARG_exec;
+ JSValue* result = jsBoolean(equal(exec, src1, src2));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+JSValue* Machine::cti_op_lshift(CTI_ARGS)
+{
+ JSValue* val = ARG_src1;
+ JSValue* shift = ARG_src2;
+
+ ExecState* exec = ARG_exec;
+
+ int32_t left;
+ uint32_t right;
+ if (JSImmediate::areBothImmediateNumbers(val, shift))
+ return jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
+ else if (fastToInt32(val, left) && fastToUInt32(shift, right))
+ return jsNumber(exec, left << (right & 0x1f));
+ else {
+ JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+JSValue* Machine::cti_op_bitand(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+
+ ExecState* exec = ARG_exec;
+
+ int32_t left;
+ int32_t right;
+ if (fastToInt32(src1, left) && fastToInt32(src2, right))
+ return jsNumber(exec, left & right);
+ else {
+ JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+JSValue* Machine::cti_op_rshift(CTI_ARGS)
+{
+ JSValue* val = ARG_src1;
+ JSValue* shift = ARG_src2;
+
+ ExecState* exec = ARG_exec;
+
+ int32_t left;
+ uint32_t right;
+ if (JSImmediate::areBothImmediateNumbers(val, shift))
+ return JSImmediate::rightShiftImmediateNumbers(val, shift);
+ else if (fastToInt32(val, left) && fastToUInt32(shift, right))
+ return jsNumber(exec, left >> (right & 0x1f));
+ else {
+ JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+JSValue* Machine::cti_op_bitnot(CTI_ARGS)
+{
+ JSValue* src = ARG_src1;
+
+ ExecState* exec = ARG_exec;
+
+ int value;
+ if (fastToInt32(src, value))
+ return jsNumber(exec, ~value);
+
+ JSValue* result = jsNumber(exec, ~src->toInt32(exec));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_resolve_with_base(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+
+ ScopeChainIterator iter = scopeChain->begin();
+ ScopeChainIterator end = scopeChain->end();
+
+ // FIXME: add scopeDepthIsZero optimization
+
+ ASSERT(iter != end);
+
+ Identifier& ident = *ARG_id1;
+ JSObject* base;
+ do {
+ base = *iter;
+ PropertySlot slot(base);
+ if (base->getPropertySlot(exec, ident, slot)) {
+ JSValue* result = slot.getValue(exec, ident);
+ VM_CHECK_EXCEPTION_AT_END();
+ ARG_set2ndResult(result);
+ return base;
+ }
+ ++iter;
+ } while (iter != end);
+
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
+ unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
+ exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock));
+
+ VM_CHECK_EXCEPTION_AT_END();
+ return 0;
+}
+
+JSValue* Machine::cti_op_new_func_exp(CTI_ARGS)
+{
+ return ARG_funcexp1->makeFunction(ARG_exec, ARG_scopeChain);
+}
+
+JSValue* Machine::cti_op_mod(CTI_ARGS)
+{
+ JSValue* dividendValue = ARG_src1;
+ JSValue* divisorValue = ARG_src2;
+
+ ExecState* exec = ARG_exec;
+ double d = dividendValue->toNumber(exec);
+ JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_less(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ JSValue* result = jsBoolean(jsLess(exec, ARG_src1, ARG_src2));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_neq(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+
+ if (JSImmediate::areBothImmediateNumbers(src1, src2))
+ return jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
+ else {
+ ExecState* exec = ARG_exec;
+ JSValue* result = jsBoolean(!equal(exec, src1, src2));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+JSValue* Machine::cti_op_post_dec(CTI_ARGS)
+{
+ JSValue* v = ARG_src1;
+
+ ExecState* exec = ARG_exec;
+
+ JSValue* number = v->toJSNumber(exec);
+ VM_CHECK_EXCEPTION(JSValue*);
+
+ ARG_set2ndResult(jsNumber(exec, number->uncheckedGetNumber() - 1));
+ return number;
+}
+
+JSValue* Machine::cti_op_urshift(CTI_ARGS)
+{
+ JSValue* val = ARG_src1;
+ JSValue* shift = ARG_src2;
+
+ ExecState* exec = ARG_exec;
+
+ if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
+ return JSImmediate::rightShiftImmediateNumbers(val, shift);
+ else {
+ JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+JSValue* Machine::cti_op_bitxor(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+
+ ExecState* exec = ARG_exec;
+
+ JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_new_regexp(CTI_ARGS)
+{
+ return new (ARG_exec) RegExpObject(ARG_scopeChain->globalObject()->regExpPrototype(), ARG_regexp1);
+}
+
+JSValue* Machine::cti_op_bitor(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+
+ ExecState* exec = ARG_exec;
+
+ JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_call_eval(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ RegisterFile* registerFile = ARG_registerFile;
+ Register* r = ARG_r;
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+
+ Machine* machine = exec->machine();
+ JSValue* exceptionValue = 0;
+
+ JSValue* funcVal = ARG_src1;
+ JSValue* baseVal = ARG_src2;
+ int firstArg = ARG_int3;
+ int argCount = ARG_int4;
+
+ if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
+ JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
+ JSValue* result = machine->callEval(exec, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
+ JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue);
+ return result;
+ }
+
+ return JSImmediate::impossibleValue();
+}
+
+void* Machine::cti_op_throw(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+ Register* r = ARG_r;
+
+ ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
+ unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
+
+ JSValue* exceptionValue = ARG_src1;
+ Instruction* handlerVPC = ARG_exec->machine()->throwException(exec, exceptionValue, codeBlock->instructions.begin() + vPCIndex, codeBlock, scopeChain, r, true);
+
+ if (handlerVPC) {
+ exec->setException(exceptionValue);
+ ARG_setScopeChain(scopeChain);
+ ARG_setCodeBlock(codeBlock);
+ ARG_setR(r);
+
+ void* catchRoutine = codeBlock->nativeExceptionCodeForHandlerVPC(handlerVPC);
+ ASSERT(catchRoutine);
+ ctiSetReturnAddress(&CTI_RETURN_ADDRESS, catchRoutine);
+ return catchRoutine;
+ } else {
+ exec->clearException();
+ *ARG_exception = exceptionValue;
+ return JSImmediate::nullImmediate();
+ }
+}
+
+JSPropertyNameIterator* Machine::cti_op_get_pnames(CTI_ARGS)
+{
+ return JSPropertyNameIterator::create(ARG_exec, ARG_src1);
+}
+
+JSValue* Machine::cti_op_next_pname(CTI_ARGS)
+{
+ JSPropertyNameIterator* it = ARG_pni1;
+ JSValue* temp = it->next(ARG_exec);
+ if (!temp)
+ it->invalidate();
+ return temp;
+}
+
+void Machine::cti_op_push_scope(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+
+ JSValue* v = ARG_src1;
+ JSObject* o = v->toObject(exec);
+ VM_CHECK_EXCEPTION_v();
+
+ ScopeChainNode* newScopeChain = ARG_scopeChain->push(o);
+ ARG_setScopeChain(newScopeChain);
+ exec->m_scopeChain = newScopeChain;
+}
+
+void Machine::cti_op_pop_scope(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+
+ ScopeChainNode* newScopeChain = ARG_scopeChain->pop();
+ ARG_setScopeChain(newScopeChain);
+ exec->m_scopeChain = newScopeChain;
+}
+
+JSValue* Machine::cti_op_typeof(CTI_ARGS)
+{
+ return jsTypeStringForValue(ARG_exec, ARG_src1);
+}
+
+JSValue* Machine::cti_op_stricteq(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+
+ if (JSImmediate::areBothImmediateNumbers(src1, src2))
+ return jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
+ else {
+ ExecState* exec = ARG_exec;
+ JSValue* result = jsBoolean(strictEqual(src1, src2));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+JSValue* Machine::cti_op_nstricteq(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+
+ if (JSImmediate::areBothImmediateNumbers(src1, src2))
+ return jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
+ else {
+ ExecState* exec = ARG_exec;
+ JSValue* result = jsBoolean(!strictEqual(src1, src2));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+ }
+}
+
+JSValue* Machine::cti_op_to_jsnumber(CTI_ARGS)
+{
+ JSValue* src = ARG_src1;
+ ExecState* exec = ARG_exec;
+
+ JSValue* result = src->toJSNumber(exec);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+JSValue* Machine::cti_op_in(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ JSValue* baseVal = ARG_src2;
+
+ if (!baseVal->isObject()) {
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
+ unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
+ exec->setException(createInvalidParamError(exec, "in", baseVal, codeBlock->instructions.begin() + vPCIndex, codeBlock));
+ VM_CHECK_EXCEPTION(JSValue*);
+ }
+
+ JSValue* propName = ARG_src1;
+ JSObject* baseObj = static_cast<JSObject*>(baseVal);
+
+ uint32_t i;
+ if (propName->getUInt32(i))
+ return jsBoolean(baseObj->hasProperty(exec, i));
+
+ Identifier property(exec, propName->toString(exec));
+ VM_CHECK_EXCEPTION(JSValue*);
+ return jsBoolean(baseObj->hasProperty(exec, property));
+}
+
+JSValue* Machine::cti_op_push_new_scope(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ JSObject* scope = new (exec) JSStaticScopeObject(exec, *ARG_id1, ARG_src2, DontDelete);
+
+ ScopeChainNode* newScopeChain = ARG_scopeChain->push(scope);
+ ARG_setScopeChain(newScopeChain);
+ exec->m_scopeChain = newScopeChain;
+
+ return scope;
+}
+
+void Machine::cti_op_jmp_scopes(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ unsigned count = ARG_int1;
+
+ ScopeChainNode* tmp = ARG_scopeChain;
+ while (count--)
+ tmp = tmp->pop();
+
+ ARG_setScopeChain(tmp);
+ exec->m_scopeChain = tmp;
+}
+
+void Machine::cti_op_put_by_index(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ unsigned property = ARG_int2;
+
+ ARG_src1->put(exec, property, ARG_src3);
+}
+
+void* Machine::cti_op_switch_imm(CTI_ARGS)
+{
+ JSValue* scrutinee = ARG_src1;
+ unsigned tableIndex = ARG_int2;
+
+ CodeBlock* codeBlock = ARG_codeBlock;
+
+ if (JSImmediate::isNumber(scrutinee)) {
+ int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
+ return codeBlock->immediateSwitchJumpTables[tableIndex].ctiForValue(value);
+ }
+
+ return codeBlock->immediateSwitchJumpTables[tableIndex].ctiDefault;
+}
+
+void* Machine::cti_op_switch_char(CTI_ARGS)
+{
+ JSValue* scrutinee = ARG_src1;
+ unsigned tableIndex = ARG_int2;
+
+ CodeBlock* codeBlock = ARG_codeBlock;
+
+ void* result = codeBlock->characterSwitchJumpTables[tableIndex].ctiDefault;
+
+ if (scrutinee->isString()) {
+ UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
+ if (value->size() == 1)
+ result = codeBlock->characterSwitchJumpTables[tableIndex].ctiForValue(value->data()[0]);
+ }
+
+ return result;
+}
+
+void* Machine::cti_op_switch_string(CTI_ARGS)
+{
+ JSValue* scrutinee = ARG_src1;
+ unsigned tableIndex = ARG_int2;
+
+ CodeBlock* codeBlock = ARG_codeBlock;
+
+ void* result = codeBlock->stringSwitchJumpTables[tableIndex].ctiDefault;
+
+ if (scrutinee->isString()) {
+ UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
+ result = codeBlock->stringSwitchJumpTables[tableIndex].ctiForValue(value);
+ }
+
+ return result;
+}
+
+JSValue* Machine::cti_op_del_by_val(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+
+ JSValue* baseValue = ARG_src1;
+ JSObject* baseObj = baseValue->toObject(exec); // may throw
+
+ JSValue* subscript = ARG_src2;
+ JSValue* result;
+ uint32_t i;
+ if (subscript->getUInt32(i))
+ result = jsBoolean(baseObj->deleteProperty(exec, i));
+ else {
+ VM_CHECK_EXCEPTION(JSValue*);
+ Identifier property(exec, subscript->toString(exec));
+ VM_CHECK_EXCEPTION(JSValue*);
+ result = jsBoolean(baseObj->deleteProperty(exec, property));
+ }
+
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
+void Machine::cti_op_put_getter(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+
+ ASSERT(ARG_src1->isObject());
+ JSObject* baseObj = static_cast<JSObject*>(ARG_src1);
+ Identifier& ident = *ARG_id2;
+ ASSERT(ARG_src3->isObject());
+ baseObj->defineGetter(exec, ident, static_cast<JSObject*>(ARG_src3));
+}
+
+void Machine::cti_op_put_setter(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+
+ ASSERT(ARG_src1->isObject());
+ JSObject* baseObj = static_cast<JSObject*>(ARG_src1);
+ Identifier& ident = *ARG_id2;
+ ASSERT(ARG_src3->isObject());
+ baseObj->defineSetter(exec, ident, static_cast<JSObject*>(ARG_src3));
+}
+
+JSValue* Machine::cti_op_new_error(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ CodeBlock* codeBlock = ARG_codeBlock;
+ unsigned type = ARG_int1;
+ JSValue* message = ARG_src2;
+ unsigned lineNumber = ARG_int3;
+
+ return Error::create(exec, static_cast<ErrorType>(type), message->toString(exec), lineNumber, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
+}
+
+void Machine::cti_op_debug(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+ Register* r = ARG_r;
+
+ int debugHookID = ARG_int1;
+ int firstLine = ARG_int2;
+ int lastLine = ARG_int3;
+
+ exec->machine()->debug(exec, codeBlock, scopeChain, r, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
+}
+
+JSValue* Machine::cti_op_eq_null(CTI_ARGS)
+{
+ JSValue* src = ARG_src1;
+ if (src->isUndefinedOrNull())
+ return jsBoolean(true);
+
+ return jsBoolean(!JSImmediate::isImmediate(src) && static_cast<JSCell*>(src)->masqueradeAsUndefined());
+}
+
+JSValue* Machine::cti_op_neq_null(CTI_ARGS)
+{
+ JSValue* src = ARG_src1;
+ if (src->isUndefinedOrNull())
+ return jsBoolean(false);
+
+ return jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->masqueradeAsUndefined());
+}
+
+void* Machine::cti_vm_throw(CTI_ARGS)
+{
+ ExecState* exec = ARG_exec;
+ CodeBlock* codeBlock = ARG_codeBlock;
+ ScopeChainNode* scopeChain = ARG_scopeChain;
+ Register* r = ARG_r;
+
+ ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(exec->ctiReturnAddress()));
+ unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(exec->ctiReturnAddress());
+
+ ASSERT(exec->hadException());
+
+ JSValue* exceptionValue = exec->exception();
+
+ Instruction* handlerVPC = ARG_exec->machine()->throwException(exec, exceptionValue, codeBlock->instructions.begin() + vPCIndex, codeBlock, scopeChain, r, false);
+
+ if (handlerVPC) {
+ exec->setException(exceptionValue);
+ ARG_setScopeChain(scopeChain);
+ ARG_setCodeBlock(codeBlock);
+ ARG_setR(r);
+
+ void* catchRoutine = codeBlock->nativeExceptionCodeForHandlerVPC(handlerVPC);
+ ASSERT(catchRoutine);
+ ctiSetReturnAddress(&CTI_RETURN_ADDRESS, catchRoutine);
+ return catchRoutine;
+ } else {
+ exec->clearException();
+ *ARG_exception = exceptionValue;
+ return JSImmediate::nullImmediate();
+ }
+}
+
+#undef VM_CHECK_EXCEPTION
+#undef VM_CHECK_EXCEPTION_v
+#undef VM_CHECK_EXCEPTION_AT_END
+
+#endif // ENABLE(CTI)
+
} // namespace KJS
#include "RegisterFile.h"
#include <wtf/HashMap.h>
+#if ENABLE(CTI)
+#include "CTI.h"
+#endif
+
namespace KJS {
class CodeBlock;
enum { MaxReentryDepth = 128 };
class Machine {
+ friend class CTI;
+ friend class WRECompiler;
public:
Machine();
+ ~Machine();
RegisterFile& registerFile() { return m_registerFile; }
SamplingTool* m_sampler;
+#if ENABLE(CTI)
+#if COMPILER(MSVC)
+#define SFX_CALL __cdecl
+#else
+#define SFX_CALL
+#endif
+
+ static void SFX_CALL cti_timeout_check(CTI_ARGS);
+
+ static void SFX_CALL cti_op_end(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_add(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_pre_inc(CTI_ARGS);
+ static int SFX_CALL cti_op_loop_if_less(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_new_object(CTI_ARGS);
+ static void SFX_CALL cti_op_put_by_id(CTI_ARGS);
+ static void SFX_CALL cti_op_put_by_id_second(CTI_ARGS);
+ static void SFX_CALL cti_op_put_by_id_generic(CTI_ARGS);
+ static void SFX_CALL cti_op_put_by_id_fail(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_get_by_id(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_get_by_id_second(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_get_by_id_generic(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_get_by_id_fail(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_del_by_id(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_instanceof(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_mul(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_new_func(CTI_ARGS);
+ static void* SFX_CALL cti_op_call_JSFunction(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_call_NotJSFunction(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_ret(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_new_array(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_resolve(CTI_ARGS);
+ static void* SFX_CALL cti_op_construct_JSConstruct(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_construct_NotJSConstruct(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_get_by_val(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_resolve_func(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_sub(CTI_ARGS);
+ static void SFX_CALL cti_op_put_by_val(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_lesseq(CTI_ARGS);
+ static int SFX_CALL cti_op_loop_if_true(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_resolve_base(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_negate(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_resolve_skip(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_div(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_pre_dec(CTI_ARGS);
+ static int SFX_CALL cti_op_jless(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_not(CTI_ARGS);
+ static int SFX_CALL cti_op_jtrue(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_post_inc(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_eq(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_lshift(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_bitand(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_rshift(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_bitnot(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_resolve_with_base(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_new_func_exp(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_mod(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_less(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_neq(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_post_dec(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_urshift(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_bitxor(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_new_regexp(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_bitor(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_call_eval(CTI_ARGS);
+ static void* SFX_CALL cti_op_throw(CTI_ARGS);
+ static JSPropertyNameIterator* SFX_CALL cti_op_get_pnames(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_next_pname(CTI_ARGS);
+ static void SFX_CALL cti_op_push_scope(CTI_ARGS);
+ static void SFX_CALL cti_op_pop_scope(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_typeof(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_stricteq(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_nstricteq(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_to_jsnumber(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_in(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_push_new_scope(CTI_ARGS);
+ static void SFX_CALL cti_op_jmp_scopes(CTI_ARGS);
+ static void SFX_CALL cti_op_put_by_index(CTI_ARGS);
+ static void* SFX_CALL cti_op_switch_imm(CTI_ARGS);
+ static void* SFX_CALL cti_op_switch_char(CTI_ARGS);
+ static void* SFX_CALL cti_op_switch_string(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_del_by_val(CTI_ARGS);
+ static void SFX_CALL cti_op_put_getter(CTI_ARGS);
+ static void SFX_CALL cti_op_put_setter(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_new_error(CTI_ARGS);
+ static void SFX_CALL cti_op_debug(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_eq_null(CTI_ARGS);
+ static JSValue* SFX_CALL cti_op_neq_null(CTI_ARGS);
+
+ static void* SFX_CALL cti_vm_throw(CTI_ARGS);
+#endif // ENABLE(CTI)
+
+ // Default number of ticks before a timeout check should be done.
+ static const int initialTickCountThreshold = 1024;
+
private:
enum ExecutionFlag { Normal, InitializeAndReturn };
ALWAYS_INLINE void initializeCallFrame(Register* callFrame, CodeBlock*, Instruction*, ScopeChainNode*, Register* r, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function);
ALWAYS_INLINE void setScopeChain(ExecState* exec, ScopeChainNode*&, ScopeChainNode*);
- NEVER_INLINE void debug(ExecState*, const Instruction*, const CodeBlock*, ScopeChainNode*, Register*);
+ NEVER_INLINE void debug(ExecState*, const CodeBlock*, ScopeChainNode*, Register*, DebugHookID, int firstLine, int lastLine);
NEVER_INLINE bool unwindCallFrame(ExecState*, JSValue*, const Instruction*&, CodeBlock*&, ScopeChainNode*&, Register*&);
NEVER_INLINE Instruction* throwException(ExecState*, JSValue*&, const Instruction*, CodeBlock*&, ScopeChainNode*&, Register*&, bool);
void uncacheGetByID(CodeBlock*, Instruction* vPC);
void tryCachePutByID(CodeBlock*, Instruction* vPC, JSValue* baseValue, const PutPropertySlot&);
void uncachePutByID(CodeBlock*, Instruction* vPC);
-
+
+#if ENABLE(CTI)
+ void tryCTICacheGetByID(ExecState*, CodeBlock*, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot&);
+ void tryCTICachePutByID(ExecState*, CodeBlock*, void* returnAddress, JSValue* baseValue, const PutPropertySlot&);
+
+ void* getCTIArrayLengthTrampoline(ExecState*, CodeBlock*);
+ void* getCTIStringLengthTrampoline(ExecState*, CodeBlock*);
+
+ void* m_ctiArrayLengthTrampoline;
+ void* m_ctiStringLengthTrampoline;
+
+ OwnPtr<JITCodeBuffer> m_jitCodeBuffer;
+ JITCodeBuffer* jitCodeBuffer() const { return m_jitCodeBuffer.get(); }
+#endif
+
int m_reentryDepth;
unsigned m_timeoutTime;
unsigned m_timeAtLastCheckTimeout;
void* m_jsArrayVptr;
void* m_jsStringVptr;
+ void* m_jsFunctionVptr;
#if HAVE(COMPUTED_GOTO)
Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling
Register(Register*);
Register(Instruction*);
Register(JSPropertyNameIterator*);
+ explicit Register(void*);
CodeBlock* codeBlock() const;
ScopeChainNode* scopeChain() const;
IntType
} m_type;
#endif
+
+// FIXME: The commented out ASSERTs below are valid; NDEBUG CTI should set these when up to date.
+// static inline ptrdiff_t offsetOf_type()
+// {
+// return OBJECT_OFFSET(Register, m_type);
+// }
};
ALWAYS_INLINE Register::Register()
{
// Once registers hold doubles, this function will allocate a JSValue*
// if the register doesn't hold one already.
- ASSERT(m_type == JSValueType);
+// ASSERT(m_type == JSValueType);
return u.jsValue;
}
ALWAYS_INLINE JSValue* Register::getJSValue() const
{
- ASSERT(m_type == JSValueType);
+// ASSERT(m_type == JSValueType);
return u.jsValue;
}
u.i = i;
}
+ ALWAYS_INLINE Register::Register(void* v)
+ {
+ u.v = v;
+ }
+
ALWAYS_INLINE CodeBlock* Register::codeBlock() const
{
- ASSERT(m_type == CodeBlockType);
+// ASSERT(m_type == CodeBlockType);
return u.codeBlock;
}
ALWAYS_INLINE ScopeChainNode* Register::scopeChain() const
{
- ASSERT(m_type == ScopeChainNodeType);
+// ASSERT(m_type == ScopeChainNodeType);
return u.scopeChain;
}
ALWAYS_INLINE intptr_t Register::i() const
{
- ASSERT(m_type == IntType);
+// ASSERT(m_type == IntType);
return u.i;
}
ALWAYS_INLINE Register* Register::r() const
{
- ASSERT(m_type == RegisterType);
+// ASSERT(m_type == RegisterType);
return u.r;
}
ALWAYS_INLINE Instruction* Register::vPC() const
{
- ASSERT(m_type == InstructionType);
+// ASSERT(m_type == InstructionType);
return u.vPC;
}
ALWAYS_INLINE JSPropertyNameIterator* Register::jsPropertyNameIterator() const
{
- ASSERT(m_type == JSPropertyNameIteratorType);
+// ASSERT(m_type == JSPropertyNameIteratorType);
return u.jsPropertyNameIterator;
}
class RegisterFile : Noncopyable {
public:
- enum {
+ enum CallFrameHeaderEntry {
CallerCodeBlock = 0,
ReturnVPC,
CallerScopeChain,
CalledAsConstructor,
Callee,
OptionalCalleeActivation,
+ CTIReturnEIP,
CallFrameHeaderSize
};
return 1000000 / hertz;
}
+#if ENABLE(SAMPLING_TOOL)
+extern OpcodeID what;
+extern unsigned incall;
+unsigned cowdogs = 0;
+unsigned sampleCows[numOpcodeIDs] = {0};
+unsigned sampleDogs[numOpcodeIDs] = {0};
+#endif
+
void SamplingTool::run()
{
while (m_running) {
sleepForMicroseconds(hertz2us(m_hertz));
m_totalSamples++;
-
+#if ENABLE(SAMPLING_TOOL)
+ if (what != (OpcodeID)-1) {
+ ++cowdogs;
+ if (incall)
+ sampleDogs[what]++;
+ else
+ sampleCows[what]++;
+ }
+#endif
CodeBlock* codeBlock = m_recordedCodeBlock;
Instruction* vPC = m_recordedVPC;
{
OpcodeID opcode;
long long count;
+ long long countincall;
};
struct LineCountInfo
OpcodeSampleInfo opcodeSampleInfo[numOpcodeIDs];
for (int i = 0; i < numOpcodeIDs; ++i) {
opcodeSampleInfo[i].opcode = (OpcodeID)i;
- opcodeSampleInfo[i].count = opcodeSampleCounts[i];
+ opcodeSampleInfo[i].count = sampleCows[i]+sampleDogs[i];
+ opcodeSampleInfo[i].countincall = sampleDogs[i];
}
#if HAVE(MERGESORT)
mergesort(opcodeSampleInfo, numOpcodeIDs, sizeof(OpcodeSampleInfo), compareOpcodeIndicesSampling);
#endif
// (4) Print Opcode sampling results.
-
+
+
printf("\nOpcode sampling results\n\n");
- printf("Total opcodes sampled (total samples): %lld (%lld)\n\n", totalOpcodeSamples, m_totalSamples);
- printf("Opcodes in order:\n\n");
- for (int i = 0; i < numOpcodeIDs; ++i) {
- long long count = opcodeSampleCounts[i];
- printf("%s:%s%6lld\t%.3f%%\t(%.3f%%)\n", opcodeNames[i], padOpcodeName(static_cast<OpcodeID>(i), 20), count, (static_cast<double>(count) * 100) / totalOpcodeSamples, (static_cast<double>(count) * 100) / m_totalSamples);
- }
- printf("\n");
- printf("Opcodes by sample count:\n\n");
+// printf("Total opcodes sampled (total samples): %lld (%lld)\n\n", totalOpcodeSamples, m_totalSamples);
+// printf("Opcodes in order:\n\n");
+// for (int i = 0; i < numOpcodeIDs; ++i) {
+// long long count = opcodeSampleCounts[i];
+// printf("%s:%s%6lld\t%.3f%%\t(%.3f%%)\n", opcodeNames[i], padOpcodeName(static_cast<OpcodeID>(i), 20), count, (static_cast<double>(count) * 100) / totalOpcodeSamples, (static_cast<double>(count) * 100) / m_totalSamples);
+// }
+// printf("\n");
+// printf("Opcodes by sample count:\n\n");
+
for (int i = 0; i < numOpcodeIDs; ++i) {
OpcodeID opcode = opcodeSampleInfo[i].opcode;
long long count = opcodeSampleInfo[i].count;
- printf("%s:%s%6lld\t%.3f%%\t(%.3f%%)\n", opcodeNames[opcode], padOpcodeName(opcode, 20), count, (static_cast<double>(count) * 100) / totalOpcodeSamples, (static_cast<double>(count) * 100) / m_totalSamples);
+// printf("%s:%s%6lld\t%.3f%%\t(%.3f%%)\n", opcodeNames[opcode], padOpcodeName(opcode, 20), count, (static_cast<double>(count) * 100) / totalOpcodeSamples, (static_cast<double>(count) * 100) / m_totalSamples);
+ long long countincall = opcodeSampleInfo[i].countincall;
+ fprintf(stdout, "%s:%s%6lld\t%6lld\t%.3f%%\t%.3f%%\t(%.3f%%)\n", opcodeNames[opcode], padOpcodeName(opcode, 20), count, countincall, ((double)count * 100)/cowdogs, ((double)count * 100)/m_totalSamples, ((double)countincall * 100)/m_totalSamples);
}
printf("\n");
}
class CodeBlock;
struct Instruction;
+#if ENABLE(SAMPLING_TOOL)
+extern OpcodeID what;
+#endif
+
struct ScopeSampleRecord {
RefPtr<ScopeNode> m_scope;
CodeBlock* m_codeBlock;
{
m_recordedCodeBlock = 0;
m_recordedVPC = 0;
+#if ENABLE(SAMPLING_TOOL)
+ what=(OpcodeID)-1;
+#endif
}
private:
#define MACHINE_SAMPLING_sample(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
#define MACHINE_SAMPLING_privateExecuteReturned() m_sampler->privateExecuteReturned()
#define MACHINE_SAMPLING_callingHostFunction() m_sampler->callingHostFunction()
+#define CTI_MACHINE_SAMPLING_callingHostFunction() machine->m_sampler->callingHostFunction()
#else
#define SCOPENODE_SAMPLING_notifyOfScope(sampler)
#define MACHINE_SAMPLING_sample(codeBlock, vPC)
#define MACHINE_SAMPLING_privateExecuteReturned()
#define MACHINE_SAMPLING_callingHostFunction()
+#define CTI_MACHINE_SAMPLING_callingHostFunction()
#endif
} // namespace KJS
// Represents the current state of script execution.
// Passed as the first argument to most functions.
class ExecState : Noncopyable {
+#if ENABLE(CTI)
+ friend class CTI;
+#endif
friend class Machine;
friend class DebuggerCallFrame;
-
public:
ExecState(JSGlobalObject*, JSObject* globalThisValue, ScopeChainNode* globalScopeChain);
JSValue* exception() const { return m_exception; }
JSValue** exceptionSlot() { return &m_exception; }
bool hadException() const { return !!m_exception; }
+#if ENABLE(CTI)
+ void setCTIReturnAddress(void* ctiRA) { m_ctiReturnAddress = ctiRA; }
+ void* ctiReturnAddress() const { return m_ctiReturnAddress; }
+#endif
JSGlobalData& globalData() { return *m_globalData; }
JSObject* m_globalThisValue;
JSValue* m_exception;
-
+#if ENABLE(CTI)
+ void* m_ctiReturnAddress;
+#endif
JSGlobalData* m_globalData;
// These values are controlled by the machine.
const UString& name(ExecState*);
protected:
+ InternalFunction(PassRefPtr<KJS::StructureID> st) : JSObject(st){}
InternalFunction(ExecState*);
InternalFunction(ExecState*, FunctionPrototype*, const Identifier&);
};
class JSArray : public JSObject {
+ friend class CTI;
+
public:
JSArray(PassRefPtr<StructureID>);
JSArray(JSObject* prototype, unsigned initialLength);
friend class JSNumberCell;
friend class JSString;
friend class Machine;
+ friend class CTI;
private:
JSCell();
JSCell(StructureID*);
class JSGlobalObject;
class JSFunction : public InternalFunction {
+ friend class Machine;
+
typedef InternalFunction Base;
+ JSFunction(PassRefPtr<KJS::StructureID> st) : InternalFunction(st), m_scopeChain(NoScopeChain()) {}
public:
JSFunction(ExecState*, const Identifier&, FunctionBodyNode*, ScopeChainNode*);
class JSImmediate {
private:
+ friend class CTI; // Whooo!
+
static const uintptr_t TagMask = 0x3u; // primary tag is 2 bits long
static const uintptr_t TagBitTypeInteger = 0x1u; // bottom bit set indicates integer, this dominates the following bit
static const uintptr_t TagBitTypeOther = 0x2u; // second bit set indicates immediate other than an integer
static JSValue* falseImmediate();
static JSValue* undefinedImmediate();
static JSValue* nullImmediate();
+ static JSValue* zeroImmediate();
+ static JSValue* oneImmediate();
static JSValue* impossibleValue();
ALWAYS_INLINE JSValue* JSImmediate::falseImmediate() { return makeBool(false); }
ALWAYS_INLINE JSValue* JSImmediate::undefinedImmediate() { return makeUndefined(); }
ALWAYS_INLINE JSValue* JSImmediate::nullImmediate() { return makeNull(); }
+ ALWAYS_INLINE JSValue* JSImmediate::zeroImmediate() { return makeInt(0); }
+ ALWAYS_INLINE JSValue* JSImmediate::oneImmediate() { return makeInt(1); }
// This value is impossible because 0x4 is not a valid pointer but a tag of 0 would indicate non-immediate
ALWAYS_INLINE JSValue* JSImmediate::impossibleValue() { return reinterpret_cast<JSValue*>(0x4); }
class JSObject : public JSCell {
friend class BatchedTransitionOptimizer;
+ friend class CTI;
public:
JSObject(PassRefPtr<StructureID>);
JSString* jsOwnedString(ExecState*, const UString&);
class JSString : public JSCell {
+ friend class CTI;
+
public:
JSString(const UString& value)
: m_value(value)
#include "ustring.h"
#include <stddef.h> // for size_t
+// The magic number 0x4000 is not important here, it is being subtracted back out (avoiding using zero since this
+// can have unexpected effects in this type of macro, particularly where multiple-inheritance is involved).
+#define OBJECT_OFFSET(class, member) (reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<class*>(0x4000)->member)) - 0x4000)
+
namespace KJS {
class ExecState;
OwnArrayPtr<Register> registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file.
size_t registerArraySize;
+ static inline ptrdiff_t offsetOf_registers()
+ {
+ return OBJECT_OFFSET(JSVariableObjectData, registers);
+ }
+
private:
JSVariableObjectData(const JSVariableObjectData&);
JSVariableObjectData& operator=(const JSVariableObjectData&);
bool symbolTablePutWithAttributes(const Identifier&, JSValue*, unsigned attributes);
JSVariableObjectData* d;
+
+ public:
+ static inline ptrdiff_t offsetOf_d()
+ {
+ return OBJECT_OFFSET(JSVariableObject, d);
+ }
+
+ static inline ptrdiff_t offsetOf_Data_registers()
+ {
+ return JSVariableObjectData::offsetOf_registers();
+ }
};
inline bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertySlot& slot)
};
class PropertyMap : Noncopyable {
+ friend class CTI;
+
public:
PropertyMap();
~PropertyMap();
UString pattern = arg0->isUndefined() ? UString("") : arg0->toString(exec);
UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec);
- RefPtr<RegExp> regExp = RegExp::create(pattern, flags);
+ RefPtr<RegExp> regExp = RegExp::create(exec, pattern, flags);
if (!regExp->isValid())
return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
return new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpPrototype(), regExp.release());
} else {
UString pattern = args.isEmpty() ? UString("") : arg0->toString(exec);
UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec);
- regExp = RegExp::create(pattern, flags);
+ regExp = RegExp::create(exec, pattern, flags);
}
if (!regExp->isValid())
return ScopeChainIterator(0);
}
+ class NoScopeChain {};
+
class ScopeChain {
public:
+ ScopeChain(NoScopeChain)
+ : m_node(0)
+ {
+ }
+
ScopeChain(JSObject* o, JSObject* globalThis)
: m_node(new ScopeChainNode(0, o, globalThis))
{
: m_node(node->copy())
{
}
-
- ~ScopeChain() { m_node->deref(); }
+
+ ~ScopeChain()
+ {
+ if (m_node)
+ m_node->deref();
+ }
void swap(ScopeChain&);
* If regexp is not an object whose [[Class]] property is "RegExp", it is
* replaced with the result of the expression new RegExp(regexp).
*/
- reg = RegExp::create(a0->toString(exec));
+ reg = RegExp::create(exec, a0->toString(exec));
}
RegExpConstructor* regExpObj = exec->lexicalGlobalObject()->regExpConstructor();
int pos;
* If regexp is not an object whose [[Class]] property is "RegExp", it is
* replaced with the result of the expression new RegExp(regexp).
*/
- reg = RegExp::create(a0->toString(exec));
+ reg = RegExp::create(exec, a0->toString(exec));
}
RegExpConstructor* regExpObj = exec->lexicalGlobalObject()->regExpConstructor();
int pos;
RegisterID* RegExpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- if (!m_regExp->isValid())
- return emitThrowError(generator, SyntaxError, ("Invalid regular expression: " + UString(m_regExp->errorMessage())).UTF8String().c_str());
+ RefPtr<RegExp> regExp = RegExp::create(generator.globalExec(), m_pattern, m_flags);
+ if (!regExp->isValid())
+ return emitThrowError(generator, SyntaxError, ("Invalid regular expression: " + UString(regExp->errorMessage())).UTF8String().c_str());
if (dst == ignoredResult())
return 0;
- return generator.emitNewRegExp(generator.finalDestination(dst), m_regExp.get());
+ return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get());
}
// ------------------------------ ThisNode -------------------------------------
RefPtr<RegisterID> highestUsedRegister = generator.highestUsedRegister();
RefPtr<LabelID> finallyEndLabel = generator.newLabel();
generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get());
+ // Use a label to record the subtle fact that sret will return to the
+ // next instruction. sret is the only way to jump without an explicit label.
+ generator.emitLabel(generator.newLabel().get());
generator.emitJump(finallyEndLabel.get());
// Finally block for exception path
RefPtr<RegisterID> tempExceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), generator.emitLabel(generator.newLabel().get()).get());
generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get());
+ // Use a label to record the subtle fact that sret will return to the
+ // next instruction. sret is the only way to jump without an explicit label.
+ generator.emitLabel(generator.newLabel().get());
generator.emitThrow(tempExceptionRegister.get());
// emit the finally block itself
public:
RegExpNode(JSGlobalData* globalData, const UString& pattern, const UString& flags) KJS_FAST_CALL
: ExpressionNode(globalData)
- , m_regExp(RegExp::create(pattern, flags))
+ , m_pattern(pattern)
+ , m_flags(flags)
{
}
virtual Precedence precedence() const { return PrecPrimary; }
private:
- RefPtr<RegExp> m_regExp;
+ UString m_pattern;
+ UString m_flags;
};
class ThisNode : public ExpressionNode {
void RegExpNode::streamTo(SourceStream& s) const
{
- s << '/' << m_regExp->pattern() << '/' << m_regExp->flags();
+ s << '/' << m_pattern << '/' << m_flags;
}
void ThisNode::streamTo(SourceStream& s) const
#include "config.h"
#include "regexp.h"
+#include "CTI.h"
#include "lexer.h"
#include <pcre/pcre.h>
#include <stdio.h>
namespace KJS {
-inline RegExp::RegExp(const UString& pattern)
+
+
+inline RegExp::RegExp(ExecState* exec, const UString& pattern)
: m_pattern(pattern)
, m_flagBits(0)
+ , m_regExp(0)
, m_constructionError(0)
, m_numSubpatterns(0)
{
- m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(pattern.data()), pattern.size(),
- JSRegExpDoNotIgnoreCase, JSRegExpSingleLine, &m_numSubpatterns, &m_constructionError);
+#if ENABLE(WREC)
+ if (!(m_wrecFunction = (WRECFunction)CTI::compileRegExp(exec, pattern, &m_numSubpatterns, &m_constructionError)))
+#else
+ UNUSED_PARAM(exec);
+#endif
+ {
+ m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(pattern.data()), pattern.size(),
+ JSRegExpDoNotIgnoreCase, JSRegExpSingleLine, &m_numSubpatterns, &m_constructionError);
+ }
}
-PassRefPtr<RegExp> RegExp::create(const UString& pattern)
+PassRefPtr<RegExp> RegExp::create(ExecState* exec, const UString& pattern)
{
- return adoptRef(new RegExp(pattern));
+ return adoptRef(new RegExp(exec, pattern));
}
-inline RegExp::RegExp(const UString& pattern, const UString& flags)
+inline RegExp::RegExp(ExecState* exec, const UString& pattern, const UString& flags)
: m_pattern(pattern)
, m_flags(flags)
, m_flagBits(0)
+ , m_regExp(0)
, m_constructionError(0)
, m_numSubpatterns(0)
{
multilineOption = JSRegExpMultiline;
}
- m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(pattern.data()), pattern.size(),
- ignoreCaseOption, multilineOption, &m_numSubpatterns, &m_constructionError);
+#if ENABLE(WREC)
+ if (!(m_wrecFunction = (WRECFunction)CTI::compileRegExp(exec, pattern, &m_numSubpatterns, &m_constructionError, (m_flagBits & IgnoreCase), (m_flagBits & Multiline))))
+#else
+ UNUSED_PARAM(exec);
+#endif
+ {
+ m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(pattern.data()), pattern.size(),
+ ignoreCaseOption, multilineOption, &m_numSubpatterns, &m_constructionError);
+ }
}
-PassRefPtr<RegExp> RegExp::create(const UString& pattern, const UString& flags)
+PassRefPtr<RegExp> RegExp::create(ExecState* exec, const UString& pattern, const UString& flags)
{
- return adoptRef(new RegExp(pattern, flags));
+ return adoptRef(new RegExp(exec, pattern, flags));
}
RegExp::~RegExp()
{
jsRegExpFree(m_regExp);
+#if ENABLE(WREC)
+ if (m_wrecFunction)
+ fastFree(reinterpret_cast<void*>(m_wrecFunction));
+#endif
}
int RegExp::match(const UString& s, int i, OwnArrayPtr<int>* ovector)
if (i > s.size() || s.isNull())
return -1;
- if (!m_regExp)
- return -1;
+#if ENABLE(WREC)
+ if (m_wrecFunction) {
+ int offsetVectorSize = (m_numSubpatterns + 1) * 2;
+ int* offsetVector = new int [offsetVectorSize];
+ for (int j = 0; j < offsetVectorSize; ++j)
+ offsetVector[j] = -1;
- // Set up the offset vector for the result.
- // First 2/3 used for result, the last third used by PCRE.
- int* offsetVector;
- int offsetVectorSize;
- int fixedSizeOffsetVector[3];
- if (!ovector) {
- offsetVectorSize = 3;
- offsetVector = fixedSizeOffsetVector;
- } else {
- offsetVectorSize = (m_numSubpatterns + 1) * 3;
- offsetVector = new int [offsetVectorSize];
- ovector->set(offsetVector);
- }
+ OwnArrayPtr<int> nonReturnedOvector;
+ if (!ovector)
+ nonReturnedOvector.set(offsetVector);
+ else
+ ovector->set(offsetVector);
- int numMatches = jsRegExpExecute(m_regExp, reinterpret_cast<const UChar*>(s.data()), s.size(), i, offsetVector, offsetVectorSize);
+ int result = m_wrecFunction(s.data(), i, s.size(), offsetVector);
- if (numMatches < 0) {
+ if (result < 0) {
#ifndef NDEBUG
- if (numMatches != JSRegExpErrorNoMatch)
- fprintf(stderr, "jsRegExpExecute failed with result %d\n", numMatches);
+ // TODO: define up a symbol, rather than magic -1
+ if (result != -1)
+ fprintf(stderr, "jsRegExpExecute failed with result %d\n", result);
#endif
- if (ovector)
- ovector->clear();
- return -1;
+ if (ovector)
+ ovector->clear();
+ }
+ return result;
+ } else
+#endif
+ if (m_regExp) {
+ // Set up the offset vector for the result.
+ // First 2/3 used for result, the last third used by PCRE.
+ int* offsetVector;
+ int offsetVectorSize;
+ int fixedSizeOffsetVector[3];
+ if (!ovector) {
+ offsetVectorSize = 3;
+ offsetVector = fixedSizeOffsetVector;
+ } else {
+ offsetVectorSize = (m_numSubpatterns + 1) * 3;
+ offsetVector = new int [offsetVectorSize];
+ ovector->set(offsetVector);
+ }
+
+ int numMatches = jsRegExpExecute(m_regExp, reinterpret_cast<const UChar*>(s.data()), s.size(), i, offsetVector, offsetVectorSize);
+
+ if (numMatches < 0) {
+#ifndef NDEBUG
+ if (numMatches != JSRegExpErrorNoMatch)
+ fprintf(stderr, "jsRegExpExecute failed with result %d\n", numMatches);
+#endif
+ if (ovector)
+ ovector->clear();
+ return -1;
+ }
+
+ return offsetVector[0];
}
- return offsetVector[0];
+ return -1;
}
} // namespace KJS
#define KJS_REGEXP_H
#include "ustring.h"
+#include "ExecState.h"
#include <wtf/Forward.h>
#include <wtf/RefCounted.h>
+#include <wrec/WREC.h>
struct JSRegExp;
class RegExp : public RefCounted<RegExp> {
public:
- static PassRefPtr<RegExp> create(const UString& pattern);
- static PassRefPtr<RegExp> create(const UString& pattern, const UString& flags);
+ static PassRefPtr<RegExp> create(ExecState*, const UString& pattern);
+ static PassRefPtr<RegExp> create(ExecState*, const UString& pattern, const UString& flags);
~RegExp();
bool global() const { return m_flagBits & Global; }
unsigned numSubpatterns() const { return m_numSubpatterns; }
private:
- RegExp(const UString& pattern);
- RegExp(const UString& pattern, const UString& flags);
+ RegExp(ExecState*, const UString& pattern);
+ RegExp(ExecState*, const UString& pattern, const UString& flags);
void compile();
JSRegExp* m_regExp;
const char* m_constructionError;
unsigned m_numSubpatterns;
+
+#if ENABLE(WREC)
+ WRECFunction m_wrecFunction;
+#endif
};
} // namespace KJS
typedef Vector<char, 32> CStringBuffer;
class UString {
+ friend class CTI;
+
public:
struct Rep {
+ friend class CTI;
+
static PassRefPtr<Rep> create(UChar*, int);
static PassRefPtr<Rep> createCopying(const UChar*, int);
static PassRefPtr<Rep> create(PassRefPtr<Rep> base, int offset, int length);
--- /dev/null
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 IA32MacroAsm_h
+#define IA32MacroAsm_h
+
+#if ENABLE(MASM) && PLATFORM(X86)
+
+#include <wtf/Assertions.h>
+#include <wtf/AlwaysInline.h>
+#if HAVE(MMAN)
+#include <sys/mman.h>
+#endif
+
+#include <string.h>
+
+namespace KJS {
+
+class JITCodeBuffer {
+public:
+ JITCodeBuffer(int size)
+ : m_buffer(static_cast<char*>(fastMalloc(size)))
+ , m_size(size)
+ , m_index(0)
+ {
+ }
+
+ ~JITCodeBuffer()
+ {
+ fastFree(m_buffer);
+ }
+
+ void ensureSpace(int space)
+ {
+ if (m_index > m_size - space)
+ growBuffer();
+ }
+
+ void putByteUnchecked(int value)
+ {
+ m_buffer[m_index] = value;
+ m_index++;
+ }
+
+ void putByte(int value)
+ {
+ if (m_index > m_size - 4)
+ growBuffer();
+ putByteUnchecked(value);
+ }
+
+ void putShortUnchecked(int value)
+ {
+ *(short*)(&m_buffer[m_index]) = value;
+ m_index += 2;
+ }
+
+ void putShort(int value)
+ {
+ if (m_index > m_size - 4)
+ growBuffer();
+ putShortUnchecked(value);
+ }
+
+ void putIntUnchecked(int value)
+ {
+ *(int*)(&m_buffer[m_index]) = value;
+ m_index += 4;
+ }
+
+ void putInt(int value)
+ {
+ if (m_index > m_size - 4)
+ growBuffer();
+ putIntUnchecked(value);
+ }
+
+ void* getEIP()
+ {
+ return m_buffer + m_index;
+ }
+
+ void* start()
+ {
+ return m_buffer;
+ }
+
+ int getOffset()
+ {
+ return m_index;
+ }
+
+ JITCodeBuffer* reset()
+ {
+ m_index = 0;
+ return this;
+ }
+
+ void* copy()
+ {
+ if (!m_index)
+ return 0;
+
+ void* result = fastMalloc(m_index);
+
+ if (!result)
+ return 0;
+
+ return memcpy(result, m_buffer, m_index);
+ }
+
+private:
+ void growBuffer()
+ {
+ m_size += m_size / 2;
+ m_buffer = static_cast<char*>(fastRealloc(m_buffer, m_size));
+ }
+
+ char* m_buffer;
+ int m_size;
+ int m_index;
+};
+
+#define MODRM(type, reg, rm) ((type << 6) | (reg << 3) | (rm))
+#define SIB(type, reg, rm) MODRM(type, reg, rm)
+#define CAN_SIGN_EXTEND_8_32(value) (value == ((int)(signed char)value))
+
+class IA32MacroAssembler {
+public:
+ typedef enum {
+ eax,
+ ecx,
+ edx,
+ ebx,
+ esp,
+ ebp,
+ esi,
+ edi,
+
+ NO_BASE = ebp,
+ HAS_SIB = esp,
+ NO_SCALE = esp,
+ } RegisterID;
+
+ typedef enum {
+ OP_ADD_EvGv = 0x01,
+ OP_ADD_GvEv = 0x03,
+ OP_OR_EvGv = 0x09,
+ OP_2BYTE_ESCAPE = 0x0F,
+ OP_AND_EvGv = 0x21,
+ OP_SUB_EvGv = 0x29,
+ OP_SUB_GvEv = 0x2B,
+ PRE_PREDICT_BRANCH_NOT_TAKEN = 0x2E,
+ OP_XOR_EvGv = 0x31,
+ OP_CMP_EvGv = 0x39,
+ OP_PUSH_EAX = 0x50,
+ OP_POP_EAX = 0x58,
+ PRE_OPERAND_SIZE = 0x66,
+ OP_GROUP1_EvIz = 0x81,
+ OP_GROUP1_EvIb = 0x83,
+ OP_TEST_EvGv = 0x85,
+ OP_MOV_EvGv = 0x89,
+ OP_MOV_GvEv = 0x8B,
+ OP_LEA = 0x8D,
+ OP_GROUP1A_Ev = 0x8F,
+ OP_CDQ = 0x99,
+ OP_GROUP2_EvIb = 0xC1,
+ OP_RET = 0xC3,
+ OP_GROUP11_EvIz = 0xC7,
+ OP_INT3 = 0xCC,
+ OP_GROUP2_Ev1 = 0xD1,
+ OP_GROUP2_EvCL = 0xD3,
+ OP_CALL_rel32 = 0xE8,
+ OP_JMP_rel32 = 0xE9,
+ OP_GROUP3_Ev = 0xF7,
+ OP_GROUP3_EvIz = 0xF7, // OP_GROUP3_Ev has an immediate, when instruction is a test.
+ OP_GROUP5_Ev = 0xFF,
+
+ OP2_JO_rel32 = 0x80,
+ OP2_JB_rel32 = 0x82,
+ OP2_JAE_rel32 = 0x83,
+ OP2_JE_rel32 = 0x84,
+ OP2_JNE_rel32 = 0x85,
+ OP2_JBE_rel32 = 0x86,
+ OP2_JL_rel32 = 0x8C,
+ OP2_JGE_rel32 = 0x8D,
+ OP2_JLE_rel32 = 0x8E,
+ OP2_MUL_GvEv = 0xAF,
+ OP2_MOVZX_GvEw = 0xB7,
+
+ GROUP1_OP_ADD = 0,
+ GROUP1_OP_OR = 1,
+ GROUP1_OP_AND = 4,
+ GROUP1_OP_SUB = 5,
+ GROUP1_OP_XOR = 6,
+ GROUP1_OP_CMP = 7,
+
+ GROUP1A_OP_POP = 0,
+
+ GROUP2_OP_SHL = 4,
+ GROUP2_OP_SAR = 7,
+
+ GROUP3_OP_TEST = 0,
+ GROUP3_OP_IDIV = 7,
+
+ GROUP5_OP_CALLN = 2,
+ GROUP5_OP_JMPN = 4,
+ GROUP5_OP_PUSH = 6,
+
+ GROUP11_MOV = 0,
+ } OpcodeID;
+
+ static const int MAX_INSTRUCTION_SIZE = 16;
+
+ IA32MacroAssembler(JITCodeBuffer* m_buffer)
+ : m_buffer(m_buffer)
+ {
+ m_buffer->reset();
+ }
+
+ void emitInt3()
+ {
+ m_buffer->putByte(OP_INT3);
+ }
+
+ void emitPushl_r(RegisterID reg)
+ {
+ m_buffer->putByte(OP_PUSH_EAX + reg);
+ }
+
+ void emitPushl_m(int offset, RegisterID base)
+ {
+ m_buffer->putByte(OP_GROUP5_Ev);
+ emitModRm_opm(GROUP5_OP_PUSH, base, offset);
+ }
+
+ void emitPopl_r(RegisterID reg)
+ {
+ m_buffer->putByte(OP_POP_EAX + reg);
+ }
+
+ void emitPopl_m(int offset, RegisterID base)
+ {
+ m_buffer->putByte(OP_GROUP1A_Ev);
+ emitModRm_opm(GROUP1A_OP_POP, base, offset);
+ }
+
+ void emitMovl_rr(RegisterID src, RegisterID dst)
+ {
+ m_buffer->putByte(OP_MOV_EvGv);
+ emitModRm_rr(src, dst);
+ }
+
+ void emitAddl_rr(RegisterID src, RegisterID dst)
+ {
+ m_buffer->putByte(OP_ADD_EvGv);
+ emitModRm_rr(src, dst);
+ }
+
+ void emitAddl_i8r(int imm, RegisterID dst)
+ {
+ m_buffer->putByte(OP_GROUP1_EvIb);
+ emitModRm_opr(GROUP1_OP_ADD, dst);
+ m_buffer->putByte(imm);
+ }
+
+ void emitAddl_i32r(int imm, RegisterID dst)
+ {
+ m_buffer->putByte(OP_GROUP1_EvIz);
+ emitModRm_opr(GROUP1_OP_ADD, dst);
+ m_buffer->putInt(imm);
+ }
+
+ void emitAddl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ m_buffer->putByte(OP_ADD_GvEv);
+ emitModRm_rm(dst, base, offset);
+ }
+
+ void emitAndl_rr(RegisterID src, RegisterID dst)
+ {
+ m_buffer->putByte(OP_AND_EvGv);
+ emitModRm_rr(src, dst);
+ }
+
+ void emitAndl_i32r(int imm, RegisterID dst)
+ {
+ m_buffer->putByte(OP_GROUP1_EvIz);
+ emitModRm_opr(GROUP1_OP_AND, dst);
+ m_buffer->putInt(imm);
+ }
+
+ void emitCmpl_i8r(int imm, RegisterID dst)
+ {
+ m_buffer->putByte(OP_GROUP1_EvIb);
+ emitModRm_opr(GROUP1_OP_CMP, dst);
+ m_buffer->putByte(imm);
+ }
+
+ void emitCmpl_rr(RegisterID src, RegisterID dst)
+ {
+ m_buffer->putByte(OP_CMP_EvGv);
+ emitModRm_rr(src, dst);
+ }
+
+ void emitCmpl_rm(RegisterID src, int offset, RegisterID base)
+ {
+ m_buffer->putByte(OP_CMP_EvGv);
+ emitModRm_rm(src, base, offset);
+ }
+
+ void emitCmpl_i32r(int imm, RegisterID dst)
+ {
+ m_buffer->putByte(OP_GROUP1_EvIz);
+ emitModRm_opr(GROUP1_OP_CMP, dst);
+ m_buffer->putInt(imm);
+ }
+
+ void emitCmpl_i32m(int imm, RegisterID dst)
+ {
+ m_buffer->putByte(OP_GROUP1_EvIz);
+ emitModRm_opm(GROUP1_OP_CMP, dst);
+ m_buffer->putInt(imm);
+ }
+
+ void emitCmpl_i32m(int imm, int offset, RegisterID dst)
+ {
+ m_buffer->putByte(OP_GROUP1_EvIz);
+ emitModRm_opm(GROUP1_OP_CMP, dst, offset);
+ m_buffer->putInt(imm);
+ }
+
+ void emitCmpl_i32m(int imm, void* addr)
+ {
+ m_buffer->putByte(OP_GROUP1_EvIz);
+ emitModRm_opm(GROUP1_OP_CMP, addr);
+ m_buffer->putInt(imm);
+ }
+
+ void emitCmpw_rm(RegisterID src, RegisterID base, RegisterID index, int scale)
+ {
+ m_buffer->putByte(PRE_OPERAND_SIZE);
+ m_buffer->putByte(OP_CMP_EvGv);
+ emitModRm_rmsib(src, base, index, scale);
+ }
+
+ void emitOrl_rr(RegisterID src, RegisterID dst)
+ {
+ m_buffer->putByte(OP_OR_EvGv);
+ emitModRm_rr(src, dst);
+ }
+
+ void emitOrl_i8r(int imm, Regis