Changeset 106478 in webkit
- Timestamp:
- Feb 1, 2012, 11:37:00 AM (14 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r106454 r106478 1 2012-02-01 Andy Wingo <wingo@igalia.com> 2 3 Refactor identifier resolution in BytecodeGenerator 4 https://bugs.webkit.org/show_bug.cgi?id=76285 5 6 Reviewed by Geoffrey Garen. 7 8 * bytecompiler/BytecodeGenerator.h: 9 (JSC::ResolveResult): New class, to describe the storage 10 location corresponding to an identifier in a program. 11 * bytecompiler/BytecodeGenerator.cpp: 12 (JSC::BytecodeGenerator::resolve): New function, replacing 13 findScopedProperty. 14 (JSC::BytecodeGenerator::resolveConstDecl): New function, 15 encapsulating what ConstDeclNode::emitBytecode used to do. 16 (JSC::BytecodeGenerator::emitGetStaticVar): 17 (JSC::BytecodeGenerator::emitPutStaticVar): New functions, 18 corresponding to the old emitGetScopedVar and emitPutScopedVar. 19 (JSC::BytecodeGenerator::registerFor): Remove version that took an 20 Identifier&; replaced by ResolveResult::local(). 21 (JSC::BytecodeGenerator::emitResolve): 22 (JSC::BytecodeGenerator::emitResolveBase): 23 (JSC::BytecodeGenerator::emitResolveBaseForPut): 24 (JSC::BytecodeGenerator::emitResolveWithBase): 25 (JSC::BytecodeGenerator::emitResolveWithThis): Change to accept a 26 "resolveResult" argument. This is more clear, and reduces the 27 amount of double analysis happening at compile-time. 28 * bytecompiler/NodesCodegen.cpp: 29 (JSC::ResolveNode::emitBytecode): 30 (JSC::EvalFunctionCallNode::emitBytecode): 31 (JSC::FunctionCallResolveNode::emitBytecode): 32 (JSC::PostfixResolveNode::emitBytecode): 33 (JSC::DeleteResolveNode::emitBytecode): 34 (JSC::TypeOfResolveNode::emitBytecode): 35 (JSC::PrefixResolveNode::emitBytecode): 36 (JSC::ReadModifyResolveNode::emitBytecode): 37 (JSC::AssignResolveNode::emitBytecode): 38 (JSC::ConstDeclNode::emitCodeSingle): 39 (JSC::ForInNode::emitBytecode): Refactor to use the new 40 ResolveResult structure. 41 1 42 2012-02-01 Csaba Osztrogonác <ossy@webkit.org> 2 43 -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r106314 r106478 2 2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. 3 3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> 4 * Copyright (C) 2012 Igalia, S.L. 4 5 * 5 6 * Redistribution and use in source and binary forms, with or without … … 116 117 expected by the callee. 117 118 */ 119 120 #ifndef NDEBUG 121 void ResolveResult::checkValidity() 122 { 123 switch (m_type) { 124 case Register: 125 case ReadOnlyRegister: 126 ASSERT(m_local); 127 return; 128 case Lexical: 129 case ReadOnlyLexical: 130 case DynamicLexical: 131 case DynamicReadOnlyLexical: 132 ASSERT(m_index != missingSymbolMarker()); 133 return; 134 case Global: 135 case DynamicGlobal: 136 ASSERT(m_globalObject); 137 return; 138 case IndexedGlobal: 139 case ReadOnlyIndexedGlobal: 140 case DynamicIndexedGlobal: 141 case DynamicReadOnlyIndexedGlobal: 142 ASSERT(m_index != missingSymbolMarker()); 143 ASSERT(m_globalObject); 144 return; 145 case Dynamic: 146 return; 147 default: 148 ASSERT_NOT_REACHED(); 149 } 150 } 151 #endif 118 152 119 153 #ifndef NDEBUG … … 502 536 // each parameter, even if the parameter doesn't make it into the symbol table. 503 537 m_codeBlock->addParameter(); 504 }505 506 RegisterID* BytecodeGenerator::registerFor(const Identifier& ident)507 {508 if (ident == propertyNames().thisIdentifier)509 return &m_thisRegister;510 511 if (m_codeType == GlobalCode)512 return 0;513 514 if (!shouldOptimizeLocals())515 return 0;516 517 SymbolTableEntry entry = symbolTable().get(ident.impl());518 if (entry.isNull())519 return 0;520 521 if (ident == propertyNames().arguments)522 createArgumentsIfNecessary();523 524 return createLazyRegisterIfNecessary(®isterFor(entry.getIndex()));525 }526 527 RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident)528 {529 if (m_codeType == EvalCode)530 return 0;531 532 if (m_codeType == GlobalCode)533 return 0;534 535 SymbolTableEntry entry = symbolTable().get(ident.impl());536 if (entry.isNull())537 return 0;538 539 return createLazyRegisterIfNecessary(®isterFor(entry.getIndex()));540 538 } 541 539 … … 1171 1169 } 1172 1170 1173 bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting, bool& requiresDynamicChecks, JSObject*& globalObject) 1174 { 1171 ResolveResult BytecodeGenerator::resolve(const Identifier& property) 1172 { 1173 if (property == propertyNames().thisIdentifier) 1174 return ResolveResult::registerResolve(thisRegister(), ResolveResult::ReadOnlyFlag); 1175 1176 // Check if the property should be allocated in a register. 1177 if (m_codeType != GlobalCode && shouldOptimizeLocals()) { 1178 SymbolTableEntry entry = symbolTable().get(property.impl()); 1179 if (!entry.isNull()) { 1180 if (property == propertyNames().arguments) 1181 createArgumentsIfNecessary(); 1182 unsigned flags = entry.isReadOnly() ? ResolveResult::ReadOnlyFlag : 0; 1183 RegisterID* local = createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); 1184 return ResolveResult::registerResolve(local, flags); 1185 } 1186 } 1187 1175 1188 // Cases where we cannot statically optimize the lookup. 1176 1189 if (property == propertyNames().arguments || !canOptimizeNonLocals()) { 1177 stackDepth = 0;1178 index = missingSymbolMarker();1179 1180 1190 if (shouldOptimizeLocals() && m_codeType == GlobalCode) { 1181 1191 ScopeChainIterator iter = m_scopeChain->begin(); 1182 globalObject = iter->get();1192 JSObject* globalObject = iter->get(); 1183 1193 ASSERT((++iter) == m_scopeChain->end()); 1184 } 1185 return false; 1186 } 1187 1188 size_t depth = 0; 1189 requiresDynamicChecks = false; 1194 return ResolveResult::globalResolve(globalObject); 1195 } else 1196 return ResolveResult::dynamicResolve(0); 1197 } 1198 1190 1199 ScopeChainIterator iter = m_scopeChain->begin(); 1191 1200 ScopeChainIterator end = m_scopeChain->end(); 1201 size_t depth = 0; 1202 unsigned flags = 0; 1203 for (; iter != end; ++iter, ++depth) { 1204 JSObject* currentScope = iter->get(); 1205 if (!currentScope->isVariableObject()) { 1206 flags |= ResolveResult::DynamicFlag; 1207 break; 1208 } 1209 JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope); 1210 SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl()); 1211 1212 // Found the property 1213 if (!entry.isNull()) { 1214 if (entry.isReadOnly()) 1215 flags |= ResolveResult::ReadOnlyFlag; 1216 depth += m_codeBlock->needsFullScopeChain(); 1217 if (++iter == end) { 1218 if (flags & ResolveResult::DynamicFlag) 1219 return ResolveResult::dynamicIndexedGlobalResolve(entry.getIndex(), depth, currentScope, flags); 1220 return ResolveResult::indexedGlobalResolve(entry.getIndex(), currentScope, flags); 1221 } 1222 return ResolveResult::lexicalResolve(entry.getIndex(), depth, flags); 1223 } 1224 bool scopeRequiresDynamicChecks = false; 1225 if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks)) 1226 break; 1227 if (scopeRequiresDynamicChecks) 1228 flags |= ResolveResult::DynamicFlag; 1229 } 1230 1231 // Can't locate the property but we're able to avoid a few lookups. 1232 JSObject* scope = iter->get(); 1233 depth += m_codeBlock->needsFullScopeChain(); 1234 if (++iter == end) { 1235 if ((flags & ResolveResult::DynamicFlag) && depth) 1236 return ResolveResult::dynamicGlobalResolve(depth, scope); 1237 return ResolveResult::globalResolve(scope); 1238 } 1239 return ResolveResult::dynamicResolve(depth); 1240 } 1241 1242 ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property) 1243 { 1244 // Register-allocated const declarations. 1245 if (m_codeType != EvalCode && m_codeType != GlobalCode) { 1246 SymbolTableEntry entry = symbolTable().get(property.impl()); 1247 if (!entry.isNull()) { 1248 unsigned flags = entry.isReadOnly() ? ResolveResult::ReadOnlyFlag : 0; 1249 RegisterID* local = createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); 1250 return ResolveResult::registerResolve(local, flags); 1251 } 1252 } 1253 1254 // Const declarations in eval code or global code. 1255 ScopeChainIterator iter = scopeChain()->begin(); 1256 ScopeChainIterator end = scopeChain()->end(); 1257 size_t depth = 0; 1192 1258 for (; iter != end; ++iter, ++depth) { 1193 1259 JSObject* currentScope = iter->get(); 1194 1260 if (!currentScope->isVariableObject()) 1195 break;1261 continue; 1196 1262 JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope); 1197 1263 SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl()); 1198 1199 // Found the property 1200 if (!entry.isNull()) { 1201 if (entry.isReadOnly() && forWriting) { 1202 stackDepth = 0; 1203 index = missingSymbolMarker(); 1204 if (++iter == end) 1205 globalObject = currentVariableObject; 1206 return false; 1207 } 1208 stackDepth = depth + m_codeBlock->needsFullScopeChain(); 1209 index = entry.getIndex(); 1210 if (++iter == end) 1211 globalObject = currentVariableObject; 1212 return true; 1213 } 1214 bool scopeRequiresDynamicChecks = false; 1215 if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks)) 1216 break; 1217 requiresDynamicChecks |= scopeRequiresDynamicChecks; 1218 } 1219 // Can't locate the property but we're able to avoid a few lookups. 1220 stackDepth = depth + m_codeBlock->needsFullScopeChain(); 1221 index = missingSymbolMarker(); 1222 JSObject* scope = iter->get(); 1223 if (++iter == end) 1224 globalObject = scope; 1225 return true; 1264 if (entry.isNull()) 1265 continue; 1266 if (++iter == end) 1267 return ResolveResult::indexedGlobalResolve(entry.getIndex(), currentVariableObject, 0); 1268 return ResolveResult::lexicalResolve(entry.getIndex(), depth + scopeDepth(), 0); 1269 } 1270 1271 // FIXME: While this code should only be hit in an eval block, it will assign 1272 // to the wrong base if property exists in an intervening with scope. 1273 return ResolveResult::dynamicResolve(scopeDepth()); 1226 1274 } 1227 1275 … … 1249 1297 } 1250 1298 1251 RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& property) 1252 { 1253 size_t depth = 0; 1254 int index = 0; 1255 JSObject* globalObject = 0; 1256 bool requiresDynamicChecks = false; 1257 if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) && !globalObject) { 1258 // We can't optimise at all :-( 1259 ValueProfile* profile = emitProfiledOpcode(op_resolve); 1260 instructions().append(dst->index()); 1261 instructions().append(addConstant(property)); 1262 instructions().append(profile); 1263 return dst; 1264 } 1265 if (shouldAvoidResolveGlobal()) { 1266 globalObject = 0; 1267 requiresDynamicChecks = true; 1268 } 1269 1270 if (globalObject) { 1271 if (index != missingSymbolMarker() && !requiresDynamicChecks) { 1272 // Directly index the property lookup across multiple scopes. 1273 return emitGetScopedVar(dst, depth, index, globalObject); 1274 } 1275 1299 RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property) 1300 { 1301 if (resolveResult.isStatic()) 1302 return emitGetStaticVar(dst, resolveResult); 1303 1304 if (resolveResult.isGlobal() && !shouldAvoidResolveGlobal()) { 1276 1305 #if ENABLE(JIT) 1277 1306 m_codeBlock->addGlobalResolveInfo(instructions().size()); … … 1280 1309 m_codeBlock->addGlobalResolveInstruction(instructions().size()); 1281 1310 #endif 1282 ValueProfile* profile = emitProfiledOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); 1311 bool dynamic = resolveResult.isDynamic() && resolveResult.depth(); 1312 ValueProfile* profile = emitProfiledOpcode(dynamic ? op_resolve_global_dynamic : op_resolve_global); 1283 1313 instructions().append(dst->index()); 1284 1314 instructions().append(addConstant(property)); 1285 1315 instructions().append(0); 1286 1316 instructions().append(0); 1287 if ( requiresDynamicChecks)1288 instructions().append( depth);1317 if (dynamic) 1318 instructions().append(resolveResult.depth()); 1289 1319 instructions().append(profile); 1290 1320 return dst; 1291 1321 } 1292 1293 if (requiresDynamicChecks) { 1294 // If we get here we have eval nested inside a |with| just give up 1295 ValueProfile* profile = emitProfiledOpcode(op_resolve); 1322 1323 if (resolveResult.type() == ResolveResult::Dynamic && resolveResult.depth()) { 1324 // In this case we are at least able to drop a few scope chains from the 1325 // lookup chain, although we still need to hash from then on. 1326 ValueProfile* profile = emitProfiledOpcode(op_resolve_skip); 1296 1327 instructions().append(dst->index()); 1297 1328 instructions().append(addConstant(property)); 1329 instructions().append(resolveResult.depth()); 1298 1330 instructions().append(profile); 1299 1331 return dst; 1300 1332 } 1301 1333 1302 if (index != missingSymbolMarker()) { 1303 // Directly index the property lookup across multiple scopes. 1304 return emitGetScopedVar(dst, depth, index, globalObject); 1305 } 1306 1307 // In this case we are at least able to drop a few scope chains from the 1308 // lookup chain, although we still need to hash from then on. 1309 ValueProfile* profile = emitProfiledOpcode(op_resolve_skip); 1334 ValueProfile* profile = emitProfiledOpcode(op_resolve); 1310 1335 instructions().append(dst->index()); 1311 1336 instructions().append(addConstant(property)); 1312 instructions().append(depth);1313 1337 instructions().append(profile); 1314 1338 return dst; 1315 1339 } 1316 1340 1317 RegisterID* BytecodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index, JSValue globalObject) 1318 { 1319 if (globalObject) { 1320 if (m_lastOpcodeID == op_put_global_var) { 1321 int dstIndex; 1322 int srcIndex; 1323 retrieveLastUnaryOp(dstIndex, srcIndex); 1324 1325 if (dstIndex == index && srcIndex == dst->index()) 1326 return dst; 1327 } 1328 1329 ValueProfile* profile = emitProfiledOpcode(op_get_global_var); 1330 instructions().append(dst->index()); 1331 instructions().append(index); 1332 instructions().append(profile); 1333 return dst; 1334 } 1335 1336 ValueProfile* profile = emitProfiledOpcode(op_get_scoped_var); 1341 RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property) 1342 { 1343 if (resolveResult.isGlobal() && !resolveResult.isDynamic()) 1344 // Global object is the base 1345 return emitLoad(dst, JSValue(resolveResult.globalObject())); 1346 1347 // We can't optimise at all :-( 1348 ValueProfile* profile = emitProfiledOpcode(op_resolve_base); 1337 1349 instructions().append(dst->index()); 1338 instructions().append( index);1339 instructions().append( depth);1350 instructions().append(addConstant(property)); 1351 instructions().append(false); 1340 1352 instructions().append(profile); 1341 1353 return dst; 1342 1354 } 1343 1355 1344 RegisterID* BytecodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value, JSValue globalObject) 1345 { 1346 if (globalObject) { 1347 emitOpcode(op_put_global_var); 1348 instructions().append(index); 1349 instructions().append(value->index()); 1350 return value; 1351 } 1352 emitOpcode(op_put_scoped_var); 1353 instructions().append(index); 1354 instructions().append(depth); 1355 instructions().append(value->index()); 1356 return value; 1357 } 1358 1359 RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property) 1360 { 1361 size_t depth = 0; 1362 int index = 0; 1363 JSObject* globalObject = 0; 1364 bool requiresDynamicChecks = false; 1365 findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject); 1366 if (!globalObject || requiresDynamicChecks) { 1367 // We can't optimise at all :-( 1368 ValueProfile* profile = emitProfiledOpcode(op_resolve_base); 1356 RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property) 1357 { 1358 if (!m_codeBlock->isStrictMode()) 1359 return emitResolveBase(dst, resolveResult, property); 1360 1361 if (resolveResult.isGlobal() && !resolveResult.isDynamic()) { 1362 // Global object is the base 1363 RefPtr<RegisterID> result = emitLoad(dst, JSValue(resolveResult.globalObject())); 1364 emitOpcode(op_ensure_property_exists); 1369 1365 instructions().append(dst->index()); 1370 1366 instructions().append(addConstant(property)); 1371 instructions().append(false); 1372 instructions().append(profile); 1373 return dst; 1374 } 1375 1376 // Global object is the base 1377 return emitLoad(dst, JSValue(globalObject)); 1378 } 1379 1380 RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Identifier& property) 1381 { 1382 if (!m_codeBlock->isStrictMode()) 1383 return emitResolveBase(dst, property); 1384 size_t depth = 0; 1385 int index = 0; 1386 JSObject* globalObject = 0; 1387 bool requiresDynamicChecks = false; 1388 findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject); 1389 if (!globalObject || requiresDynamicChecks) { 1390 // We can't optimise at all :-( 1391 ValueProfile* profile = emitProfiledOpcode(op_resolve_base); 1392 instructions().append(dst->index()); 1393 instructions().append(addConstant(property)); 1394 instructions().append(true); 1395 instructions().append(profile); 1396 return dst; 1397 } 1398 1399 // Global object is the base 1400 RefPtr<RegisterID> result = emitLoad(dst, JSValue(globalObject)); 1401 emitOpcode(op_ensure_property_exists); 1367 return result.get(); 1368 } 1369 1370 // We can't optimise at all :-( 1371 ValueProfile* profile = emitProfiledOpcode(op_resolve_base); 1402 1372 instructions().append(dst->index()); 1403 1373 instructions().append(addConstant(property)); 1404 return result.get(); 1405 } 1406 1407 RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property) 1408 { 1409 size_t depth = 0; 1410 int index = 0; 1411 JSObject* globalObject = 0; 1412 bool requiresDynamicChecks = false; 1413 if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) { 1414 // We can't optimise at all :-( 1415 ValueProfile* profile = emitProfiledOpcode(op_resolve_with_base); 1416 instructions().append(baseDst->index()); 1374 instructions().append(true); 1375 instructions().append(profile); 1376 return dst; 1377 } 1378 1379 RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property) 1380 { 1381 if (resolveResult.isGlobal() && !resolveResult.isDynamic()) { 1382 // Global object is the base 1383 emitLoad(baseDst, JSValue(resolveResult.globalObject())); 1384 1385 if (resolveResult.isStatic()) { 1386 // Directly index the property lookup across multiple scopes. 1387 emitGetStaticVar(propDst, resolveResult); 1388 return baseDst; 1389 } 1390 1391 if (shouldAvoidResolveGlobal()) { 1392 ValueProfile* profile = emitProfiledOpcode(op_resolve); 1393 instructions().append(propDst->index()); 1394 instructions().append(addConstant(property)); 1395 instructions().append(profile); 1396 return baseDst; 1397 } 1398 1399 #if ENABLE(JIT) 1400 m_codeBlock->addGlobalResolveInfo(instructions().size()); 1401 #endif 1402 #if ENABLE(INTERPRETER) 1403 m_codeBlock->addGlobalResolveInstruction(instructions().size()); 1404 #endif 1405 ValueProfile* profile = emitProfiledOpcode(op_resolve_global); 1417 1406 instructions().append(propDst->index()); 1418 1407 instructions().append(addConstant(property)); 1408 instructions().append(0); 1409 instructions().append(0); 1419 1410 instructions().append(profile); 1420 1411 return baseDst; 1421 1412 } 1422 1413 1423 bool forceGlobalResolve = false; 1424 1425 // Global object is the base 1426 emitLoad(baseDst, JSValue(globalObject)); 1427 1428 if (index != missingSymbolMarker() && !forceGlobalResolve) { 1429 // Directly index the property lookup across multiple scopes. 1430 emitGetScopedVar(propDst, depth, index, globalObject); 1431 return baseDst; 1432 } 1433 if (shouldAvoidResolveGlobal()) { 1434 ValueProfile* profile = emitProfiledOpcode(op_resolve); 1435 instructions().append(propDst->index()); 1436 instructions().append(addConstant(property)); 1437 instructions().append(profile); 1438 return baseDst; 1439 } 1440 #if ENABLE(JIT) 1441 m_codeBlock->addGlobalResolveInfo(instructions().size()); 1442 #endif 1443 #if ENABLE(INTERPRETER) 1444 m_codeBlock->addGlobalResolveInstruction(instructions().size()); 1445 #endif 1446 ValueProfile* profile = emitProfiledOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); 1414 1415 1416 1417 ValueProfile* profile = emitProfiledOpcode(op_resolve_with_base); 1418 instructions().append(baseDst->index()); 1447 1419 instructions().append(propDst->index()); 1448 1420 instructions().append(addConstant(property)); 1449 instructions().append(0);1450 instructions().append(0);1451 if (requiresDynamicChecks)1452 instructions().append(depth);1453 1421 instructions().append(profile); 1454 1422 return baseDst; 1455 1423 } 1456 1424 1457 RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const Identifier& property) 1458 { 1459 size_t depth = 0; 1460 int index = 0; 1461 JSObject* globalObject = 0; 1462 bool requiresDynamicChecks = false; 1463 if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) { 1425 RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property) 1426 { 1427 if (resolveResult.isStatic()) { 1428 emitLoad(baseDst, jsUndefined()); 1429 emitGetStaticVar(propDst, resolveResult); 1430 return baseDst; 1431 } 1432 1433 if (resolveResult.type() == ResolveResult::Dynamic) { 1464 1434 // We can't optimise at all :-( 1465 1435 ValueProfile* profile = emitProfiledOpcode(op_resolve_with_this); … … 1471 1441 } 1472 1442 1473 bool forceGlobalResolve = false;1474 1475 // Global object is the base1476 1443 emitLoad(baseDst, jsUndefined()); 1477 1478 if (index != missingSymbolMarker() && !forceGlobalResolve) { 1479 // Directly index the property lookup across multiple scopes. 1480 emitGetScopedVar(propDst, depth, index, globalObject); 1481 return baseDst; 1482 } 1483 if (shouldAvoidResolveGlobal()) { 1484 ValueProfile* profile = emitProfiledOpcode(op_resolve); 1485 instructions().append(propDst->index()); 1486 instructions().append(addConstant(property)); 1444 return emitResolve(propDst, resolveResult, property); 1445 } 1446 1447 RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult) 1448 { 1449 ValueProfile* profile = 0; 1450 1451 switch (resolveResult.type()) { 1452 case ResolveResult::Register: 1453 case ResolveResult::ReadOnlyRegister: 1454 if (dst == ignoredResult()) 1455 return 0; 1456 return moveToDestinationIfNeeded(dst, resolveResult.local()); 1457 1458 case ResolveResult::Lexical: 1459 case ResolveResult::ReadOnlyLexical: 1460 profile = emitProfiledOpcode(op_get_scoped_var); 1461 instructions().append(dst->index()); 1462 instructions().append(resolveResult.index()); 1463 instructions().append(resolveResult.depth()); 1487 1464 instructions().append(profile); 1488 return baseDst; 1489 } 1490 #if ENABLE(JIT) 1491 m_codeBlock->addGlobalResolveInfo(instructions().size()); 1492 #endif 1493 #if ENABLE(INTERPRETER) 1494 m_codeBlock->addGlobalResolveInstruction(instructions().size()); 1495 #endif 1496 ValueProfile* profile = emitProfiledOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); 1497 instructions().append(propDst->index()); 1498 instructions().append(addConstant(property)); 1499 instructions().append(0); 1500 instructions().append(0); 1501 if (requiresDynamicChecks) 1502 instructions().append(depth); 1503 instructions().append(profile); 1504 return baseDst; 1465 return dst; 1466 1467 case ResolveResult::IndexedGlobal: 1468 case ResolveResult::ReadOnlyIndexedGlobal: 1469 if (m_lastOpcodeID == op_put_global_var) { 1470 int dstIndex; 1471 int srcIndex; 1472 retrieveLastUnaryOp(dstIndex, srcIndex); 1473 if (dstIndex == resolveResult.index() && srcIndex == dst->index()) 1474 return dst; 1475 } 1476 1477 profile = emitProfiledOpcode(op_get_global_var); 1478 instructions().append(dst->index()); 1479 instructions().append(resolveResult.index()); 1480 instructions().append(profile); 1481 return dst; 1482 1483 default: 1484 ASSERT_NOT_REACHED(); 1485 return 0; 1486 } 1487 } 1488 1489 RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, RegisterID* value) 1490 { 1491 switch (resolveResult.type()) { 1492 case ResolveResult::Register: 1493 case ResolveResult::ReadOnlyRegister: 1494 return moveToDestinationIfNeeded(resolveResult.local(), value); 1495 1496 case ResolveResult::Lexical: 1497 case ResolveResult::ReadOnlyLexical: 1498 emitOpcode(op_put_scoped_var); 1499 instructions().append(resolveResult.index()); 1500 instructions().append(resolveResult.depth()); 1501 instructions().append(value->index()); 1502 return value; 1503 1504 case ResolveResult::IndexedGlobal: 1505 case ResolveResult::ReadOnlyIndexedGlobal: 1506 emitOpcode(op_put_global_var); 1507 instructions().append(resolveResult.index()); 1508 instructions().append(value->index()); 1509 return value; 1510 1511 default: 1512 ASSERT_NOT_REACHED(); 1513 return 0; 1514 } 1505 1515 } 1506 1516 … … 2385 2395 bool BytecodeGenerator::isArgumentNumber(const Identifier& ident, int argumentNumber) 2386 2396 { 2387 RegisterID* registerID = re gisterFor(ident);2397 RegisterID* registerID = resolve(ident).local(); 2388 2398 if (!registerID || registerID->index() >= 0) 2389 2399 return 0; -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
r106255 r106478 2 2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. 3 3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> 4 * Copyright (C) 2012 Igalia, S.L. 4 5 * 5 6 * Redistribution and use in source and binary forms, with or without … … 86 87 }; 87 88 89 class ResolveResult { 90 public: 91 enum Flags { 92 // The property is locally bound, in a register. 93 RegisterFlag = 0x1, 94 // We need to traverse the scope chain at runtime, checking for 95 // non-strict eval and/or `with' nodes. 96 DynamicFlag = 0x2, 97 // The property was resolved to a definite location, and the 98 // identifier is not needed any more. 99 StaticFlag = 0x4, 100 // Once we have the base object, the property will be located at a 101 // known index. 102 IndexedFlag = 0x8, 103 // Skip some number of objects in the scope chain, given by "depth". 104 ScopedFlag = 0x10, 105 // The resolved binding is immutable. 106 ReadOnlyFlag = 0x20, 107 // The base object is the global object. 108 GlobalFlag = 0x40 109 }; 110 enum Type { 111 // The property is local, and stored in a register. 112 Register = RegisterFlag | StaticFlag, 113 // A read-only local, created by "const". 114 ReadOnlyRegister = RegisterFlag | ReadOnlyFlag | StaticFlag, 115 // The property is statically scoped free variable. Its coordinates 116 // are in "index" and "depth". 117 Lexical = IndexedFlag | ScopedFlag | StaticFlag, 118 // A read-only Lexical, created by "const". 119 ReadOnlyLexical = IndexedFlag | ScopedFlag | ReadOnlyFlag | StaticFlag, 120 // The property was not bound lexically, so at runtime we should 121 // look directly in the global object. 122 Global = GlobalFlag, 123 // Like Global, but we could actually resolve the property to a 124 // DontDelete property in the global object, for instance, any 125 // binding created with "var" at the top level. At runtime we'll 126 // just index into the global object. 127 IndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag, 128 // Like IndexedGlobal, but the property is also read-only, like NaN, 129 // Infinity, or undefined. 130 ReadOnlyIndexedGlobal = IndexedFlag | ReadOnlyFlag | GlobalFlag | StaticFlag, 131 // The property could not be resolved statically, due to the 132 // presence of `with' blocks. At runtime we'll have to walk the 133 // scope chain. ScopedFlag is set to indicate that "depth" will 134 // hold some number of nodes to skip in the scope chain, before 135 // beginning the search. 136 Dynamic = DynamicFlag | ScopedFlag, 137 // The property was located as a statically scoped free variable, 138 // but while traversing the scope chain, there was an intermediate 139 // activation that used non-strict `eval'. At runtime we'll have to 140 // check for the absence of this property in those intervening 141 // scopes. 142 DynamicLexical = DynamicFlag | IndexedFlag | ScopedFlag, 143 // Like ReadOnlyLexical, but with intervening non-strict `eval'. 144 DynamicReadOnlyLexical = DynamicFlag | IndexedFlag | ScopedFlag | ReadOnlyFlag, 145 // Like Global, but with intervening non-strict `eval'. As with 146 // Dynamic, ScopeFlag is set to indicate that "depth" does indeed 147 // store a number of frames to skip before doing the dynamic checks. 148 DynamicGlobal = DynamicFlag | GlobalFlag | ScopedFlag, 149 // Like IndexedGlobal, but with intervening non-strict `eval'. 150 DynamicIndexedGlobal = DynamicFlag | IndexedFlag | GlobalFlag | ScopedFlag, 151 // Like ReadOnlyIndexedGlobal, but with intervening non-strict 152 // `eval'. 153 DynamicReadOnlyIndexedGlobal = DynamicFlag | IndexedFlag | ReadOnlyFlag | GlobalFlag | ScopedFlag, 154 }; 155 156 static ResolveResult registerResolve(RegisterID *local, unsigned flags) 157 { 158 return ResolveResult(Register | flags, local, missingSymbolMarker(), 0, 0); 159 } 160 static ResolveResult dynamicResolve(size_t depth) 161 { 162 return ResolveResult(Dynamic, 0, missingSymbolMarker(), depth, 0); 163 } 164 static ResolveResult lexicalResolve(int index, size_t depth, unsigned flags) 165 { 166 unsigned type = (flags & DynamicFlag) ? DynamicLexical : Lexical; 167 return ResolveResult(type | flags, 0, index, depth, 0); 168 } 169 static ResolveResult indexedGlobalResolve(int index, JSObject *globalObject, unsigned flags) 170 { 171 return ResolveResult(IndexedGlobal | flags, 0, index, 0, globalObject); 172 } 173 static ResolveResult dynamicIndexedGlobalResolve(int index, size_t depth, JSObject *globalObject, unsigned flags) 174 { 175 return ResolveResult(DynamicIndexedGlobal | flags, 0, index, depth, globalObject); 176 } 177 static ResolveResult globalResolve(JSObject *globalObject) 178 { 179 return ResolveResult(Global, 0, missingSymbolMarker(), 0, globalObject); 180 } 181 static ResolveResult dynamicGlobalResolve(size_t dynamicDepth, JSObject *globalObject) 182 { 183 return ResolveResult(DynamicGlobal, 0, missingSymbolMarker(), dynamicDepth, globalObject); 184 } 185 186 unsigned type() const { return m_type; } 187 // Returns the register corresponding to a local variable, or 0 if no 188 // such register exists. Registers returned by ResolveResult::local() do 189 // not require explicit reference counting. 190 RegisterID* local() const { return m_local; } 191 int index() const { ASSERT (isIndexed() || isRegister()); return m_index; } 192 size_t depth() const { ASSERT(isScoped()); return m_depth; } 193 JSObject* globalObject() const { ASSERT(isGlobal()); ASSERT(m_globalObject); return m_globalObject; } 194 195 bool isRegister() const { return m_type & RegisterFlag; } 196 bool isDynamic() const { return m_type & DynamicFlag; } 197 bool isStatic() const { return m_type & StaticFlag; } 198 bool isIndexed() const { return m_type & IndexedFlag; } 199 bool isScoped() const { return m_type & ScopedFlag; } 200 bool isReadOnly() const { return (m_type & ReadOnlyFlag) && !isDynamic(); } 201 bool isGlobal() const { return m_type & GlobalFlag; } 202 203 private: 204 ResolveResult(unsigned type, RegisterID* local, int index, size_t depth, JSObject* globalObject) 205 : m_type(type) 206 , m_index(index) 207 , m_local(local) 208 , m_depth(depth) 209 , m_globalObject(globalObject) 210 { 211 #ifndef NDEBUG 212 checkValidity(); 213 #endif 214 } 215 216 #ifndef NDEBUG 217 void checkValidity(); 218 #endif 219 220 unsigned m_type; 221 int m_index; // Index in scope, if IndexedFlag is set 222 RegisterID* m_local; // Local register, if RegisterFlag is set 223 size_t m_depth; // Depth in scope chain, if ScopedFlag is set 224 JSObject* m_globalObject; // If GlobalFlag is set. 225 }; 226 88 227 class BytecodeGenerator { 89 228 WTF_MAKE_FAST_ALLOCATED; … … 108 247 JSObject* generate(); 109 248 110 // Returns the register corresponding to a local variable, or 0 if no111 // such register exists. Registers returned by registerFor do not112 // require explicit reference counting.113 RegisterID* registerFor(const Identifier&);114 115 249 bool isArgumentNumber(const Identifier&, int); 116 250 … … 120 254 RegisterID* uncheckedRegisterForArguments(); 121 255 122 // Behaves as registerFor does, but ignores dynamic scope as 256 // Resolve an identifier, given the current compile-time scope chain. 257 ResolveResult resolve(const Identifier&); 258 // Behaves as resolve does, but ignores dynamic scope as 123 259 // dynamic scope should not interfere with const initialisation 124 RegisterID* constRegisterFor(const Identifier&); 125 126 // Searches the scope chain in an attempt to statically locate the requested 127 // property. Returns false if for any reason the property cannot be safely 128 // optimised at all. Otherwise it will return the index and depth of the 129 // VariableObject that defines the property. If the property cannot be found 130 // statically, depth will contain the depth of the scope chain where dynamic 131 // lookup must begin. 132 bool findScopedProperty(const Identifier&, int& index, size_t& depth, bool forWriting, bool& includesDynamicScopes, JSObject*& globalObject); 260 ResolveResult resolveConstDecl(const Identifier&); 133 261 134 262 // Returns the register storing "this" … … 310 438 RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); } 311 439 312 RegisterID* emit Resolve(RegisterID* dst, const Identifier& property);313 RegisterID* emit GetScopedVar(RegisterID* dst, size_t skip, int index, JSValue globalObject);314 RegisterID* emitPutScopedVar(size_t skip, int index, RegisterID* value, JSValue globalObject); 315 316 RegisterID* emitResolveBase(RegisterID* dst, const Identifier& property);317 RegisterID* emitResolveBaseForPut(RegisterID* dst, const Identifier& property);318 RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property);319 RegisterID* emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const Identifier& property);440 RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&); 441 RegisterID* emitPutStaticVar(const ResolveResult&, RegisterID* value); 442 443 RegisterID* emitResolve(RegisterID* dst, const ResolveResult&, const Identifier& property); 444 RegisterID* emitResolveBase(RegisterID* dst, const ResolveResult&, const Identifier& property); 445 RegisterID* emitResolveBaseForPut(RegisterID* dst, const ResolveResult&, const Identifier& property); 446 RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property); 447 RegisterID* emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property); 320 448 321 449 void emitMethodCheck(); -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r106255 r106478 6 6 * Copyright (C) 2007 Maks Orlovich 7 7 * Copyright (C) 2007 Eric Seidel <eric@webkit.org> 8 * Copyright (C) 2012 Igalia, S.L. 8 9 * 9 10 * This library is free software; you can redistribute it and/or … … 147 148 RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) 148 149 { 149 if (RegisterID* local = generator.registerFor(m_ident)) { 150 ResolveResult resolveResult = generator.resolve(m_ident); 151 if (RegisterID* local = resolveResult.local()) { 150 152 if (dst == generator.ignoredResult()) 151 153 return 0; … … 154 156 155 157 generator.emitExpressionInfo(m_startOffset + m_ident.length(), m_ident.length(), 0); 156 return generator.emitResolve(generator.finalDestination(dst), m_ident);158 return generator.emitResolve(generator.finalDestination(dst), resolveResult, m_ident); 157 159 } 158 160 … … 399 401 CallArguments callArguments(generator, m_args); 400 402 generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); 401 generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), generator. propertyNames().eval);403 generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), generator.resolve(generator.propertyNames().eval), generator.propertyNames().eval); 402 404 return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); 403 405 } … … 417 419 RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) 418 420 { 419 if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) { 420 RefPtr<RegisterID> function = generator.emitMove(generator.tempDestination(dst), local.get()); 421 ResolveResult resolveResult = generator.resolve(m_ident); 422 423 if (RegisterID* local = resolveResult.local()) { 424 RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local); 421 425 CallArguments callArguments(generator, m_args); 422 426 generator.emitLoad(callArguments.thisRegister(), jsUndefined()); 423 return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), function.get(), callArguments, divot(), startOffset(), endOffset()); 424 } 425 426 int index = 0; 427 size_t depth = 0; 428 JSObject* globalObject = 0; 429 bool requiresDynamicChecks = false; 430 if (generator.findScopedProperty(m_ident, index, depth, false, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { 431 RefPtr<RegisterID> func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); 427 return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), callArguments, divot(), startOffset(), endOffset()); 428 } 429 430 if (resolveResult.isStatic()) { 431 RefPtr<RegisterID> func = generator.newTemporary(); 432 432 CallArguments callArguments(generator, m_args); 433 generator.emitGetStaticVar(func.get(), resolveResult); 433 434 generator.emitLoad(callArguments.thisRegister(), jsUndefined()); 434 435 return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); … … 438 439 CallArguments callArguments(generator, m_args); 439 440 int identifierStart = divot() - startOffset(); 441 440 442 generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0); 441 generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), m_ident);443 generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), resolveResult, m_ident); 442 444 return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); 443 445 } … … 603 605 RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) 604 606 { 605 if (RegisterID* local = generator.registerFor(m_ident)) { 606 if (generator.isLocalConstant(m_ident)) { 607 ResolveResult resolveResult = generator.resolve(m_ident); 608 609 if (RegisterID* local = resolveResult.local()) { 610 if (resolveResult.isReadOnly()) { 607 611 if (dst == generator.ignoredResult()) 608 612 return 0; 609 613 return generator.emitToJSNumber(generator.finalDestination(dst), local); 610 614 } 611 612 615 if (dst == generator.ignoredResult()) 613 616 return emitPreIncOrDec(generator, local, m_operator); … … 615 618 } 616 619 617 int index = 0; 618 size_t depth = 0; 619 JSObject* globalObject = 0; 620 bool requiresDynamicChecks = false; 621 if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { 622 RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); 620 if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { 621 RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult); 623 622 RegisterID* oldValue; 624 623 if (dst == generator.ignoredResult()) { … … 628 627 oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); 629 628 } 630 generator.emitPutS copedVar(depth, index, value.get(), globalObject);629 generator.emitPutStaticVar(resolveResult, value.get()); 631 630 return oldValue; 632 631 } 633 632 634 633 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); 635 634 RefPtr<RegisterID> value = generator.newTemporary(); 636 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident);635 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), resolveResult, m_ident); 637 636 RegisterID* oldValue; 638 637 if (dst == generator.ignoredResult()) { … … 706 705 RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) 707 706 { 708 if (generator.registerFor(m_ident)) 707 ResolveResult resolveResult = generator.resolve(m_ident); 708 if (resolveResult.isRegister()) 709 709 return generator.emitLoad(generator.finalDestination(dst), false); 710 710 711 711 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); 712 RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident);712 RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), resolveResult, m_ident); 713 713 return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident); 714 714 } … … 761 761 RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) 762 762 { 763 if (RegisterID* local = generator.registerFor(m_ident)) { 763 ResolveResult resolveResult = generator.resolve(m_ident); 764 if (RegisterID* local = resolveResult.local()) { 764 765 if (dst == generator.ignoredResult()) 765 766 return 0; … … 767 768 } 768 769 769 RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident);770 RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), resolveResult, m_ident); 770 771 generator.emitGetById(scratch.get(), scratch.get(), m_ident); 771 772 if (dst == generator.ignoredResult()) … … 790 791 RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) 791 792 { 792 if (RegisterID* local = generator.registerFor(m_ident)) { 793 ResolveResult resolveResult = generator.resolve(m_ident); 794 if (RegisterID* local = resolveResult.local()) { 793 795 if (generator.isLocalConstant(m_ident)) { 794 796 if (dst == generator.ignoredResult()) … … 797 799 return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes()); 798 800 } 799 800 801 emitPreIncOrDec(generator, local, m_operator); 801 802 return generator.moveToDestinationIfNeeded(dst, local); 802 803 } 803 804 804 int index = 0; 805 size_t depth = 0; 806 JSObject* globalObject = 0; 807 bool requiresDynamicChecks = false; 808 if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { 809 RefPtr<RegisterID> propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); 805 if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { 806 RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult); 810 807 emitPreIncOrDec(generator, propDst.get(), m_operator); 811 generator.emitPutS copedVar(depth, index, propDst.get(), globalObject);808 generator.emitPutStaticVar(resolveResult, propDst.get()); 812 809 return generator.moveToDestinationIfNeeded(dst, propDst.get()); 813 810 } … … 815 812 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); 816 813 RefPtr<RegisterID> propDst = generator.tempDestination(dst); 817 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident);814 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), resolveResult, m_ident); 818 815 emitPreIncOrDec(generator, propDst.get(), m_operator); 819 816 generator.emitPutById(base.get(), m_ident, propDst.get()); … … 1203 1200 RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) 1204 1201 { 1205 if (RegisterID* local = generator.registerFor(m_ident)) { 1206 if (generator.isLocalConstant(m_ident)) { 1202 ResolveResult resolveResult = generator.resolve(m_ident); 1203 1204 if (RegisterID *local = resolveResult.local()) { 1205 if (resolveResult.isReadOnly()) 1207 1206 return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); 1208 }1209 1207 1210 1208 if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { … … 1220 1218 } 1221 1219 1222 int index = 0; 1223 size_t depth = 0; 1224 JSObject* globalObject = 0; 1225 bool requiresDynamicChecks = false; 1226 if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { 1227 RefPtr<RegisterID> src1 = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); 1220 if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { 1221 RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult); 1228 1222 RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); 1229 generator.emitPutS copedVar(depth, index, result, globalObject);1223 generator.emitPutStaticVar(resolveResult, result); 1230 1224 return result; 1231 1225 } … … 1233 1227 RefPtr<RegisterID> src1 = generator.tempDestination(dst); 1234 1228 generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0); 1235 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident);1229 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), resolveResult, m_ident); 1236 1230 RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); 1237 1231 return generator.emitPutById(base.get(), m_ident, result); … … 1242 1236 RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) 1243 1237 { 1244 if (RegisterID* local = generator.registerFor(m_ident)) { 1245 if (generator.isLocalConstant(m_ident)) 1238 ResolveResult resolveResult = generator.resolve(m_ident); 1239 1240 if (RegisterID *local = resolveResult.local()) { 1241 if (resolveResult.isReadOnly()) 1246 1242 return generator.emitNode(dst, m_right); 1247 1248 1243 RegisterID* result = generator.emitNode(local, m_right); 1249 1244 return generator.moveToDestinationIfNeeded(dst, result); 1250 1245 } 1251 1246 1252 int index = 0; 1253 size_t depth = 0; 1254 JSObject* globalObject = 0; 1255 bool requiresDynamicChecks = false; 1256 if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { 1247 if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { 1257 1248 if (dst == generator.ignoredResult()) 1258 1249 dst = 0; 1259 1250 RegisterID* value = generator.emitNode(dst, m_right); 1260 generator.emitPutS copedVar(depth, index, value, globalObject);1251 generator.emitPutStaticVar(resolveResult, value); 1261 1252 return value; 1262 1253 } 1263 1254 1264 RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), m_ident);1255 RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident); 1265 1256 if (dst == generator.ignoredResult()) 1266 1257 dst = 0; … … 1350 1341 RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) 1351 1342 { 1343 ResolveResult resolveResult = generator.resolveConstDecl(m_ident); 1344 1352 1345 // FIXME: This code does not match the behavior of const in Firefox. 1353 if (RegisterID* local = generator.constRegisterFor(m_ident)) {1346 if (RegisterID* local = resolveResult.local()) { 1354 1347 if (!m_init) 1355 1348 return local; … … 1360 1353 RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); 1361 1354 1362 ScopeChainIterator iter = generator.scopeChain()->begin(); 1363 ScopeChainIterator end = generator.scopeChain()->end(); 1364 size_t depth = 0; 1365 for (; iter != end; ++iter, ++depth) { 1366 JSObject* currentScope = iter->get(); 1367 if (!currentScope->isVariableObject()) 1368 continue; 1369 JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope); 1370 SymbolTableEntry entry = currentVariableObject->symbolTable().get(m_ident.impl()); 1371 if (entry.isNull()) 1372 continue; 1373 1374 return generator.emitPutScopedVar(generator.scopeDepth() + depth, entry.getIndex(), value.get(), currentVariableObject->isGlobalObject() ? currentVariableObject : 0); 1375 } 1376 1355 if (resolveResult.isStatic()) 1356 return generator.emitPutStaticVar(resolveResult, value.get()); 1357 1377 1358 if (generator.codeType() != EvalCode) 1378 1359 return value.get(); … … 1380 1361 // FIXME: While this code should only be hit in an eval block, it will assign 1381 1362 // to the wrong base if m_ident exists in an intervening with scope. 1382 RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident);1363 RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), resolveResult, m_ident); 1383 1364 return generator.emitPutById(base.get(), m_ident, value.get()); 1384 1365 } … … 1651 1632 if (m_lexpr->isResolveNode()) { 1652 1633 const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); 1653 propertyName = generator.registerFor(ident); 1634 ResolveResult resolveResult = generator.resolve(ident); 1635 propertyName = resolveResult.local(); 1654 1636 if (!propertyName) { 1655 1637 propertyName = generator.newTemporary(); 1656 1638 RefPtr<RegisterID> protect = propertyName; 1657 RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), ident);1639 RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident); 1658 1640 1659 1641 generator.emitExpressionInfo(divot(), startOffset(), endOffset());
Note:
See TracChangeset
for help on using the changeset viewer.