void ArrayElementExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_global) { if (!m_globalName.empty()) { VariableTablePtr variables = getScope()->getVariables(); string name = variables->getGlobalVariableName(cg, ar, m_globalName); cg_printf("g->%s", name.c_str()); } else { cg_printf("((LVariableTable *)g)->get("); m_offset->outputCPP(cg, ar); cg_printf(")"); } } else { TypePtr type = m_variable->getActualType(); if (hasContext(UnsetContext)) { cg_printf("unsetLval("); m_variable->outputCPP(cg, ar); cg_printf(", "); } else { if (m_variable->is(Expression::KindOfScalarExpression) || (type && (type->isInteger() || type->is(Type::KindOfDouble) || type->is(Type::KindOfObject) || type->is(Type::KindOfBoolean)))) { cg_printf(type && type->is(Type::KindOfString) ? "((String)" : "((Variant)"); m_variable->outputCPP(cg, ar); cg_printf(")"); } else { TypePtr act; if (!m_variable->hasCPPTemp() && m_variable->getImplementedType() && type->is(Type::KindOfArray) && !Type::SameType(m_variable->getImplementedType(), type)) { act = type; type = m_variable->getImplementedType(); m_variable->setActualType(m_variable->getImplementedType()); } m_variable->outputCPP(cg, ar); if (act) { m_variable->setActualType(act); } } } if (m_offset) { bool lvalAt = false; bool rvalAt = false; bool byRef = false; bool arrRef = false; const char *sep = ", AccessFlags::"; if (hasContext(UnsetContext)) { // do nothing } else if (hasContext(InvokeArgument) && cg.callInfoTop() != -1) { cg_printf(".argvalAt(cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum); } else if (m_context & (LValue|RefValue|DeepReference)) { cg_printf(".lvalAt("); lvalAt = true; } else { byRef = (m_context & AccessContext) && (!type || !type->is(Type::KindOfString)); arrRef = byRef && type && type->is(Type::KindOfArray); cg_printf(".rval%s%s(", arrRef || !byRef ? "At" : "", byRef ? "Ref" : ""); rvalAt = true; } m_offset->outputCPP(cg, ar); if (!type || !type->is(Type::KindOfString)) { if (rvalAt) { if (byRef && !arrRef) { const string &tmp = cg.getReferenceTemp(); cg_printf(", %s", tmp.empty() ? "Variant()" : tmp.c_str()); } if (!hasContext(ExistContext)) { cg_printf(", AccessFlags::Error"); // raise undefined index error sep = "_"; } } else if (lvalAt) { if (hasContext(AccessContext)) { // Dont copy the array if the element is an object, or // is referenced. // This is safe in AccessContext (the parent is an ArrayElement, // or an ObjectProperty) because applying [] to an object will // either invoke OffsetGet, or fatal, and modifications to a // referenced element would be reflected in all copies // of the array anyway. cg_printf(", AccessFlags::CheckExist"); sep = "_"; } } ScalarExpressionPtr sc = dynamic_pointer_cast<ScalarExpression>(m_offset); if (!hasContext(UnsetContext) && sc && sc->isLiteralString()) { String s(sc->getLiteralString()); int64 n; if (!s.get()->isStrictlyInteger(n)) { if (lvalAt || rvalAt) { cg_printf("%sKey", sep); } else { cg_printf(", true"); // skip toKey() at run time } } } } cg_printf(")"); } else { cg_printf(".lvalAt()"); } } }
void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg, AnalysisResultPtr ar, int doExist) { string func = Option::ObjectPrefix; const char *error = ", true"; std::string context = ""; bool doUnset = m_context & LValue && m_context & UnsetContext; bool needTemp = false; if (cg.getOutput() != CodeGenerator::SystemCPP) { context = originalClassName(cg, true); } if (doUnset) { func = "o_unset"; error = ""; } else if (doExist) { func = doExist > 0 ? "o_isset" : "o_empty"; error = ""; } else { if (m_context & ExistContext) { error = ", false"; } if (m_context & InvokeArgument) { ASSERT(cg.callInfoTop() != -1); func += "argval"; } else if (m_context & (LValue | RefValue | DeepReference | UnsetContext)) { if (m_context & UnsetContext) { assert(!(m_context & LValue)); // handled by doUnset func += "unsetLval"; } else { func += "lval"; } error = ""; needTemp = true; } else { func += "get"; if (isNonPrivate(ar)) { func += "Public"; context = ""; } } } if (m_valid && doExist) cg_printf(doExist > 0 ? "isset(" : "empty("); bool flag = outputCPPObject(cg, ar, doUnset || (!m_valid && doExist)); if (flag) { cg_printf("id("); outputCPPProperty(cg, ar); cg_printf(")"); if (doExist) cg_printf(", %s", doExist > 0 ? "false" : "true"); cg_printf(")"); } else if (!doUnset && m_valid) { assert(m_object->getType()->isSpecificObject()); ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(m_property); cg_printf("%s%s", Option::PropertyPrefix, name->getString().c_str()); if (doExist) cg_printf(")"); } else { cg_printf("%s(", func.c_str()); if (hasContext(InvokeArgument)) { cg_printf("cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum); } outputCPPProperty(cg, ar); if (needTemp) { const string &tmp = cg.getReferenceTemp(); context = ", " + (tmp.empty() ? "Variant()" : tmp) + context; } cg_printf("%s%s)", error, context.c_str()); } }
void ArrayElementExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_global) { if (!m_globalName.empty()) { VariableTablePtr variables = getScope()->getVariables(); string name = variables->getGlobalVariableName(ar, m_globalName); cg_printf("g->%s", name.c_str()); } else { cg_printf("((LVariableTable *)g)->get("); m_offset->outputCPP(cg, ar); cg_printf(")"); } } else { TypePtr type = m_variable->getType(); if (hasContext(UnsetContext)) { cg_printf("unsetLval("); m_variable->outputCPP(cg, ar); cg_printf(", "); } else { if (m_variable->is(Expression::KindOfScalarExpression) || (type && (type->isInteger() || type->is(Type::KindOfDouble) || type->is(Type::KindOfObject) || type->is(Type::KindOfBoolean)))) { cg_printf(type && type->is(Type::KindOfString) ? "((String)" : "((Variant)"); m_variable->outputCPP(cg, ar); cg_printf(")"); } else { m_variable->outputCPP(cg, ar); } } if (m_offset) { bool lvalAt = false; bool rvalAt = false; bool byRef = false; bool arrRef = false; const char *sep = ", AccessFlags::"; bool isArrayType = type && type->is(Type::KindOfArray); bool isStringType = type && type->is(Type::KindOfString); bool isRealChainRoot = isChainRoot() && hasCPPCseTemp(); TypePtr t; bool hasCseStore = isRealChainRoot && GetCseTempInfo( ar, static_pointer_cast<Expression>(shared_from_this()), t); if (hasContext(UnsetContext)) { // do nothing } else if (hasContext(InvokeArgument) && cg.callInfoTop() != -1) { ASSERT(!isRealChainRoot); // TODO: handle this case cg_printf(".argvalAt(cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum); } else if (m_context & (LValue|RefValue|DeepReference)) { // if we see an array access element in LValue context, the // type inference pass will never infer its type to be a string ASSERT(!isStringType); if (isRealChainRoot && !isArrayType) { // chain roots for non array types (variants) should call // lvalRef() cg_printf(".lvalRef("); } else { cg_printf(".lvalAt("); } lvalAt = true; } else { byRef = ((m_context & AccessContext) || isRealChainRoot) && !isStringType; arrRef = byRef && isArrayType; cg_printf(".rval%s%s(", arrRef || !byRef ? "At" : "", byRef ? "Ref" : ""); rvalAt = true; } m_offset->outputCPP(cg, ar); if (!isStringType) { if (rvalAt) { if (byRef && !arrRef) { string tmp; if (hasCseStore) { tmp = string(Option::CseTempStoragePrefix) + m_cppCseTemp; } else { tmp = cg.getReferenceTemp(); } cg_printf(", %s", tmp.empty() ? "Variant()" : tmp.c_str()); } if (!hasContext(ExistContext)) { cg_printf(", AccessFlags::Error"); // raise undefined index error sep = "_"; } } else if (lvalAt) { if (hasCseStore && !isArrayType) { cg_printf(", %s%s", Option::CseTempStoragePrefix, m_cppCseTemp.c_str()); } if (hasContext(AccessContext)) { // Dont copy the array if the element is an object, or // is referenced. // This is safe in AccessContext (the parent is an ArrayElement, // or an ObjectProperty) because applying [] to an object will // either invoke OffsetGet, or fatal, and modifications to a // referenced element would be reflected in all copies // of the array anyway. cg_printf(", AccessFlags::CheckExist"); sep = "_"; } } ScalarExpressionPtr sc = dynamic_pointer_cast<ScalarExpression>(m_offset); if (!hasContext(UnsetContext) && sc && sc->isLiteralString()) { String s(sc->getLiteralString()); int64 n; if (!s.get()->isStrictlyInteger(n)) { if (lvalAt || rvalAt) { cg_printf("%sKey", sep); } else { cg_printf(", true"); // skip toKey() at run time } } } } cg_printf(")"); } else { cg_printf(".lvalAt()"); } } }
void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg, AnalysisResultPtr ar, int doExist) { if (m_valid) { TypePtr type = m_object->getActualType(); if (type->isSpecificObject()) { ClassScopePtr cls(type->getClass(ar, getScope())); if (cls) getFileScope()->addUsedClassFullHeader(cls); } } string func = Option::ObjectPrefix; const char *error = ", true"; std::string context = ""; bool doUnset = m_context & LValue && m_context & UnsetContext; bool needTemp = false; if (cg.getOutput() != CodeGenerator::SystemCPP) { context = originalClassName(cg, true); } if (doUnset) { func = "o_unset"; error = ""; } else if (doExist) { func = doExist > 0 ? "o_isset" : "o_empty"; error = ""; } else { if (m_context & ExistContext) { error = ", false"; } if (m_context & InvokeArgument) { if (cg.callInfoTop() != -1) { func += "argval"; } else { func += "get"; } } else if (m_context & (LValue | RefValue | DeepReference | UnsetContext)) { if (m_context & UnsetContext) { always_assert(!(m_context & LValue)); // handled by doUnset func += "unsetLval"; } else { func += "lval"; } error = ""; needTemp = true; } else { func += "get"; if (isNonPrivate(ar)) { func += "Public"; context = ""; } } } if (m_valid && !m_object->isThis() && (!m_object->is(KindOfSimpleVariable) || !static_pointer_cast<SimpleVariable>(m_object)->isGuarded())) { cg_printf("(obj_tmp = "); outputCPPValidObject(cg, ar, false); bool write_context = hasAnyContext(LValue | RefValue | DeepReference | UnsetContext | OprLValue | DeepOprLValue | DeepAssignmentLHS | AssignmentLHS) && !doUnset; cg_printf(", LIKELY(obj_tmp != 0) %s ", write_context ? "||" : "?"); always_assert(m_property->is(KindOfScalarExpression)); ScalarExpressionPtr name = static_pointer_cast<ScalarExpression>(m_property); if (doExist || doUnset) { cg_printf(doUnset ? "unset" : doExist > 0 ? "isset" : "empty"); } ClassScopePtr cls = ar->findExactClass(shared_from_this(), m_object->getActualType()->getName()); if (write_context) { cg_printf("(throw_null_object_prop(),false),"); } cg_printf("(((%s%s*)obj_tmp)->%s%s)", Option::ClassPrefix, cls->getId().c_str(), Option::PropertyPrefix, name->getString().c_str()); if (!write_context) { cg_printf(" : (raise_null_object_prop(),%s)", doUnset ? "null_variant" : doExist ? doExist > 0 ? "false" : "true" : nullName(ar, getCPPType()).c_str()); } cg_printf(")"); return; } if (m_valid && (doExist || doUnset)) { cg_printf(doUnset ? "unset(" : doExist > 0 ? "isset(" : "empty("); } bool flag = outputCPPObject(cg, ar, !m_valid && (doUnset || doExist)); if (flag) { cg_printf("id("); outputCPPProperty(cg, ar); cg_printf(")"); if (doExist) cg_printf(", %s", doExist > 0 ? "false" : "true"); cg_printf(")"); } else if (m_valid) { always_assert(m_object->getActualType() && m_object->getActualType()->isSpecificObject()); ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(m_property); cg_printf("%s%s", Option::PropertyPrefix, name->getString().c_str()); if (doExist || doUnset) cg_printf(")"); } else { cg_printf("%s(", func.c_str()); if (hasContext(InvokeArgument) && cg.callInfoTop() != -1) { cg_printf("cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum); } outputCPPProperty(cg, ar); if (needTemp) { const string &tmp = cg.getReferenceTemp(); context = ", " + (tmp.empty() ? "Variant()" : tmp) + context; } cg_printf("%s%s)", error, context.c_str()); } }