1. implement instanceof, in, delete operator

2. VariableDeclaratorNode does not affect execute result
3. optimize Object get, set in interpreter

Signed-off-by: seonghyun kim <sh8281.kim@samsung.com>
This commit is contained in:
seonghyun kim 2016-12-20 13:30:21 +09:00
commit 11e625f373
26 changed files with 386 additions and 114 deletions

View file

@ -47,6 +47,8 @@ class Node;
F(BinaryLeftShift, 1, 2) \
F(BinarySignedRightShift, 1, 2) \
F(BinaryUnsignedRightShift, 1, 2) \
F(BinaryInOperation, 1, 2) \
F(BinaryInstanceOfOperation, 1, 2) \
F(CreateObject, 1, 0) \
F(CreateArray, 1, 0) \
F(GetObject, 1, 2) \
@ -63,6 +65,7 @@ class Node;
F(UnaryNot, 1, 1) \
F(UnaryBitwiseNot, 1, 1) \
F(UnaryTypeof, 1, 1) \
F(UnaryDelete, 1, 1) \
F(Jump, 0, 0) \
F(JumpComplexCase, 0, 0) \
F(JumpIfTrue, 0, 0) \
@ -79,6 +82,7 @@ class Node;
F(LoadRegexp, 1, 0) \
F(CallNativeFunction, 0, 0) \
F(CallEvalFunction, 0, 0) \
F(ResetExecuteResult, 0, 0) \
F(End, 0, 0)
enum Opcode {
@ -526,6 +530,8 @@ DEFINE_BINARY_OPERATION(BitwiseXor, "bitwise Xor");
DEFINE_BINARY_OPERATION(LeftShift, "left shift");
DEFINE_BINARY_OPERATION(SignedRightShift, "signed right shift");
DEFINE_BINARY_OPERATION(UnsignedRightShift, "unsigned right shift");
DEFINE_BINARY_OPERATION(InOperation, "in operation");
DEFINE_BINARY_OPERATION(InstanceOfOperation, "instance of");
class CreateObject : public ByteCode {
@ -606,7 +612,21 @@ public:
};
typedef Vector<std::pair<ObjectStructure*, size_t>, gc_malloc_ignore_off_page_allocator<std::pair<ObjectStructure*, size_t>>> ObjectStructureChain;
struct ObjectStructureChainItem : public gc {
ObjectStructure* m_objectStructure;
size_t m_version;
bool operator==(const ObjectStructureChainItem& item) const
{
return m_objectStructure == item.m_objectStructure && m_version == item.m_version;
}
bool operator!=(const ObjectStructureChainItem& item) const
{
return !operator==(item);
}
};
typedef Vector<ObjectStructureChainItem, gc_malloc_ignore_off_page_allocator<ObjectStructureChainItem>> ObjectStructureChain;
struct GetObjectInlineCacheData {
GetObjectInlineCacheData()
@ -875,6 +895,28 @@ public:
#endif
};
class UnaryDelete : public ByteCode {
public:
UnaryDelete(const ByteCodeLOC& loc, const size_t& registerIndex0, const size_t& registerIndex1, AtomicString name)
: ByteCode(Opcode::UnaryDeleteOpcode, loc)
, m_registerIndex0(registerIndex0)
, m_registerIndex1(registerIndex1)
, m_id(name)
{
}
size_t m_registerIndex0;
size_t m_registerIndex1;
AtomicString m_id;
#ifndef NDEBUG
virtual void dump()
{
printf("unary delete r%d r%d %s", (int)m_registerIndex0, (int)m_registerIndex1, m_id.string()->toUTF8StringData().data());
}
#endif
};
class Jump : public ByteCode {
public:
Jump(const ByteCodeLOC& loc, size_t pos = SIZE_MAX)
@ -1236,6 +1278,21 @@ public:
NativeFunctionPointer m_fn;
};
class ResetExecuteResult : public ByteCode {
public:
ResetExecuteResult(const ByteCodeLOC& loc)
: ByteCode(Opcode::ResetExecuteResultOpcode, loc)
{
}
#ifndef NDEBUG
virtual void dump()
{
printf("reset execute result");
}
#endif
};
class End : public ByteCode {
public:
End(const ByteCodeLOC& loc)

View file

@ -782,7 +782,10 @@ void ByteCodeInterpreter::interpret(ExecutionState& state, CodeBlock* codeBlock,
Object* obj = data->m_object;
for (size_t i = 0; i < data->m_hiddenClassChain.size(); i++) {
auto hc = data->m_hiddenClassChain[i];
if (hc.first != obj->structure() && hc.second == obj->structure()->version()) {
ObjectStructureChainItem testItem;
testItem.m_objectStructure = obj->structure();
testItem.m_version = obj->structure()->version();
if (hc != testItem) {
shouldUpdateEnumerateObjectData = true;
break;
}
@ -823,6 +826,34 @@ void ByteCodeInterpreter::interpret(ExecutionState& state, CodeBlock* codeBlock,
NEXT_INSTRUCTION();
}
UnaryDeleteOpcodeLbl : {
UnaryDelete* code = (UnaryDelete*)currentCode;
if (code->m_id.string()->length()) {
registerFile[code->m_registerIndex0] = Value(env->deleteBinding(state, code->m_id));
} else {
const Value& o = registerFile[code->m_registerIndex0];
const Value& p = registerFile[code->m_registerIndex1];
registerFile[code->m_registerIndex0] = Value(o.toObject(state)->deleteOwnProperty(state, ObjectPropertyName(state, p)));
}
ADD_PROGRAM_COUNTER(UnaryDelete);
NEXT_INSTRUCTION();
}
BinaryInOperationOpcodeLbl : {
BinaryInOperation* code = (BinaryInOperation*)currentCode;
auto result = registerFile[code->m_srcIndex1].toObject(state)->get(state, ObjectPropertyName(state, registerFile[code->m_srcIndex0]));
registerFile[code->m_srcIndex0] = Value(result.hasValue());
ADD_PROGRAM_COUNTER(BinaryInOperation);
NEXT_INSTRUCTION();
}
BinaryInstanceOfOperationOpcodeLbl : {
BinaryInstanceOfOperation* code = (BinaryInstanceOfOperation*)currentCode;
registerFile[code->m_srcIndex0] = instanceOfOperation(state, registerFile[code->m_srcIndex0], registerFile[code->m_srcIndex1]);
ADD_PROGRAM_COUNTER(BinaryInstanceOfOperation);
NEXT_INSTRUCTION();
}
LoadByGlobalNameOpcodeLbl : {
LoadByGlobalName* code = (LoadByGlobalName*)currentCode;
GlobalObject* g = state.context()->globalObject();
@ -856,6 +887,12 @@ void ByteCodeInterpreter::interpret(ExecutionState& state, CodeBlock* codeBlock,
NEXT_INSTRUCTION();
}
ResetExecuteResultOpcodeLbl : {
registerFile[0] = Value();
ADD_PROGRAM_COUNTER(ResetExecuteResult);
NEXT_INSTRUCTION();
}
} catch (const Value& v) {
if (state.context()->m_sandBoxStack.size()) {
SandBox* sb = state.context()->m_sandBoxStack.back();
@ -1035,6 +1072,31 @@ Value ByteCodeInterpreter::newOperation(ExecutionState& state, const Value& call
return receiver;
}
Value ByteCodeInterpreter::instanceOfOperation(ExecutionState& state, const Value& left, const Value& right)
{
if (!right.isFunction()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, errorMessage_InstanceOf_NotFunction);
}
if (left.isObject()) {
FunctionObject* C = right.asFunction();
// while (C->isBoundFunc())
// C = C->codeBlock()->peekCode<CallBoundFunction>(0)->m_boundTargetFunction;
Value P = C->getFunctionPrototype(state);
Value O = left.asObject()->getPrototype(state);
if (P.isObject()) {
while (!O.isUndefinedOrNull()) {
if (P == O) {
return Value(true);
}
O = O.asObject()->getPrototype(state);
}
} else {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, errorMessage_InstanceOf_InvalidPrototypeProperty);
}
}
return Value(false);
}
inline bool ByteCodeInterpreter::abstractRelationalComparison(ExecutionState& state, const Value& left, const Value& right, bool leftFirst)
{
// consume very fast case
@ -1114,6 +1176,9 @@ ALWAYS_INLINE std::pair<bool, Value> ByteCodeInterpreter::getObjectPrecomputedCa
{
Object* targetObj = obj;
unsigned currentCacheIndex = 0;
ObjectStructureChainItem testItem;
testItem.m_objectStructure = obj->structure();
testItem.m_version = obj->structure()->version();
const size_t cacheFillCount = inlineCache.m_cache.size();
for (; currentCacheIndex < cacheFillCount; currentCacheIndex++) {
const GetObjectInlineCacheData& data = inlineCache.m_cache[currentCacheIndex];
@ -1121,7 +1186,9 @@ ALWAYS_INLINE std::pair<bool, Value> ByteCodeInterpreter::getObjectPrecomputedCa
const size_t& cachedIndex = data.m_cachedIndex;
const size_t cSiz = cachedHiddenClassChain->size() - 1;
for (size_t i = 0; i < cSiz; i++) {
if (UNLIKELY((*cachedHiddenClassChain)[i].first != obj->structure() || (*cachedHiddenClassChain)[i].second != obj->structure()->version())) {
testItem.m_objectStructure = obj->structure();
testItem.m_version = obj->structure()->version();
if (UNLIKELY((*cachedHiddenClassChain)[i] != testItem)) {
return getObjectPrecomputedCaseOperationCacheMiss(state, targetObj, name, inlineCache);
}
const Value& proto = obj->getPrototype(state);
@ -1131,7 +1198,10 @@ ALWAYS_INLINE std::pair<bool, Value> ByteCodeInterpreter::getObjectPrecomputedCa
return getObjectPrecomputedCaseOperationCacheMiss(state, targetObj, name, inlineCache);
}
}
if (LIKELY((*cachedHiddenClassChain)[cSiz].first == obj->structure() && (*cachedHiddenClassChain)[cSiz].second == obj->structure()->version())) {
testItem.m_objectStructure = obj->structure();
testItem.m_version = obj->structure()->version();
if (LIKELY((*cachedHiddenClassChain)[cSiz] == testItem)) {
if (LIKELY(cachedIndex != SIZE_MAX)) {
return std::make_pair(true, obj->getOwnPropertyUtilForObject(state, cachedIndex, targetObj));
} else {
@ -1160,8 +1230,13 @@ std::pair<bool, Value> ByteCodeInterpreter::getObjectPrecomputedCaseOperationCac
ASSERT(&inlineCache.m_cache[0] == &inlineCache.m_cache[0]);
ObjectStructureChain* cachedHiddenClassChain = &inlineCache.m_cache[0].m_cachedhiddenClassChain;
size_t* cachedHiddenClassIndex = &inlineCache.m_cache[0].m_cachedIndex;
ObjectStructureChainItem newItem;
while (true) {
cachedHiddenClassChain->push_back(std::make_pair(obj->structure(), obj->structure()->version()));
newItem.m_objectStructure = obj->structure();
newItem.m_version = obj->structure()->version();
cachedHiddenClassChain->push_back(newItem);
size_t idx = obj->structure()->findProperty(state, name);
if (idx != SIZE_MAX) {
*cachedHiddenClassIndex = idx;
@ -1184,7 +1259,12 @@ std::pair<bool, Value> ByteCodeInterpreter::getObjectPrecomputedCaseOperationCac
ALWAYS_INLINE void ByteCodeInterpreter::setObjectPreComputedCaseOperation(ExecutionState& state, Object* obj, const PropertyName& name, const Value& value, SetObjectInlineCache& inlineCache)
{
Object* originalObject = obj;
if (inlineCache.m_cachedIndex != SIZE_MAX && inlineCache.m_cachedhiddenClassChain[0].first == obj->structure() && inlineCache.m_cachedhiddenClassChain[0].second == obj->structure()->version()) {
ObjectStructureChainItem testItem;
testItem.m_objectStructure = obj->structure();
testItem.m_version = obj->structure()->version();
if (inlineCache.m_cachedIndex != SIZE_MAX && inlineCache.m_cachedhiddenClassChain[0] == testItem) {
ASSERT(inlineCache.m_cachedhiddenClassChain.size() == 1);
// cache hit!
obj->setOwnPropertyThrowsExceptionWhenStrictMode(state, inlineCache.m_cachedIndex, value);
@ -1193,7 +1273,7 @@ ALWAYS_INLINE void ByteCodeInterpreter::setObjectPreComputedCaseOperation(Execut
int cSiz = inlineCache.m_cachedhiddenClassChain.size();
bool miss = false;
for (int i = 0; i < cSiz - 1; i++) {
if (inlineCache.m_cachedhiddenClassChain[i].first != obj->structure()) {
if (inlineCache.m_cachedhiddenClassChain[i].m_objectStructure != obj->structure()) {
miss = true;
break;
} else {
@ -1206,7 +1286,7 @@ ALWAYS_INLINE void ByteCodeInterpreter::setObjectPreComputedCaseOperation(Execut
}
}
if (!miss) {
if (inlineCache.m_cachedhiddenClassChain[cSiz - 1].first == obj->structure()) {
if (inlineCache.m_cachedhiddenClassChain[cSiz - 1].m_objectStructure == obj->structure()) {
// cache hit!
obj = originalObject;
ASSERT(!obj->structure()->isStructureWithFastAccess());
@ -1230,8 +1310,13 @@ void ByteCodeInterpreter::setObjectPreComputedCaseOperationCacheMiss(ExecutionSt
size_t idx = obj->structure()->findProperty(state, name);
if (idx != SIZE_MAX) {
// own property
ObjectStructureChainItem newItem;
newItem.m_objectStructure = obj->structure();
newItem.m_version = obj->structure()->version();
inlineCache.m_cachedIndex = idx;
inlineCache.m_cachedhiddenClassChain.push_back(std::make_pair(obj->structure(), obj->structure()->version()));
inlineCache.m_cachedhiddenClassChain.push_back(newItem);
obj->setOwnPropertyThrowsExceptionWhenStrictMode(state, inlineCache.m_cachedIndex, value);
} else {
Object* orgObject = obj;
@ -1240,7 +1325,11 @@ void ByteCodeInterpreter::setObjectPreComputedCaseOperationCacheMiss(ExecutionSt
orgObject->setThrowsExceptionWhenStrictMode(state, ObjectPropertyName(state, name), value, orgObject);
return;
}
inlineCache.m_cachedhiddenClassChain.push_back(std::make_pair(obj->structure(), obj->structure()->version()));
ASSERT(obj->structure()->version() == 0);
ObjectStructureChainItem newItem;
newItem.m_objectStructure = obj->structure();
newItem.m_version = obj->structure()->version();
inlineCache.m_cachedhiddenClassChain.push_back(newItem);
Value proto = obj->getPrototype(state);
while (proto.isObject()) {
obj = proto.asObject();
@ -1249,7 +1338,9 @@ void ByteCodeInterpreter::setObjectPreComputedCaseOperationCacheMiss(ExecutionSt
orgObject->setThrowsExceptionWhenStrictMode(state, ObjectPropertyName(state, name), value, orgObject);
return;
}
inlineCache.m_cachedhiddenClassChain.push_back(std::make_pair(obj->structure(), obj->structure()->version()));
newItem.m_objectStructure = obj->structure();
newItem.m_version = obj->structure()->version();
inlineCache.m_cachedhiddenClassChain.push_back(newItem);
proto = obj->getPrototype(state);
}
bool s = orgObject->set(state, ObjectPropertyName(state, name), value, obj);
@ -1285,7 +1376,11 @@ EnumerateObjectData* ByteCodeInterpreter::executeEnumerateObject(ExecutionState&
}
return true;
});
data->m_hiddenClassChain.push_back(std::make_pair(target.asObject()->structure(), target.asObject()->structure()->version()));
ObjectStructureChainItem newItem;
newItem.m_objectStructure = target.asObject()->structure();
newItem.m_version = target.asObject()->structure()->version();
data->m_hiddenClassChain.push_back(newItem);
std::unordered_set<String*, std::hash<String*>, std::equal_to<String*>, gc_malloc_ignore_off_page_allocator<String*>> keyStringSet;
@ -1300,7 +1395,9 @@ EnumerateObjectData* ByteCodeInterpreter::executeEnumerateObject(ExecutionState&
return true;
});
}
data->m_hiddenClassChain.push_back(std::make_pair(target.asObject()->structure(), target.asObject()->structure()->version()));
newItem.m_objectStructure = target.asObject()->structure();
newItem.m_version = target.asObject()->structure()->version();
data->m_hiddenClassChain.push_back(newItem);
target = target.asObject()->getPrototype(state);
}

View file

@ -20,6 +20,7 @@ public:
static Value plusSlowCase(ExecutionState& state, const Value& a, const Value& b);
static Value modOperation(ExecutionState& state, const Value& left, const Value& right);
static Value newOperation(ExecutionState& state, const Value& callee, size_t argc, Value* argv);
static Value instanceOfOperation(ExecutionState& state, const Value& left, const Value& right);
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.8.5
static bool abstractRelationalComparisonSlowCase(ExecutionState& state, const Value& left, const Value& right, bool leftFirst);

View file

@ -30,6 +30,18 @@ public:
m_right = (ExpressionNode*)right;
}
virtual void generateExpressionByteCode(ByteCodeBlock* codeBlock, ByteCodeGenerateContext* context)
{
m_left->generateExpressionByteCode(codeBlock, context);
m_right->generateExpressionByteCode(codeBlock, context);
size_t src1 = context->getLastRegisterIndex();
context->giveUpRegister();
size_t src0 = context->getLastRegisterIndex();
codeBlock->pushCode(BinaryInOperation(ByteCodeLOC(m_loc.index), src0, src1), context, this);
}
virtual ASTNodeType type() { return ASTNodeType::BinaryExpressionIn; }
protected:
ExpressionNode* m_left;

View file

@ -31,6 +31,18 @@ public:
}
virtual ASTNodeType type() { return ASTNodeType::BinaryExpressionInstanceOf; }
virtual void generateExpressionByteCode(ByteCodeBlock* codeBlock, ByteCodeGenerateContext* context)
{
m_left->generateExpressionByteCode(codeBlock, context);
m_right->generateExpressionByteCode(codeBlock, context);
size_t src1 = context->getLastRegisterIndex();
context->giveUpRegister();
size_t src0 = context->getLastRegisterIndex();
codeBlock->pushCode(BinaryInstanceOfOperation(ByteCodeLOC(m_loc.index), src0, src1), context, this);
}
protected:
ExpressionNode* m_left;
ExpressionNode* m_right;

View file

@ -33,6 +33,16 @@ public:
m_computed = computed;
}
Node* object()
{
return m_object;
}
Node* property()
{
return m_property;
}
virtual ASTNodeType type() { return ASTNodeType::MemberExpression; }
bool isPreComputedCase()
{

View file

@ -37,12 +37,12 @@ public:
ASTScopeContext* scopeContext() { return m_scopeContext; }
virtual void generateStatementByteCode(ByteCodeBlock* codeBlock, ByteCodeGenerateContext* context)
{
codeBlock->pushCode(ResetExecuteResult(ByteCodeLOC(SIZE_MAX)), context, this);
size_t len = m_body.size();
for (size_t i = 0; i < len; i++) {
m_body[i]->generateStatementByteCode(codeBlock, context);
}
codeBlock->pushCode(End(ByteCodeLOC(SIZE_MAX)), context, this);
}

View file

@ -31,6 +31,46 @@ public:
}
virtual ASTNodeType type() { return ASTNodeType::UnaryExpressionDelete; }
virtual void generateExpressionByteCode(ByteCodeBlock* codeBlock, ByteCodeGenerateContext* context)
{
size_t base = context->m_baseRegisterCount;
if (m_argument->isIdentifier()) {
AtomicString name = m_argument->asIdentifier()->name();
bool nameCase = false;
if (!context->m_codeBlock->canUseIndexedVariableStorage()) {
nameCase = true;
} else {
CodeBlock::IndexedIdentifierInfo info = context->m_codeBlock->indexedIdentifierInfo(name);
if (!info.m_isResultSaved) {
nameCase = true;
}
}
if (nameCase) {
codeBlock->pushCode(UnaryDelete(ByteCodeLOC(m_loc.index), context->getRegister(), SIZE_MAX, name), context, this);
} else {
codeBlock->pushCode(LoadLiteral(ByteCodeLOC(m_loc.index), context->getRegister(), Value(false)), context, this);
}
} else if (m_argument->isMemberExpression()) {
((MemberExpressionNode*)m_argument)->object()->generateExpressionByteCode(codeBlock, context);
size_t o = context->getLastRegisterIndex();
if (((MemberExpressionNode*)m_argument)->isPreComputedCase())
codeBlock->pushCode(LoadLiteral(ByteCodeLOC(m_loc.index), context->getRegister(), Value(((MemberExpressionNode*)m_argument)->property()->asIdentifier()->name().string())), context, this);
else
((MemberExpressionNode*)m_argument)->property()->generateExpressionByteCode(codeBlock, context);
size_t p = context->getLastRegisterIndex();
codeBlock->pushCode(UnaryDelete(ByteCodeLOC(m_loc.index), o, p, AtomicString()), context, this);
context->giveUpRegister();
} else {
m_argument->generateExpressionByteCode(codeBlock, context);
context->giveUpRegister();
codeBlock->pushCode(LoadLiteral(ByteCodeLOC(m_loc.index), context->getRegister(), Value(true)), context, this);
}
ASSERT(base + 1 == context->m_baseRegisterCount);
}
protected:
ExpressionNode* m_argument;
};

View file

@ -44,9 +44,11 @@ public:
if (!context->m_codeBlock->hasName(name))
codeBlock->pushCode(DeclareVarVariable(ByteCodeLOC(m_loc.index), name), context, this);
if (m_init) {
context->getRegister();
m_init->generateExpressionByteCode(codeBlock, context);
m_id->generateStoreByteCode(codeBlock, context);
context->giveUpRegister();
context->giveUpRegister();
}
}

View file

@ -3763,7 +3763,7 @@ public:
this->context->isAssignmentTarget = false;
this->context->isBindingElement = false;
if (exprOld->isIdentifier()) {
if (this->context->strict && exprOld->isIdentifier()) {
this->tolerateError(Messages::StrictDelete);
}
} else if (this->matchKeyword(Void)) {
@ -3911,7 +3911,7 @@ public:
while ((stack.size() > 2) && (prec <= ((ScannerResult*)stack[stack.size() - 2])->prec)) {
right = (Node*)stack.back();
stack.pop_back();
PunctuatorsKind operator_ = ((ScannerResult*)stack.back())->valuePunctuatorsKind;
ScannerResult* operator_ = ((ScannerResult*)stack.back());
stack.pop_back();
left = (Node*)stack.back();
stack.pop_back();
@ -3934,7 +3934,7 @@ public:
markers.pop_back();
while (i > 1) {
MetaNode node = this->startNode(markers.back());
expr = this->finalize(node, finishBinaryExpression((Node*)stack[i - 2], expr, ((ScannerResult*)stack[i - 1])->valuePunctuatorsKind));
expr = this->finalize(node, finishBinaryExpression((Node*)stack[i - 2], expr, ((ScannerResult*)stack[i - 1])));
i -= 2;
}
}
@ -3942,70 +3942,74 @@ public:
return expr;
}
Node* finishBinaryExpression(Node* left, Node* right, PunctuatorsKind oper)
Node* finishBinaryExpression(Node* left, Node* right, ScannerResult* token)
{
// Additive Operators
Node* nd;
if (oper == Plus)
nd = new BinaryExpressionPlusNode(left, right);
else if (oper == Minus)
nd = new BinaryExpressionMinusNode(left, right);
if (token->type == Token::PunctuatorToken) {
PunctuatorsKind oper = token->valuePunctuatorsKind;
// Additive Operators
if (oper == Plus)
nd = new BinaryExpressionPlusNode(left, right);
else if (oper == Minus)
nd = new BinaryExpressionMinusNode(left, right);
// Bitwise Shift Operators
else if (oper == LeftShift)
nd = new BinaryExpressionLeftShiftNode(left, right);
else if (oper == RightShift)
nd = new BinaryExpressionSignedRightShiftNode(left, right);
else if (oper == UnsignedRightShift)
nd = new BinaryExpressionUnsignedRightShiftNode(left, right);
// Bitwise Shift Operators
else if (oper == LeftShift)
nd = new BinaryExpressionLeftShiftNode(left, right);
else if (oper == RightShift)
nd = new BinaryExpressionSignedRightShiftNode(left, right);
else if (oper == UnsignedRightShift)
nd = new BinaryExpressionUnsignedRightShiftNode(left, right);
// Multiplicative Operators
else if (oper == Multiply)
nd = new BinaryExpressionMultiplyNode(left, right);
else if (oper == Divide)
nd = new BinaryExpressionDivisionNode(left, right);
else if (oper == Mod)
nd = new BinaryExpressionModNode(left, right);
// Multiplicative Operators
else if (oper == Multiply)
nd = new BinaryExpressionMultiplyNode(left, right);
else if (oper == Divide)
nd = new BinaryExpressionDivisionNode(left, right);
else if (oper == Mod)
nd = new BinaryExpressionModNode(left, right);
// Relational Operators
else if (oper == LeftInequality)
nd = new BinaryExpressionLessThanNode(left, right);
else if (oper == RightInequality)
nd = new BinaryExpressionGreaterThanNode(left, right);
else if (oper == LeftInequalityEqual)
nd = new BinaryExpressionLessThanOrEqualNode(left, right);
else if (oper == RightInequalityEqual)
nd = new BinaryExpressionGreaterThanOrEqualNode(left, right);
// Relational Operators
else if (oper == LeftInequality)
nd = new BinaryExpressionLessThanNode(left, right);
else if (oper == RightInequality)
nd = new BinaryExpressionGreaterThanNode(left, right);
else if (oper == LeftInequalityEqual)
nd = new BinaryExpressionLessThanOrEqualNode(left, right);
else if (oper == RightInequalityEqual)
nd = new BinaryExpressionGreaterThanOrEqualNode(left, right);
// Equality Operators
else if (oper == Equal)
nd = new BinaryExpressionEqualNode(left, right);
else if (oper == NotEqual)
nd = new BinaryExpressionNotEqualNode(left, right);
else if (oper == StrictEqual)
nd = new BinaryExpressionStrictEqualNode(left, right);
else if (oper == NotStrictEqual)
nd = new BinaryExpressionNotStrictEqualNode(left, right);
// Binary Bitwise Operator
else if (oper == BitwiseAnd)
nd = new BinaryExpressionBitwiseAndNode(left, right);
else if (oper == BitwiseXor)
nd = new BinaryExpressionBitwiseXorNode(left, right);
else if (oper == BitwiseOr)
nd = new BinaryExpressionBitwiseOrNode(left, right);
else if (oper == LogicalOr)
nd = new BinaryExpressionLogicalOrNode(left, right);
else if (oper == LogicalAnd)
nd = new BinaryExpressionLogicalAndNode(left, right);
else if (oper == InPunctuator)
nd = new BinaryExpressionInNode(left, right);
else if (oper == InstanceOfPunctuator)
nd = new BinaryExpressionInstanceOfNode(left, right);
// TODO
else
RELEASE_ASSERT_NOT_REACHED();
// Equality Operators
else if (oper == Equal)
nd = new BinaryExpressionEqualNode(left, right);
else if (oper == NotEqual)
nd = new BinaryExpressionNotEqualNode(left, right);
else if (oper == StrictEqual)
nd = new BinaryExpressionStrictEqualNode(left, right);
else if (oper == NotStrictEqual)
nd = new BinaryExpressionNotStrictEqualNode(left, right);
// Binary Bitwise Operator
else if (oper == BitwiseAnd)
nd = new BinaryExpressionBitwiseAndNode(left, right);
else if (oper == BitwiseXor)
nd = new BinaryExpressionBitwiseXorNode(left, right);
else if (oper == BitwiseOr)
nd = new BinaryExpressionBitwiseOrNode(left, right);
else if (oper == LogicalOr)
nd = new BinaryExpressionLogicalOrNode(left, right);
else if (oper == LogicalAnd)
nd = new BinaryExpressionLogicalAndNode(left, right);
else
RELEASE_ASSERT_NOT_REACHED();
} else {
if (token->valueKeywordKind == KeywordKind::In)
nd = new BinaryExpressionInNode(left, right);
else if (token->valueKeywordKind == KeywordKind::InstanceofKeyword)
nd = new BinaryExpressionInstanceOfNode(left, right);
else
RELEASE_ASSERT_NOT_REACHED();
}
return nd;
}

View file

@ -40,7 +40,7 @@ bool ArrayObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyN
return Object::defineOwnProperty(state, P, desc);
}
void ArrayObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
bool ArrayObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
if (LIKELY(isFastModeArray())) {
uint32_t idx;
@ -54,7 +54,7 @@ void ArrayObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyN
ASSERT(len == getLength(state));
if (idx < len) {
m_fastModeData[idx] = Value(Value::EmptyValue);
return;
return true;
}
}
}

View file

@ -41,7 +41,7 @@ public:
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void enumeration(ExecutionState& state, std::function<bool(const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc)> callback) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual uint32_t length(ExecutionState& state)
{

View file

@ -40,6 +40,18 @@ public:
}
}
bool deleteBinding(ExecutionState& state, const AtomicString& name)
{
LexicalEnvironment* env = this;
while (env) {
if (LIKELY(env->record()->hasBinding(state, name).m_index != SIZE_MAX)) {
return env->record()->deleteBinding(state, name);
}
env = env->outerEnvironment();
}
return true;
}
protected:
EnvironmentRecord* m_record;
LexicalEnvironment* m_outerEnvironment;

View file

@ -59,6 +59,16 @@ void GlobalEnvironmentRecord::setMutableBinding(ExecutionState& state, const Ato
m_globalObject->setThrowsExceptionWhenStrictMode(state, name, V, m_globalObject);
}
bool GlobalEnvironmentRecord::deleteBinding(ExecutionState& state, const AtomicString& name)
{
return m_globalObject->deleteOwnProperty(state, name);
}
EnvironmentRecord::BindingSlot GlobalEnvironmentRecord::hasBinding(ExecutionState& state, const AtomicString& atomicName)
{
return EnvironmentRecord::BindingSlot(this, m_globalObject->findPropertyIndex(state, atomicName));
}
void DeclarativeEnvironmentRecordNotIndexded::createMutableBinding(ExecutionState& state, const AtomicString& name, bool canDelete)
{
ASSERT(canDelete == false);

View file

@ -169,6 +169,11 @@ public:
return false;
}
virtual bool deleteBinding(ExecutionState& state, const AtomicString& name)
{
return m_bindingObject->deleteOwnProperty(state, name);
}
protected:
Object* m_bindingObject;
};
@ -192,6 +197,8 @@ public:
virtual void createMutableBinding(ExecutionState& state, const AtomicString& name, bool canDelete = false);
virtual GetBindingValueResult getBindingValue(ExecutionState& state, const AtomicString& name);
virtual void setMutableBinding(ExecutionState& state, const AtomicString& name, const Value& V);
virtual bool deleteBinding(ExecutionState& state, const AtomicString& name);
virtual BindingSlot hasBinding(ExecutionState& state, const AtomicString& atomicName);
CodeBlock* globalCodeBlock()
{

View file

@ -18,6 +18,8 @@ const char* errorMessage_Get_FromNull = "Cannot get property '%s' of null";
const char* errorMessage_Set_ToUndefined = "Cannot set property '%s' of undefined";
const char* errorMessage_Set_ToNull = "Cannot set property '%s' of null";
const char* errorMessage_New_NotConstructor = "%s is not a constructor";
const char* errorMessage_InstanceOf_NotFunction = "Invalid operand to 'instanceof': Callee is not a function object";
const char* errorMessage_InstanceOf_InvalidPrototypeProperty = "instanceof called on an object with an invalid prototype property";
const char* errorMessage_ArgumentsOrCaller_InStrictMode = "'caller' and 'arguments' are restricted function properties and cannot be accessed in this context.";
const char* errorMessage_GlobalObject_ThisUndefinedOrNull = "%s: this value is undefined or null";
const char* errorMessage_GlobalObject_ThisNotObject = "%s: this value is not an object";

View file

@ -20,6 +20,8 @@ extern const char* errorMessage_Get_FromNull;
extern const char* errorMessage_Set_ToUndefined;
extern const char* errorMessage_Set_ToNull;
extern const char* errorMessage_New_NotConstructor;
extern const char* errorMessage_InstanceOf_NotFunction;
extern const char* errorMessage_InstanceOf_InvalidPrototypeProperty;
extern const char* errorMessage_ArgumentsOrCaller_InStrictMode;
extern const char* errorMessage_GlobalObject_ThisUndefinedOrNull;
extern const char* errorMessage_GlobalObject_ThisNotObject;

View file

@ -186,22 +186,22 @@ void GlobalObject::installOthers(ExecutionState& state)
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().parseInt),
ObjectPropertyDescriptor(new FunctionObject(state,
NativeFunctionInfo(state.context()->staticStrings().parseInt, builtinParseInt, 2, nullptr, NativeFunctionInfo::Strict), false),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
NativeFunctionInfo(state.context()->staticStrings().parseInt, builtinParseInt, 2, nullptr, NativeFunctionInfo::Strict), false),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
#ifdef ESCARGOT_SHELL
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().print),
ObjectPropertyDescriptor(new FunctionObject(state,
NativeFunctionInfo(state.context()->staticStrings().print, builtinPrint, 1, nullptr, NativeFunctionInfo::Strict), false),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
NativeFunctionInfo(state.context()->staticStrings().print, builtinPrint, 1, nullptr, NativeFunctionInfo::Strict), false),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().load),
ObjectPropertyDescriptor(new FunctionObject(state,
NativeFunctionInfo(state.context()->staticStrings().load, builtinLoad, 1, nullptr, NativeFunctionInfo::Strict), false),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
NativeFunctionInfo(state.context()->staticStrings().load, builtinLoad, 1, nullptr, NativeFunctionInfo::Strict), false),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
#endif
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().gc),
ObjectPropertyDescriptor(new FunctionObject(state,
NativeFunctionInfo(state.context()->staticStrings().gc, builtinGc, 0, nullptr, NativeFunctionInfo::Strict), false),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
NativeFunctionInfo(state.context()->staticStrings().gc, builtinGc, 0, nullptr, NativeFunctionInfo::Strict), false),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
#ifdef PROFILE_BDWGC
AtomicString dumpBackTrace(state, "dumpBackTrace");

View file

@ -23,6 +23,7 @@ class FunctionObject;
class GlobalObject : public Object {
public:
friend class ByteCodeInterpreter;
friend class GlobalEnvironmentRecord;
GlobalObject(ExecutionState& state)
: Object(state, ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER, false)

View file

@ -209,22 +209,22 @@ void GlobalObject::installDate(ExecutionState& state)
m_datePrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().getTime),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().getTime, builtinDateGetTime, 0, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_datePrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().valueOf),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().valueOf, builtinDateValueOf, 0, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_datePrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().toString),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().toString, builtinDateToString, 0, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_datePrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().setTime),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().setTime, builtinDateSetTime, 1, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
#define DATE_DEFINE_GETTER(dname) \
m_datePrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().get##dname), \
#define DATE_DEFINE_GETTER(dname) \
m_datePrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().get##dname), \
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().get##dname, builtinDateGet##dname, 0, nullptr, NativeFunctionInfo::Strict)), \
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
DATE_DEFINE_GETTER(Date);
DATE_DEFINE_GETTER(Day);

View file

@ -88,17 +88,17 @@ void GlobalObject::installError(ExecutionState& state)
m_errorPrototype->defineOwnPropertyThrowsException(state, state.context()->staticStrings().toString, ObjectPropertyDescriptor(errorToStringFn, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// m_##name##Error->defineAccessorProperty(strings->prototype.string(), ESVMInstance::currentInstance()->functionPrototypeAccessorData(), false, false, false);
#define DEFINE_ERROR(errorname, bname) \
m_##errorname##Error = new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().bname##Error, builtinErrorConstructor, 1, [](ExecutionState& state, size_t argc, Value* argv) -> Object* { \
return new bname##ErrorObject(state, String::emptyString); \
})); \
m_##errorname##Error->setPrototype(state, m_functionPrototype); \
m_##errorname##ErrorPrototype = new ErrorObject(state, String::emptyString); \
#define DEFINE_ERROR(errorname, bname) \
m_##errorname##Error = new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().bname##Error, builtinErrorConstructor, 1, [](ExecutionState& state, size_t argc, Value* argv) -> Object* { \
return new bname##ErrorObject(state, String::emptyString); \
})); \
m_##errorname##Error->setPrototype(state, m_functionPrototype); \
m_##errorname##ErrorPrototype = new ErrorObject(state, String::emptyString); \
m_##errorname##ErrorPrototype->defineOwnProperty(state, state.context()->staticStrings().constructor, ObjectPropertyDescriptor(m_##errorname##Error, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::EnumerablePresent))); \
m_##errorname##ErrorPrototype->defineOwnProperty(state, state.context()->staticStrings().message, ObjectPropertyDescriptor(String::emptyString, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::EnumerablePresent))); \
m_##errorname##ErrorPrototype->defineOwnProperty(state, state.context()->staticStrings().name, ObjectPropertyDescriptor(String::emptyString, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::EnumerablePresent))); \
m_##errorname##Error->setFunctionPrototype(state, m_##errorname##ErrorPrototype); \
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().bname##Error), \
m_##errorname##Error->setFunctionPrototype(state, m_##errorname##ErrorPrototype); \
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().bname##Error), \
ObjectPropertyDescriptor(m_function, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::EnumerablePresent)));
DEFINE_ERROR(reference, Reference);

View file

@ -135,7 +135,7 @@ void GlobalObject::installObject(ExecutionState& state)
m_objectPrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().toString),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().toString, builtinObjectToString, 0, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// $19.1.3.2 Object.prototype.hasOwnProperty(V)
m_objectPrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().hasOwnProperty),

View file

@ -259,11 +259,14 @@ bool Object::defineOwnProperty(ExecutionState& state, const ObjectPropertyName&
}
}
void Object::deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
bool Object::deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
ASSERT(getOwnProperty(state, P).hasValue());
ASSERT(getOwnProperty(state, P).isConfigurable());
deleteOwnProperty(state, m_structure->findProperty(state, P.toPropertyName(state)));
auto result = getOwnProperty(state, P);
if (result.hasValue() && result.isConfigurable()) {
deleteOwnProperty(state, m_structure->findProperty(state, P.toPropertyName(state)));
return true;
}
return false;
}
void Object::enumeration(ExecutionState& state, std::function<bool(const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc)> fn) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE

View file

@ -375,7 +375,7 @@ public:
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
// enumeration every property!
// callback function should skip un-Enumerable property if needs
virtual void enumeration(ExecutionState& state, std::function<bool(const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc)> callback) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;

View file

@ -39,11 +39,11 @@ bool StringObject::defineOwnProperty(ExecutionState& state, const ObjectProperty
return Object::defineOwnProperty(state, P, desc);
}
void StringObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
bool StringObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
auto r = getOwnProperty(state, P);
if (r.hasValue() && !r.isConfigurable())
return;
return false;
return Object::deleteOwnProperty(state, P);
}

View file

@ -26,7 +26,7 @@ public:
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void enumeration(ExecutionState& state, std::function<bool(const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc)> callback) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual uint32_t length(ExecutionState& state)
{