Changeset 43331 in webkit for trunk/JavaScriptCore/parser/Nodes.cpp
- Timestamp:
- May 6, 2009, 5:06:07 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/parser/Nodes.cpp
r43313 r43331 1148 1148 } 1149 1149 1150 // BinaryOpNode::emitStrcat: 1151 // 1152 // This node generates an op_strcat operation. This opcode can handle concatenation of three or 1153 // more values, where we can determine a set of separate op_add operations would be operating on 1154 // string values. 1155 // 1156 // This function expects to be operating on a graph of AST nodes looking something like this: 1157 // 1158 // (a)... (b) 1159 // \ / 1160 // (+) (c) 1161 // \ / 1162 // [d] ((+)) 1163 // \ / 1164 // [+=] 1165 // 1166 // The assignment operation is optional, if it exists the register holding the value on the 1167 // lefthand side of the assignment should be passing as the optional 'lhs' argument. 1168 // 1169 // The method should be called on the node at the root of the tree of regular binary add 1170 // operations (marked in the diagram with a double set of parentheses). This node must 1171 // be performing a string concatenation (determined by statically detecting that at least 1172 // one child must be a string). 1173 // 1174 // Since the minimum number of values being concatenated together is expected to be 3, if 1175 // a lhs to a concatenating assignment is not provided then the root add should have at 1176 // least one left child that is also an add that can be determined to be operating on strings. 1177 // 1178 // Fixme: This method should correctly support concatenation on read-modify nodes (+=) 1179 // but disabling this due to performance degradation (op_strcat needs to be able 1180 // to append to the existing string). 1181 // 1182 RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* dst, RegisterID* lhs) 1183 { 1184 ASSERT(isAdd()); 1185 ASSERT(resultDescriptor().definitelyIsString()); 1186 1187 // Create a list of expressions for all the adds in the tree of nodes we can convert into 1188 // a string concatenation. The rightmost node (c) is added first. The rightmost node is 1189 // added first, and the leftmost child is never added, so the vector produced for the 1190 // example above will be [ c, b ]. 1191 Vector<ExpressionNode*, 16> reverseExpressionList; 1192 reverseExpressionList.append(m_expr2.get()); 1193 1194 // Examine the left child of the add. So long as this is a string add, add its right-child 1195 // to the list, and keep processing along the left fork. 1196 ExpressionNode* leftMostAddChild = m_expr1.get(); 1197 while (leftMostAddChild->isAdd() && leftMostAddChild->resultDescriptor().definitelyIsString()) { 1198 reverseExpressionList.append(static_cast<AddNode*>(leftMostAddChild)->m_expr2.get()); 1199 leftMostAddChild = static_cast<AddNode*>(leftMostAddChild)->m_expr1.get(); 1200 } 1201 1202 Vector<RefPtr<RegisterID>, 16> temporaryRegisters; 1203 1204 // If there is an assignment, allocate a temporary to hold the lhs after conversion. 1205 // We could possibly avoid this (the lhs is converted last anyway, we could let the 1206 // op_strcat node handle its conversion if required). 1207 if (lhs) 1208 temporaryRegisters.append(generator.newTemporary()); 1209 1210 // Emit code for the leftmost node ((a) in the example). 1211 temporaryRegisters.append(generator.newTemporary()); 1212 RegisterID* leftMostAddChildTempRegister = temporaryRegisters.last().get(); 1213 generator.emitNode(leftMostAddChildTempRegister, leftMostAddChild); 1214 1215 // Note on ordering of conversions: 1216 // 1217 // We maintain the same ordering of conversions as we would see if the concatenations 1218 // was performed as a sequence of adds (otherwise this optimization could change 1219 // behaviour should an object have been provided a valueOf or toString method). 1220 // 1221 // Considering the above example, the sequnce of execution is: 1222 // * evaluate operand (a) 1223 // * evaluate operand (b) 1224 // * convert (a) to primitive <- (this would be triggered by the first add) 1225 // * convert (b) to primitive <- (ditto) 1226 // * evaluate operand (c) 1227 // * convert (c) to primitive <- (this would be triggered by the second add) 1228 // And optionally, if there is an assignment: 1229 // * convert (d) to primitive <- (this would be triggered by the assigning addition) 1230 // 1231 // As such we do not plant an op to convert the leftmost child now. Instead, use 1232 // 'leftMostAddChildTempRegister' as a flag to trigger generation of the conversion 1233 // once the second node has been generated. However, if the leftmost child is an 1234 // immediate we can trivially determine that no conversion will be required. 1235 // If this is the case 1236 if (leftMostAddChild->isString()) 1237 leftMostAddChildTempRegister = 0; 1238 1239 while (reverseExpressionList.size()) { 1240 ExpressionNode* node = reverseExpressionList.last(); 1241 reverseExpressionList.removeLast(); 1242 1243 // Emit the code for the current node. 1244 temporaryRegisters.append(generator.newTemporary()); 1245 generator.emitNode(temporaryRegisters.last().get(), node); 1246 1247 // On the first iteration of this loop, when we first reach this point we have just 1248 // generated the second node, which means it is time to convert the leftmost operand. 1249 if (leftMostAddChildTempRegister) { 1250 generator.emitToPrimitive(leftMostAddChildTempRegister, leftMostAddChildTempRegister); 1251 leftMostAddChildTempRegister = 0; // Only do this once. 1252 } 1253 // Plant a conversion for this node, if necessary. 1254 if (!node->isString()) 1255 generator.emitToPrimitive(temporaryRegisters.last().get(), temporaryRegisters.last().get()); 1256 } 1257 ASSERT(temporaryRegisters.size() >= 3); 1258 1259 // If there is an assignment convert the lhs now. This will also copy lhs to 1260 // the temporary register we allocated for it. 1261 if (lhs) 1262 generator.emitToPrimitive(temporaryRegisters[0].get(), lhs); 1263 1264 return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); 1265 } 1266 1150 1267 RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) 1151 1268 { 1152 1269 OpcodeID opcodeID = this->opcodeID(); 1270 1271 if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) 1272 return emitStrcat(generator, dst); 1273 1153 1274 if (opcodeID == op_neq) { 1154 1275 if (m_expr1->isNull() || m_expr2->isNull()) {
Note:
See TracChangeset
for help on using the changeset viewer.