diff options
author | Jocelyn Turcotte <jocelyn.turcotte@nokia.com> | 2010-04-06 10:36:47 (GMT) |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@nokia.com> | 2010-04-06 10:36:47 (GMT) |
commit | bb35b65bbfba82e0dd0ac306d3dab54436cdaff6 (patch) | |
tree | 8174cb262a960ff7b2e4aa8f1aaf154db71d2636 /src/3rdparty/webkit/JavaScriptCore/interpreter | |
parent | 4b27d0d887269583a0f76e922948f8c25e96ab88 (diff) | |
download | Qt-bb35b65bbfba82e0dd0ac306d3dab54436cdaff6.zip Qt-bb35b65bbfba82e0dd0ac306d3dab54436cdaff6.tar.gz Qt-bb35b65bbfba82e0dd0ac306d3dab54436cdaff6.tar.bz2 |
Update src/3rdparty/webkit from trunk.
Imported from 839d8709327f925aacb3b6362c06152594def97e
in branch qtwebkit-2.0 of repository
git://gitorious.org/+qtwebkit-developers/webkit/qtwebkit.git
Rubber-stamped-by: Simon Hausmann
Diffstat (limited to 'src/3rdparty/webkit/JavaScriptCore/interpreter')
6 files changed, 498 insertions, 79 deletions
diff --git a/src/3rdparty/webkit/JavaScriptCore/interpreter/CachedCall.h b/src/3rdparty/webkit/JavaScriptCore/interpreter/CachedCall.h index e903b79..eb48a03 100644 --- a/src/3rdparty/webkit/JavaScriptCore/interpreter/CachedCall.h +++ b/src/3rdparty/webkit/JavaScriptCore/interpreter/CachedCall.h @@ -38,7 +38,7 @@ namespace JSC { : m_valid(false) , m_interpreter(callFrame->interpreter()) , m_exception(exception) - , m_globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : function->scope().globalObject()) + , m_globalObjectScope(callFrame, function->scope().globalObject()) { ASSERT(!function->isHostFunction()); m_closure = m_interpreter->prepareForRepeatCall(function->jsExecutable(), callFrame, function, argCount, function->scope().node(), exception); @@ -52,7 +52,14 @@ namespace JSC { } void setThis(JSValue v) { m_closure.setArgument(0, v); } void setArgument(int n, JSValue v) { m_closure.setArgument(n + 1, v); } - CallFrame* newCallFrame() { return m_closure.newCallFrame; } + + CallFrame* newCallFrame(ExecState* exec) + { + CallFrame* callFrame = m_closure.newCallFrame; + callFrame->setScopeChain(exec->scopeChain()); + return callFrame; + } + ~CachedCall() { if (m_valid) diff --git a/src/3rdparty/webkit/JavaScriptCore/interpreter/CallFrame.h b/src/3rdparty/webkit/JavaScriptCore/interpreter/CallFrame.h index b4d49db..e3ea689 100644 --- a/src/3rdparty/webkit/JavaScriptCore/interpreter/CallFrame.h +++ b/src/3rdparty/webkit/JavaScriptCore/interpreter/CallFrame.h @@ -39,7 +39,11 @@ namespace JSC { public: JSFunction* callee() const { return this[RegisterFile::Callee].function(); } CodeBlock* codeBlock() const { return this[RegisterFile::CodeBlock].Register::codeBlock(); } - ScopeChainNode* scopeChain() const { return this[RegisterFile::ScopeChain].Register::scopeChain(); } + ScopeChainNode* scopeChain() const + { + ASSERT(this[RegisterFile::ScopeChain].Register::scopeChain()); + return this[RegisterFile::ScopeChain].Register::scopeChain(); + } int argumentCount() const { return this[RegisterFile::ArgumentCount].i(); } JSValue thisValue(); @@ -66,6 +70,7 @@ namespace JSC { // or a pointer everywhere. JSGlobalData& globalData() const { + ASSERT(scopeChain()->globalData); return *scopeChain()->globalData; } @@ -105,9 +110,9 @@ namespace JSC { Arguments* optionalCalleeArguments() const { return this[RegisterFile::OptionalCalleeArguments].arguments(); } Instruction* returnPC() const { return this[RegisterFile::ReturnPC].vPC(); } - void setCalleeArguments(JSValue arguments) { this[RegisterFile::OptionalCalleeArguments] = arguments; } - void setCallerFrame(CallFrame* callerFrame) { this[RegisterFile::CallerFrame] = callerFrame; } - void setScopeChain(ScopeChainNode* scopeChain) { this[RegisterFile::ScopeChain] = scopeChain; } + void setCalleeArguments(JSValue arguments) { static_cast<Register*>(this)[RegisterFile::OptionalCalleeArguments] = arguments; } + void setCallerFrame(CallFrame* callerFrame) { static_cast<Register*>(this)[RegisterFile::CallerFrame] = callerFrame; } + void setScopeChain(ScopeChainNode* scopeChain) { static_cast<Register*>(this)[RegisterFile::ScopeChain] = scopeChain; } ALWAYS_INLINE void init(CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, CallFrame* callerFrame, int returnValueRegister, int argc, JSFunction* function) @@ -117,8 +122,8 @@ namespace JSC { setCodeBlock(codeBlock); setScopeChain(scopeChain); setCallerFrame(callerFrame); - this[RegisterFile::ReturnPC] = vPC; // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*. - this[RegisterFile::ReturnValueRegister] = Register::withInt(returnValueRegister); + static_cast<Register*>(this)[RegisterFile::ReturnPC] = vPC; // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*. + static_cast<Register*>(this)[RegisterFile::ReturnValueRegister] = Register::withInt(returnValueRegister); setArgumentCount(argc); // original argument count (for the sake of the "arguments" object) setCallee(function); setCalleeArguments(JSValue()); @@ -135,9 +140,9 @@ namespace JSC { CallFrame* removeHostCallFrameFlag() { return reinterpret_cast<CallFrame*>(reinterpret_cast<intptr_t>(this) & ~HostCallFrameFlag); } private: - void setArgumentCount(int count) { this[RegisterFile::ArgumentCount] = Register::withInt(count); } - void setCallee(JSFunction* callee) { this[RegisterFile::Callee] = callee; } - void setCodeBlock(CodeBlock* codeBlock) { this[RegisterFile::CodeBlock] = codeBlock; } + void setArgumentCount(int count) { static_cast<Register*>(this)[RegisterFile::ArgumentCount] = Register::withInt(count); } + void setCallee(JSFunction* callee) { static_cast<Register*>(this)[RegisterFile::Callee] = callee; } + void setCodeBlock(CodeBlock* codeBlock) { static_cast<Register*>(this)[RegisterFile::CodeBlock] = codeBlock; } static const intptr_t HostCallFrameFlag = 1; diff --git a/src/3rdparty/webkit/JavaScriptCore/interpreter/Interpreter.cpp b/src/3rdparty/webkit/JavaScriptCore/interpreter/Interpreter.cpp index db0edc4..2713fd4 100644 --- a/src/3rdparty/webkit/JavaScriptCore/interpreter/Interpreter.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/interpreter/Interpreter.cpp @@ -40,6 +40,7 @@ #include "DebuggerCallFrame.h" #include "EvalCodeCache.h" #include "ExceptionHelpers.h" +#include "GetterSetter.h" #include "GlobalEvalFunction.h" #include "JSActivation.h" #include "JSArray.h" @@ -169,7 +170,7 @@ NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* PropertySlot slot(globalObject); if (globalObject->getPropertySlot(callFrame, ident, slot)) { JSValue result = slot.getValue(callFrame, ident); - if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { + if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { if (vPC[4].u.structure) vPC[4].u.structure->deref(); globalObject->structure()->ref(); @@ -300,7 +301,7 @@ NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* r if (!program.isString()) return program; - UString programSource = asString(program)->value(); + UString programSource = asString(program)->value(callFrame); LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON); if (JSValue parsedObject = preparser.tryLiteralParse()) @@ -321,7 +322,13 @@ Interpreter::Interpreter() : m_sampleEntryDepth(0) , m_reentryDepth(0) { +#if HAVE(COMPUTED_GOTO) privateExecute(InitializeAndReturn, 0, 0, 0); + + for (int i = 0; i < numOpcodeIDs; ++i) + m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i)); +#endif // HAVE(COMPUTED_GOTO) + #if ENABLE(OPCODE_SAMPLING) enableSampler(); #endif @@ -527,7 +534,8 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) { DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue); - debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)); + bool hasHandler = codeBlock->handlerForBytecodeOffset(bytecodeOffset); + debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset), hasHandler); } // If we throw in the middle of a call instruction, we need to notify @@ -537,7 +545,7 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV #if !ENABLE(JIT) if (isCallBytecode(codeBlock->instructions()[bytecodeOffset].u.opcode)) profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 2].u.operand).jsValue()); - else if (codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct)) + else if (codeBlock->instructions().size() > (bytecodeOffset + 8) && codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct)) profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 10].u.operand).jsValue()); #else int functionRegisterIndex; @@ -647,7 +655,7 @@ JSValue Interpreter::execute(FunctionExecutable* functionExecutable, CallFrame* return jsNull(); } - DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject); + DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject); CallFrame* newCallFrame = CallFrame::create(oldEnd); size_t dst = 0; @@ -777,7 +785,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec } } - DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject); + DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject); EvalCodeBlock* codeBlock = &eval->bytecode(callFrame, scopeChain); @@ -1022,8 +1030,20 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* // Cache hit: Specialize instruction and ref Structures. if (slot.slotBase() == baseValue) { - vPC[0] = getOpcode(op_get_by_id_self); - vPC[5] = slot.cachedOffset(); + switch (slot.cachedPropertyType()) { + case PropertySlot::Getter: + vPC[0] = getOpcode(op_get_by_id_getter_self); + vPC[5] = slot.cachedOffset(); + break; + case PropertySlot::Custom: + vPC[0] = getOpcode(op_get_by_id_custom_self); + vPC[5] = slot.customGetter(); + break; + default: + vPC[0] = getOpcode(op_get_by_id_self); + vPC[5] = slot.cachedOffset(); + break; + } codeBlock->refStructures(vPC); return; @@ -1038,33 +1058,62 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* ASSERT(slot.slotBase().isObject()); JSObject* baseObject = asObject(slot.slotBase()); + size_t offset = slot.cachedOffset(); // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. - if (baseObject->structure()->isDictionary()) - baseObject->setStructure(Structure::fromDictionaryTransition(baseObject->structure())); + if (baseObject->structure()->isDictionary()) { + baseObject->flattenDictionaryObject(); + offset = baseObject->structure()->get(propertyName); + } ASSERT(!baseObject->structure()->isUncacheableDictionary()); - - vPC[0] = getOpcode(op_get_by_id_proto); + + switch (slot.cachedPropertyType()) { + case PropertySlot::Getter: + vPC[0] = getOpcode(op_get_by_id_getter_proto); + vPC[6] = offset; + break; + case PropertySlot::Custom: + vPC[0] = getOpcode(op_get_by_id_custom_proto); + vPC[6] = slot.customGetter(); + break; + default: + vPC[0] = getOpcode(op_get_by_id_proto); + vPC[6] = offset; + break; + } vPC[5] = baseObject->structure(); - vPC[6] = slot.cachedOffset(); codeBlock->refStructures(vPC); return; } - size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase()); + size_t offset = slot.cachedOffset(); + size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset); if (!count) { vPC[0] = getOpcode(op_get_by_id_generic); return; } - vPC[0] = getOpcode(op_get_by_id_chain); + + switch (slot.cachedPropertyType()) { + case PropertySlot::Getter: + vPC[0] = getOpcode(op_get_by_id_getter_chain); + vPC[7] = offset; + break; + case PropertySlot::Custom: + vPC[0] = getOpcode(op_get_by_id_custom_chain); + vPC[7] = slot.customGetter(); + break; + default: + vPC[0] = getOpcode(op_get_by_id_chain); + vPC[7] = offset; + break; + } vPC[4] = structure; vPC[5] = structure->prototypeChain(callFrame); vPC[6] = count; - vPC[7] = slot.cachedOffset(); codeBlock->refStructures(vPC); } @@ -1081,16 +1130,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi { // One-time initialization of our address tables. We have to put this code // here because our labels are only in scope inside this function. - if (flag == InitializeAndReturn) { + if (UNLIKELY(flag == InitializeAndReturn)) { #if HAVE(COMPUTED_GOTO) - #define ADD_BYTECODE(id, length) m_opcodeTable[id] = &&id; - FOR_EACH_OPCODE_ID(ADD_BYTECODE); - #undef ADD_BYTECODE - - #define ADD_OPCODE_ID(id, length) m_opcodeIDTable.add(&&id, id); - FOR_EACH_OPCODE_ID(ADD_OPCODE_ID); - #undef ADD_OPCODE_ID - ASSERT(m_opcodeIDTable.size() == numOpcodeIDs); + #define LIST_OPCODE_LABEL(id, length) &&id, + static Opcode labels[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL) }; + for (size_t i = 0; i < sizeof(labels) / sizeof(Opcode); ++i) + m_opcodeTable[i] = labels[i]; + #undef LIST_OPCODE_LABEL #endif // HAVE(COMPUTED_GOTO) return JSValue(); } @@ -1306,7 +1352,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int dst = vPC[1].u.operand; JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); - callFrame->r(dst) = jsBoolean(JSValue::strictEqual(src1, src2)); + callFrame->r(dst) = jsBoolean(JSValue::strictEqual(callFrame, src1, src2)); vPC += OPCODE_LENGTH(op_stricteq); NEXT_INSTRUCTION(); @@ -1321,7 +1367,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int dst = vPC[1].u.operand; JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); - callFrame->r(dst) = jsBoolean(!JSValue::strictEqual(src1, src2)); + callFrame->r(dst) = jsBoolean(!JSValue::strictEqual(callFrame, src1, src2)); vPC += OPCODE_LENGTH(op_nstricteq); NEXT_INSTRUCTION(); @@ -1474,7 +1520,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi */ int dst = vPC[1].u.operand; JSValue src = callFrame->r(vPC[2].u.operand).jsValue(); - if (src.isInt32() && src.asInt32()) + if (src.isInt32() && (src.asInt32() & 0x7fffffff)) // non-zero and no overflow callFrame->r(dst) = jsNumber(callFrame, -src.asInt32()); else { JSValue result = jsNumber(callFrame, -src.toNumber(callFrame)); @@ -1495,7 +1541,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int dst = vPC[1].u.operand; JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); - if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() & 0xc0000000)) // no overflow + if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() + src2.asInt32()); else { JSValue result = jsAdd(callFrame, src1, src2); @@ -1582,7 +1628,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int dst = vPC[1].u.operand; JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); - if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() & 0xc0000000)) // no overflow + if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() - src2.asInt32()); else { JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) - src2.toNumber(callFrame)); @@ -2153,6 +2199,93 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi uncacheGetByID(callFrame->codeBlock(), vPC); NEXT_INSTRUCTION(); } +#if HAVE(COMPUTED_GOTO) + goto *(&&skip_id_getter_proto); +#endif + DEFINE_OPCODE(op_get_by_id_getter_proto) { + /* op_get_by_id_getter_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n) + + Cached property access: Attempts to get a cached getter property from the + value base's prototype. If the cache misses, op_get_by_id_getter_proto + reverts to op_get_by_id. + */ + int base = vPC[2].u.operand; + JSValue baseValue = callFrame->r(base).jsValue(); + + if (LIKELY(baseValue.isCell())) { + JSCell* baseCell = asCell(baseValue); + Structure* structure = vPC[4].u.structure; + + if (LIKELY(baseCell->structure() == structure)) { + ASSERT(structure->prototypeForLookup(callFrame).isObject()); + JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame)); + Structure* prototypeStructure = vPC[5].u.structure; + + if (LIKELY(protoObject->structure() == prototypeStructure)) { + int dst = vPC[1].u.operand; + int offset = vPC[6].u.operand; + if (GetterSetter* getterSetter = asGetterSetter(protoObject->getDirectOffset(offset).asCell())) { + JSObject* getter = getterSetter->getter(); + CallData callData; + CallType callType = getter->getCallData(callData); + JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList()); + CHECK_FOR_EXCEPTION(); + callFrame->r(dst) = result; + } else + callFrame->r(dst) = jsUndefined(); + vPC += OPCODE_LENGTH(op_get_by_id_getter_proto); + NEXT_INSTRUCTION(); + } + } + } + uncacheGetByID(callFrame->codeBlock(), vPC); + NEXT_INSTRUCTION(); + } +#if HAVE(COMPUTED_GOTO) + skip_id_getter_proto: +#endif +#if HAVE(COMPUTED_GOTO) + goto *(&&skip_id_custom_proto); +#endif + DEFINE_OPCODE(op_get_by_id_custom_proto) { + /* op_get_by_id_custom_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n) + + Cached property access: Attempts to use a cached named property getter + from the value base's prototype. If the cache misses, op_get_by_id_custom_proto + reverts to op_get_by_id. + */ + int base = vPC[2].u.operand; + JSValue baseValue = callFrame->r(base).jsValue(); + + if (LIKELY(baseValue.isCell())) { + JSCell* baseCell = asCell(baseValue); + Structure* structure = vPC[4].u.structure; + + if (LIKELY(baseCell->structure() == structure)) { + ASSERT(structure->prototypeForLookup(callFrame).isObject()); + JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame)); + Structure* prototypeStructure = vPC[5].u.structure; + + if (LIKELY(protoObject->structure() == prototypeStructure)) { + int dst = vPC[1].u.operand; + int property = vPC[3].u.operand; + Identifier& ident = callFrame->codeBlock()->identifier(property); + + PropertySlot::GetValueFunc getter = vPC[6].u.getterFunc; + JSValue result = getter(callFrame, protoObject, ident); + CHECK_FOR_EXCEPTION(); + callFrame->r(dst) = result; + vPC += OPCODE_LENGTH(op_get_by_id_custom_proto); + NEXT_INSTRUCTION(); + } + } + } + uncacheGetByID(callFrame->codeBlock(), vPC); + NEXT_INSTRUCTION(); + } +#if HAVE(COMPUTED_GOTO) + skip_id_custom_proto: +#endif DEFINE_OPCODE(op_get_by_id_self_list) { // Polymorphic self access caching currently only supported when JITting. ASSERT_NOT_REACHED(); @@ -2167,6 +2300,34 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi vPC += OPCODE_LENGTH(op_get_by_id_proto_list); NEXT_INSTRUCTION(); } + DEFINE_OPCODE(op_get_by_id_getter_self_list) { + // Polymorphic self access caching currently only supported when JITting. + ASSERT_NOT_REACHED(); + // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)! + vPC += OPCODE_LENGTH(op_get_by_id_self_list); + NEXT_INSTRUCTION(); + } + DEFINE_OPCODE(op_get_by_id_getter_proto_list) { + // Polymorphic prototype access caching currently only supported when JITting. + ASSERT_NOT_REACHED(); + // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)! + vPC += OPCODE_LENGTH(op_get_by_id_proto_list); + NEXT_INSTRUCTION(); + } + DEFINE_OPCODE(op_get_by_id_custom_self_list) { + // Polymorphic self access caching currently only supported when JITting. + ASSERT_NOT_REACHED(); + // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)! + vPC += OPCODE_LENGTH(op_get_by_id_custom_self_list); + NEXT_INSTRUCTION(); + } + DEFINE_OPCODE(op_get_by_id_custom_proto_list) { + // Polymorphic prototype access caching currently only supported when JITting. + ASSERT_NOT_REACHED(); + // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)! + vPC += OPCODE_LENGTH(op_get_by_id_proto_list); + NEXT_INSTRUCTION(); + } DEFINE_OPCODE(op_get_by_id_chain) { /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n) @@ -2213,6 +2374,86 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi uncacheGetByID(callFrame->codeBlock(), vPC); NEXT_INSTRUCTION(); } +#if HAVE(COMPUTED_GOTO) + goto *(&&skip_id_getter_self); +#endif + DEFINE_OPCODE(op_get_by_id_getter_self) { + /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n) + + Cached property access: Attempts to get a cached property from the + value base. If the cache misses, op_get_by_id_getter_self reverts to + op_get_by_id. + */ + int base = vPC[2].u.operand; + JSValue baseValue = callFrame->r(base).jsValue(); + + if (LIKELY(baseValue.isCell())) { + JSCell* baseCell = asCell(baseValue); + Structure* structure = vPC[4].u.structure; + + if (LIKELY(baseCell->structure() == structure)) { + ASSERT(baseCell->isObject()); + JSObject* baseObject = asObject(baseCell); + int dst = vPC[1].u.operand; + int offset = vPC[5].u.operand; + + if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) { + JSObject* getter = getterSetter->getter(); + CallData callData; + CallType callType = getter->getCallData(callData); + JSValue result = call(callFrame, getter, callType, callData, baseObject, ArgList()); + CHECK_FOR_EXCEPTION(); + callFrame->r(dst) = result; + } else + callFrame->r(dst) = jsUndefined(); + + vPC += OPCODE_LENGTH(op_get_by_id_getter_self); + NEXT_INSTRUCTION(); + } + } + uncacheGetByID(callFrame->codeBlock(), vPC); + NEXT_INSTRUCTION(); + } +#if HAVE(COMPUTED_GOTO) + skip_id_getter_self: +#endif +#if HAVE(COMPUTED_GOTO) + goto *(&&skip_id_custom_self); +#endif + DEFINE_OPCODE(op_get_by_id_custom_self) { + /* op_get_by_id_custom_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n) + + Cached property access: Attempts to use a cached named property getter + from the value base. If the cache misses, op_get_by_id_custom_self reverts to + op_get_by_id. + */ + int base = vPC[2].u.operand; + JSValue baseValue = callFrame->r(base).jsValue(); + + if (LIKELY(baseValue.isCell())) { + JSCell* baseCell = asCell(baseValue); + Structure* structure = vPC[4].u.structure; + + if (LIKELY(baseCell->structure() == structure)) { + ASSERT(baseCell->isObject()); + int dst = vPC[1].u.operand; + int property = vPC[3].u.operand; + Identifier& ident = callFrame->codeBlock()->identifier(property); + + PropertySlot::GetValueFunc getter = vPC[5].u.getterFunc; + JSValue result = getter(callFrame, baseValue, ident); + CHECK_FOR_EXCEPTION(); + callFrame->r(dst) = result; + vPC += OPCODE_LENGTH(op_get_by_id_custom_self); + NEXT_INSTRUCTION(); + } + } + uncacheGetByID(callFrame->codeBlock(), vPC); + NEXT_INSTRUCTION(); + } +#if HAVE(COMPUTED_GOTO) +skip_id_custom_self: +#endif DEFINE_OPCODE(op_get_by_id_generic) { /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n) @@ -2233,6 +2474,113 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi vPC += OPCODE_LENGTH(op_get_by_id_generic); NEXT_INSTRUCTION(); } +#if HAVE(COMPUTED_GOTO) + goto *(&&skip_id_getter_chain); +#endif + DEFINE_OPCODE(op_get_by_id_getter_chain) { + /* op_get_by_id_getter_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n) + + Cached property access: Attempts to get a cached property from the + value base's prototype chain. If the cache misses, op_get_by_id_getter_chain + reverts to op_get_by_id. + */ + int base = vPC[2].u.operand; + JSValue baseValue = callFrame->r(base).jsValue(); + + if (LIKELY(baseValue.isCell())) { + JSCell* baseCell = asCell(baseValue); + Structure* structure = vPC[4].u.structure; + + if (LIKELY(baseCell->structure() == structure)) { + RefPtr<Structure>* it = vPC[5].u.structureChain->head(); + size_t count = vPC[6].u.operand; + RefPtr<Structure>* end = it + count; + + while (true) { + JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame)); + + if (UNLIKELY(baseObject->structure() != (*it).get())) + break; + + if (++it == end) { + int dst = vPC[1].u.operand; + int offset = vPC[7].u.operand; + if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) { + JSObject* getter = getterSetter->getter(); + CallData callData; + CallType callType = getter->getCallData(callData); + JSValue result = call(callFrame, getter, callType, callData, baseValue, ArgList()); + CHECK_FOR_EXCEPTION(); + callFrame->r(dst) = result; + } else + callFrame->r(dst) = jsUndefined(); + vPC += OPCODE_LENGTH(op_get_by_id_getter_chain); + NEXT_INSTRUCTION(); + } + + // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype. + baseCell = baseObject; + } + } + } + uncacheGetByID(callFrame->codeBlock(), vPC); + NEXT_INSTRUCTION(); + } +#if HAVE(COMPUTED_GOTO) + skip_id_getter_chain: +#endif +#if HAVE(COMPUTED_GOTO) + goto *(&&skip_id_custom_chain); +#endif + DEFINE_OPCODE(op_get_by_id_custom_chain) { + /* op_get_by_id_custom_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n) + + Cached property access: Attempts to use a cached named property getter on the + value base's prototype chain. If the cache misses, op_get_by_id_custom_chain + reverts to op_get_by_id. + */ + int base = vPC[2].u.operand; + JSValue baseValue = callFrame->r(base).jsValue(); + + if (LIKELY(baseValue.isCell())) { + JSCell* baseCell = asCell(baseValue); + Structure* structure = vPC[4].u.structure; + + if (LIKELY(baseCell->structure() == structure)) { + RefPtr<Structure>* it = vPC[5].u.structureChain->head(); + size_t count = vPC[6].u.operand; + RefPtr<Structure>* end = it + count; + + while (true) { + JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame)); + + if (UNLIKELY(baseObject->structure() != (*it).get())) + break; + + if (++it == end) { + int dst = vPC[1].u.operand; + int property = vPC[3].u.operand; + Identifier& ident = callFrame->codeBlock()->identifier(property); + + PropertySlot::GetValueFunc getter = vPC[7].u.getterFunc; + JSValue result = getter(callFrame, baseObject, ident); + CHECK_FOR_EXCEPTION(); + callFrame->r(dst) = result; + vPC += OPCODE_LENGTH(op_get_by_id_custom_chain); + NEXT_INSTRUCTION(); + } + + // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype. + baseCell = baseObject; + } + } + } + uncacheGetByID(callFrame->codeBlock(), vPC); + NEXT_INSTRUCTION(); + } +#if HAVE(COMPUTED_GOTO) + skip_id_custom_chain: +#endif DEFINE_OPCODE(op_get_array_length) { /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n) @@ -2265,7 +2613,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi JSValue baseValue = callFrame->r(base).jsValue(); if (LIKELY(isJSString(globalData, baseValue))) { int dst = vPC[1].u.operand; - callFrame->r(dst) = jsNumber(callFrame, asString(baseValue)->value().size()); + callFrame->r(dst) = jsNumber(callFrame, asString(baseValue)->length()); vPC += OPCODE_LENGTH(op_get_string_length); NEXT_INSTRUCTION(); } @@ -2479,7 +2827,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi else result = jsArray->JSArray::get(callFrame, i); } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) - result = asString(baseValue)->getIndex(&callFrame->globalData(), i); + result = asString(baseValue)->getIndex(callFrame, i); else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) result = asByteArray(baseValue)->getIndex(callFrame, i); else @@ -2647,6 +2995,26 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi vPC += OPCODE_LENGTH(op_loop_if_true); NEXT_INSTRUCTION(); } + DEFINE_OPCODE(op_loop_if_false) { + /* loop_if_true cond(r) target(offset) + + Jumps to offset target from the current instruction, if and + only if register cond converts to boolean as false. + + Additionally this loop instruction may terminate JS execution is + the JS timeout is reached. + */ + int cond = vPC[1].u.operand; + int target = vPC[2].u.operand; + if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) { + vPC += target; + CHECK_FOR_TIMEOUT(); + NEXT_INSTRUCTION(); + } + + vPC += OPCODE_LENGTH(op_loop_if_true); + NEXT_INSTRUCTION(); + } DEFINE_OPCODE(op_jtrue) { /* jtrue cond(r) target(offset) @@ -2707,7 +3075,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int target = vPC[2].u.operand; JSValue srcValue = callFrame->r(src).jsValue(); - if (!srcValue.isUndefinedOrNull() || (srcValue.isCell() && !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) { + if (!srcValue.isUndefinedOrNull() && (!srcValue.isCell() || !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) { vPC += target; NEXT_INSTRUCTION(); } @@ -2810,6 +3178,29 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi vPC += OPCODE_LENGTH(op_jnless); NEXT_INSTRUCTION(); } + DEFINE_OPCODE(op_jless) { + /* jless src1(r) src2(r) target(offset) + + Checks whether register src1 is less than register src2, as + with the ECMAScript '<' operator, and then jumps to offset + target from the current instruction, if and only if the + result of the comparison is true. + */ + JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); + int target = vPC[3].u.operand; + + bool result = jsLess(callFrame, src1, src2); + CHECK_FOR_EXCEPTION(); + + if (result) { + vPC += target; + NEXT_INSTRUCTION(); + } + + vPC += OPCODE_LENGTH(op_jless); + NEXT_INSTRUCTION(); + } DEFINE_OPCODE(op_jnlesseq) { /* jnlesseq src1(r) src2(r) target(offset) @@ -2872,11 +3263,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (!scrutinee.isString()) vPC += defaultOffset; else { - UString::Rep* value = asString(scrutinee)->value().rep(); - if (value->size() != 1) + UString::Rep* value = asString(scrutinee)->value(callFrame).rep(); + if (value->length() != 1) vPC += defaultOffset; else - vPC += callFrame->codeBlock()->characterSwitchJumpTable(tableIndex).offsetForValue(value->data()[0], defaultOffset); + vPC += callFrame->codeBlock()->characterSwitchJumpTable(tableIndex).offsetForValue(value->characters()[0], defaultOffset); } NEXT_INSTRUCTION(); } @@ -2895,7 +3286,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (!scrutinee.isString()) vPC += defaultOffset; else - vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value().rep(), defaultOffset); + vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).rep(), defaultOffset); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_new_func) { @@ -3487,7 +3878,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int src = vPC[2].u.operand; int count = vPC[3].u.operand; - callFrame->r(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count); + callFrame->r(dst) = jsString(callFrame, &callFrame->registers()[src], count); + CHECK_FOR_EXCEPTION(); vPC += OPCODE_LENGTH(op_strcat); NEXT_INSTRUCTION(); diff --git a/src/3rdparty/webkit/JavaScriptCore/interpreter/Register.h b/src/3rdparty/webkit/JavaScriptCore/interpreter/Register.h index 76184ba..ecd7403 100644 --- a/src/3rdparty/webkit/JavaScriptCore/interpreter/Register.h +++ b/src/3rdparty/webkit/JavaScriptCore/interpreter/Register.h @@ -51,17 +51,18 @@ namespace JSC { class Register : public WTF::FastAllocBase { public: Register(); - Register(JSValue); + Register(const JSValue&); + Register& operator=(const JSValue&); JSValue jsValue() const; - Register(JSActivation*); - Register(CallFrame*); - Register(CodeBlock*); - Register(JSFunction*); - Register(JSPropertyNameIterator*); - Register(ScopeChainNode*); - Register(Instruction*); + Register& operator=(JSActivation*); + Register& operator=(CallFrame*); + Register& operator=(CodeBlock*); + Register& operator=(JSFunction*); + Register& operator=(JSPropertyNameIterator*); + Register& operator=(ScopeChainNode*); + Register& operator=(Instruction*); int32_t i() const; JSActivation* activation() const; @@ -75,12 +76,12 @@ namespace JSC { static Register withInt(int32_t i) { - return Register(i); + Register r; + r.u.i = i; + return r; } private: - Register(int32_t); - union { int32_t i; EncodedJSValue value; @@ -98,13 +99,25 @@ namespace JSC { ALWAYS_INLINE Register::Register() { #ifndef NDEBUG - u.value = JSValue::encode(JSValue()); + *this = JSValue(); +#endif + } + + ALWAYS_INLINE Register::Register(const JSValue& v) + { +#if ENABLE(JSC_ZOMBIES) + ASSERT(!v.isZombie()); #endif + u.value = JSValue::encode(v); } - ALWAYS_INLINE Register::Register(JSValue v) + ALWAYS_INLINE Register& Register::operator=(const JSValue& v) { +#if ENABLE(JSC_ZOMBIES) + ASSERT(!v.isZombie()); +#endif u.value = JSValue::encode(v); + return *this; } ALWAYS_INLINE JSValue Register::jsValue() const @@ -114,44 +127,46 @@ namespace JSC { // Interpreter functions - ALWAYS_INLINE Register::Register(JSActivation* activation) + ALWAYS_INLINE Register& Register::operator=(JSActivation* activation) { u.activation = activation; + return *this; } - ALWAYS_INLINE Register::Register(CallFrame* callFrame) + ALWAYS_INLINE Register& Register::operator=(CallFrame* callFrame) { u.callFrame = callFrame; + return *this; } - ALWAYS_INLINE Register::Register(CodeBlock* codeBlock) + ALWAYS_INLINE Register& Register::operator=(CodeBlock* codeBlock) { u.codeBlock = codeBlock; + return *this; } - ALWAYS_INLINE Register::Register(JSFunction* function) + ALWAYS_INLINE Register& Register::operator=(JSFunction* function) { u.function = function; + return *this; } - ALWAYS_INLINE Register::Register(Instruction* vPC) + ALWAYS_INLINE Register& Register::operator=(Instruction* vPC) { u.vPC = vPC; + return *this; } - ALWAYS_INLINE Register::Register(ScopeChainNode* scopeChain) + ALWAYS_INLINE Register& Register::operator=(ScopeChainNode* scopeChain) { u.scopeChain = scopeChain; + return *this; } - ALWAYS_INLINE Register::Register(JSPropertyNameIterator* propertyNameIterator) + ALWAYS_INLINE Register& Register::operator=(JSPropertyNameIterator* propertyNameIterator) { u.propertyNameIterator = propertyNameIterator; - } - - ALWAYS_INLINE Register::Register(int32_t i) - { - u.i = i; + return *this; } ALWAYS_INLINE int32_t Register::i() const diff --git a/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.cpp b/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.cpp index 5424199..510effe 100644 --- a/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.cpp @@ -36,7 +36,7 @@ RegisterFile::~RegisterFile() #if HAVE(MMAP) munmap(m_buffer, ((m_max - m_start) + m_maxGlobals) * sizeof(Register)); #elif HAVE(VIRTUALALLOC) -#if PLATFORM(WINCE) +#if OS(WINCE) VirtualFree(m_buffer, DWORD(m_commitEnd) - DWORD(m_buffer), MEM_DECOMMIT); #endif VirtualFree(m_buffer, 0, MEM_RELEASE); diff --git a/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.h b/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.h index 953c70f..1fc4f82 100644 --- a/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.h +++ b/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.h @@ -176,7 +176,7 @@ namespace JSC { #if HAVE(MMAP) m_buffer = static_cast<Register*>(mmap(0, bufferLength, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, VM_TAG_FOR_REGISTERFILE_MEMORY, 0)); if (m_buffer == MAP_FAILED) { -#if PLATFORM(WINCE) +#if OS(WINCE) fprintf(stderr, "Could not allocate register file: %d\n", GetLastError()); #else fprintf(stderr, "Could not allocate register file: %d\n", errno); @@ -186,7 +186,7 @@ namespace JSC { #elif HAVE(VIRTUALALLOC) m_buffer = static_cast<Register*>(VirtualAlloc(0, roundUpAllocationSize(bufferLength, commitSize), MEM_RESERVE, PAGE_READWRITE)); if (!m_buffer) { -#if PLATFORM(WINCE) +#if OS(WINCE) fprintf(stderr, "Could not allocate register file: %d\n", GetLastError()); #else fprintf(stderr, "Could not allocate register file: %d\n", errno); @@ -196,7 +196,7 @@ namespace JSC { size_t committedSize = roundUpAllocationSize(maxGlobals * sizeof(Register), commitSize); void* commitCheck = VirtualAlloc(m_buffer, committedSize, MEM_COMMIT, PAGE_READWRITE); if (commitCheck != m_buffer) { -#if PLATFORM(WINCE) +#if OS(WINCE) fprintf(stderr, "Could not allocate register file: %d\n", GetLastError()); #else fprintf(stderr, "Could not allocate register file: %d\n", errno); @@ -242,7 +242,7 @@ namespace JSC { if (newEnd > m_commitEnd) { size_t size = roundUpAllocationSize(reinterpret_cast<char*>(newEnd) - reinterpret_cast<char*>(m_commitEnd), commitSize); if (!VirtualAlloc(m_commitEnd, size, MEM_COMMIT, PAGE_READWRITE)) { -#if PLATFORM(WINCE) +#if OS(WINCE) fprintf(stderr, "Could not allocate register file: %d\n", GetLastError()); #else fprintf(stderr, "Could not allocate register file: %d\n", errno); |