summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/webkit/JavaScriptCore/interpreter
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/webkit/JavaScriptCore/interpreter')
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/interpreter/CachedCall.h11
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/interpreter/CallFrame.h23
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/interpreter/Interpreter.cpp468
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/interpreter/Register.h65
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.cpp2
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.h8
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);