Changeset 69940 in webkit
- Timestamp:
- Oct 17, 2010 9:08:37 PM (14 years ago)
- Location:
- trunk
- Files:
-
- 20 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r69929 r69940 1 2010-10-17 Oliver Hunt <oliver@apple.com> 2 3 Reviewed by Sam Weinig. 4 5 Strict mode: Assignment that would create a global should be a late ReferenceError, not a syntax failure 6 https://bugs.webkit.org/show_bug.cgi?id=47788 7 8 Fixing this required a couple of changes: 9 * resolve_base now has a flag to indicate whether it is being used for a put in strict mode. 10 this allows us to throw an exception when we're doing a completely generic resolve for 11 assignment, and that assignment would create a new global. 12 * There is a new opcode 'op_ensure_property_exists' that is used to determine whether 13 the property being assigned to already exists on the global object. This currently 14 has no caching, but such caching could be added relatively trivially. It is only used 15 in the case where we know that a property will be placed on the global object, and 16 we cannot verify that the property already exists. 17 18 In the jit we plant a call to cti_op_resolve_base_strict_put in the effected case rather 19 than making op_resolve_base have an additional runtime branch. 20 21 There's also a new helper function to create the exception for the invalid assignment. 22 23 * bytecode/CodeBlock.cpp: 24 (JSC::CodeBlock::dump): 25 * bytecode/Opcode.h: 26 * bytecompiler/BytecodeGenerator.cpp: 27 (JSC::BytecodeGenerator::emitResolveBase): 28 (JSC::BytecodeGenerator::emitResolveBaseForPut): 29 * bytecompiler/BytecodeGenerator.h: 30 * bytecompiler/NodesCodegen.cpp: 31 (JSC::AssignResolveNode::emitBytecode): 32 (JSC::ForInNode::emitBytecode): 33 * interpreter/Interpreter.cpp: 34 (JSC::Interpreter::resolveBase): 35 (JSC::Interpreter::privateExecute): 36 * jit/JIT.cpp: 37 (JSC::JIT::privateCompileMainPass): 38 * jit/JIT.h: 39 * jit/JITOpcodes.cpp: 40 (JSC::JIT::emit_op_resolve_base): 41 (JSC::JIT::emit_op_ensure_property_exists): 42 * jit/JITOpcodes32_64.cpp: 43 (JSC::JIT::emit_op_resolve_base): 44 (JSC::JIT::emit_op_ensure_property_exists): 45 * jit/JITStubs.cpp: 46 (JSC::DEFINE_STUB_FUNCTION): 47 * jit/JITStubs.h: 48 * parser/JSParser.cpp: 49 (JSC::JSParser::parseProgram): 50 * runtime/ExceptionHelpers.cpp: 51 (JSC::createErrorForInvalidGlobalAssignment): 52 * runtime/ExceptionHelpers.h: 53 * runtime/Operations.h: 54 (JSC::resolveBase): 55 1 56 2010-10-17 Simon Fraser <simon.fraser@apple.com> 2 57 -
trunk/JavaScriptCore/bytecode/CodeBlock.cpp
r69665 r69940 762 762 int r0 = (++it)->u.operand; 763 763 int id0 = (++it)->u.operand; 764 printf("[%4d] resolve_base\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); 764 int isStrict = (++it)->u.operand; 765 printf("[%4d] resolve_base%s\t %s, %s\n", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); 766 break; 767 } 768 case op_ensure_property_exists: { 769 int r0 = (++it)->u.operand; 770 int id0 = (++it)->u.operand; 771 printf("[%4d] ensure_property_exists\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); 765 772 break; 766 773 } -
trunk/JavaScriptCore/bytecode/Opcode.h
r69516 r69940 101 101 macro(op_get_global_var, 3) \ 102 102 macro(op_put_global_var, 3) \ 103 macro(op_resolve_base, 3) \ 103 macro(op_resolve_base, 4) \ 104 macro(op_ensure_property_exists, 3) \ 104 105 macro(op_resolve_with_base, 4) \ 105 106 macro(op_get_by_id, 8) \ -
trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r69516 r69940 1272 1272 instructions().append(dst->index()); 1273 1273 instructions().append(addConstant(property)); 1274 instructions().append(false); 1274 1275 return dst; 1275 1276 } … … 1277 1278 // Global object is the base 1278 1279 return emitLoad(dst, JSValue(globalObject)); 1280 } 1281 1282 RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Identifier& property) 1283 { 1284 if (!m_codeBlock->isStrictMode()) 1285 return emitResolveBase(dst, property); 1286 size_t depth = 0; 1287 int index = 0; 1288 JSObject* globalObject = 0; 1289 bool requiresDynamicChecks = false; 1290 findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject); 1291 if (!globalObject || requiresDynamicChecks) { 1292 // We can't optimise at all :-( 1293 emitOpcode(op_resolve_base); 1294 instructions().append(dst->index()); 1295 instructions().append(addConstant(property)); 1296 instructions().append(true); 1297 return dst; 1298 } 1299 1300 // Global object is the base 1301 RefPtr<RegisterID> result = emitLoad(dst, JSValue(globalObject)); 1302 emitOpcode(op_ensure_property_exists); 1303 instructions().append(dst->index()); 1304 instructions().append(addConstant(property)); 1305 return result.get(); 1279 1306 } 1280 1307 -
trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.h
r69516 r69940 330 330 331 331 RegisterID* emitResolveBase(RegisterID* dst, const Identifier& property); 332 RegisterID* emitResolveBaseForPut(RegisterID* dst, const Identifier& property); 332 333 RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property); 333 334 -
trunk/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r69663 r69940 1232 1232 } 1233 1233 1234 RefPtr<RegisterID> base = generator.emitResolveBase (generator.newTemporary(), m_ident);1234 RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), m_ident); 1235 1235 if (dst == generator.ignoredResult()) 1236 1236 dst = 0; … … 1606 1606 propertyName = generator.newTemporary(); 1607 1607 RefPtr<RegisterID> protect = propertyName; 1608 RegisterID* base = generator.emitResolveBase (generator.newTemporary(), ident);1608 RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), ident); 1609 1609 1610 1610 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); -
trunk/JavaScriptCore/interpreter/Interpreter.cpp
r69522 r69940 281 281 int dst = vPC[1].u.operand; 282 282 int property = vPC[2].u.operand; 283 callFrame->r(dst) = JSValue(JSC::resolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain())); 284 ASSERT(callFrame->r(dst).jsValue()); 283 bool isStrictPut = vPC[3].u.operand; 284 const Identifier ident = callFrame->codeBlock()->identifier(property); 285 JSValue result = JSC::resolveBase(callFrame, ident, callFrame->scopeChain(), isStrictPut); 286 if (!result) { 287 callFrame->r(dst) = result; 288 ASSERT(callFrame->r(dst).jsValue()); 289 } else 290 callFrame->globalData().exception = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring()); 285 291 } 286 292 … … 2431 2437 2432 2438 vPC += OPCODE_LENGTH(op_resolve_base); 2439 NEXT_INSTRUCTION(); 2440 } 2441 DEFINE_OPCODE(op_ensure_property_exists) { 2442 /* ensure_property_exists base(r) property(id) 2443 2444 Throws an exception if property does not exist on base 2445 */ 2446 int base = vPC[1].u.operand; 2447 int property = vPC[2].u.operand; 2448 Identifier& ident = codeBlock->identifier(property); 2449 2450 JSValue baseVal = callFrame->r(base).jsValue(); 2451 JSObject* baseObject = asObject(baseVal); 2452 PropertySlot slot(baseVal); 2453 if (!baseObject->getPropertySlot(callFrame, ident, slot)) { 2454 exceptionValue = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring()); 2455 goto vm_throw; 2456 } 2433 2457 NEXT_INSTRUCTION(); 2434 2458 } -
trunk/JavaScriptCore/jit/JIT.cpp
r69516 r69940 303 303 DEFINE_OP(op_resolve) 304 304 DEFINE_OP(op_resolve_base) 305 DEFINE_OP(op_ensure_property_exists) 305 306 DEFINE_OP(op_resolve_global) 306 307 DEFINE_OP(op_resolve_global_dynamic) -
trunk/JavaScriptCore/jit/JIT.h
r69516 r69940 812 812 void emit_op_resolve(Instruction*); 813 813 void emit_op_resolve_base(Instruction*); 814 void emit_op_ensure_property_exists(Instruction*); 814 815 void emit_op_resolve_global(Instruction*, bool dynamic = false); 815 816 void emit_op_resolve_global_dynamic(Instruction*); -
trunk/JavaScriptCore/jit/JITOpcodes.cpp
r69516 r69940 645 645 void JIT::emit_op_resolve_base(Instruction* currentInstruction) 646 646 { 647 JITStubCall stubCall(this, cti_op_resolve_base); 647 JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base); 648 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 649 stubCall.call(currentInstruction[1].u.operand); 650 } 651 652 void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction) 653 { 654 JITStubCall stubCall(this, cti_op_ensure_property_exists); 655 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 648 656 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 649 657 stubCall.call(currentInstruction[1].u.operand); -
trunk/JavaScriptCore/jit/JITOpcodes32_64.cpp
r69533 r69940 738 738 void JIT::emit_op_resolve_base(Instruction* currentInstruction) 739 739 { 740 JITStubCall stubCall(this, cti_op_resolve_base); 740 JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base); 741 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 742 stubCall.call(currentInstruction[1].u.operand); 743 } 744 745 void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction) 746 { 747 JITStubCall stubCall(this, cti_op_ensure_property_exists); 748 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 741 749 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 742 750 stubCall.call(currentInstruction[1].u.operand); -
trunk/JavaScriptCore/jit/JITStubs.cpp
r69516 r69940 2698 2698 STUB_INIT_STACK_FRAME(stackFrame); 2699 2699 2700 return JSValue::encode(JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain())); 2701 } 2702 2700 return JSValue::encode(JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), false)); 2701 } 2702 2703 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base_strict_put) 2704 { 2705 STUB_INIT_STACK_FRAME(stackFrame); 2706 JSValue base = JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), true); 2707 if (!base) { 2708 stackFrame.globalData->exception = createErrorForInvalidGlobalAssignment(stackFrame.callFrame, stackFrame.args[0].identifier().ustring()); 2709 VM_THROW_EXCEPTION(); 2710 } 2711 return JSValue::encode(base); 2712 } 2713 2714 DEFINE_STUB_FUNCTION(EncodedJSValue, op_ensure_property_exists) 2715 { 2716 STUB_INIT_STACK_FRAME(stackFrame); 2717 JSValue base = stackFrame.callFrame->r(stackFrame.args[0].int32()).jsValue(); 2718 JSObject* object = asObject(base); 2719 PropertySlot slot(object); 2720 ASSERT(stackFrame.callFrame->codeBlock()->isStrictMode()); 2721 if (!object->getPropertySlot(stackFrame.callFrame, stackFrame.args[1].identifier(), slot)) { 2722 stackFrame.globalData->exception = createErrorForInvalidGlobalAssignment(stackFrame.callFrame, stackFrame.args[1].identifier().ustring()); 2723 VM_THROW_EXCEPTION(); 2724 } 2725 2726 return JSValue::encode(base); 2727 } 2728 2703 2729 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip) 2704 2730 { -
trunk/JavaScriptCore/jit/JITStubs.h
r69516 r69940 339 339 EncodedJSValue JIT_STUB cti_op_resolve(STUB_ARGS_DECLARATION); 340 340 EncodedJSValue JIT_STUB cti_op_resolve_base(STUB_ARGS_DECLARATION); 341 EncodedJSValue JIT_STUB cti_op_resolve_base_strict_put(STUB_ARGS_DECLARATION); 342 EncodedJSValue JIT_STUB cti_op_ensure_property_exists(STUB_ARGS_DECLARATION); 341 343 EncodedJSValue JIT_STUB cti_op_resolve_global(STUB_ARGS_DECLARATION); 342 344 EncodedJSValue JIT_STUB cti_op_resolve_global_dynamic(STUB_ARGS_DECLARATION); -
trunk/JavaScriptCore/parser/JSParser.cpp
r69906 r69940 530 530 return true; 531 531 if (!m_syntaxAlreadyValidated) { 532 IdentifierSet writtenVariables;533 scope->getUncapturedWrittenVariables(writtenVariables);534 IdentifierSet::const_iterator end = writtenVariables.end();535 for (IdentifierSet::const_iterator ptr = writtenVariables.begin(); ptr != end; ++ptr) {536 PropertySlot slot(lexicalGlobalObject);537 if (!lexicalGlobalObject->getPropertySlot(lexicalGlobalObject->globalExec(), Identifier(m_globalData, *ptr), slot))538 return true;539 }540 532 IdentifierSet deletedVariables; 541 533 if (!scope->getDeletedVariables(deletedVariables)) 542 534 return true; 543 end = deletedVariables.end();535 IdentifierSet::const_iterator end = deletedVariables.end(); 544 536 SymbolTable& globalEnvRecord = lexicalGlobalObject->symbolTable(); 545 537 for (IdentifierSet::const_iterator ptr = deletedVariables.begin(); ptr != end; ++ptr) { -
trunk/JavaScriptCore/runtime/ExceptionHelpers.cpp
r69663 r69940 193 193 } 194 194 195 JSObject* createErrorForInvalidGlobalAssignment(ExecState* exec, const UString& propertyName) 196 { 197 return createReferenceError(exec, makeUString("Strict mode forbids implicit creation of global property '", propertyName, "'")); 198 } 199 195 200 } // namespace JSC -
trunk/JavaScriptCore/runtime/ExceptionHelpers.h
r66150 r69940 55 55 JSObject* createNotAnObjectError(ExecState*, JSNotAnObjectErrorStub*, unsigned bytecodeOffset, CodeBlock*); 56 56 JSValue throwOutOfMemoryError(ExecState*); 57 JSObject* createErrorForInvalidGlobalAssignment(ExecState*, const UString&); 57 58 58 59 } // namespace JSC -
trunk/JavaScriptCore/runtime/Operations.h
r65177 r69940 461 461 } 462 462 463 ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain )463 ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain, bool isStrictPut) 464 464 { 465 465 ScopeChainIterator iter = scopeChain->begin(); … … 473 473 while (true) { 474 474 base = *iter; 475 if (next == end || base->getPropertySlot(callFrame, property, slot)) 475 if (next == end) 476 return isStrictPut ? JSValue() : base; 477 if (base->getPropertySlot(callFrame, property, slot)) 476 478 return base; 477 479 -
trunk/LayoutTests/ChangeLog
r69939 r69940 1 2010-10-17 Oliver Hunt <oliver@apple.com> 2 3 Reviewed by Sam Weinig. 4 5 Strict mode: Assignment that would create a global should be a late ReferenceError, not a syntax failure 6 https://bugs.webkit.org/show_bug.cgi?id=47788 7 8 Update test to check for the correct behaviour. 9 10 * fast/js/basic-strict-mode-expected.txt: 11 * fast/js/script-tests/basic-strict-mode.js: 12 1 13 2010-10-17 Antonio Gomes <agomes@rim.com> 2 14 -
trunk/LayoutTests/fast/js/basic-strict-mode-expected.txt
r69516 r69940 52 52 PASS 'use strict'; (function (){ delete someDeclaredGlobal;}) threw exception SyntaxError: Parse error. 53 53 PASS (function (){ 'use strict'; delete someDeclaredGlobal;}) threw exception SyntaxError: Parse error. 54 PASS 'use strict'; someGlobal = 'Shouldn\'t be able to assign this.'; someGlobal; threw exception SyntaxError: Parse error. 54 PASS 'use strict'; if (0) { someGlobal = 'Shouldn\'t be able to assign this.'; }; true; is true 55 PASS 'use strict'; someGlobal = 'Shouldn\'t be able to assign this.'; threw exception ReferenceError: Strict mode forbids implicit creation of global property 'someGlobal'. 55 56 PASS 'use strict'; eval('var introducedVariable = "FAIL: variable introduced into containing scope";'); introducedVariable threw exception ReferenceError: Can't find variable: introducedVariable. 56 57 PASS 'use strict'; objectWithReadonlyProperty.prop = 'fail' threw exception TypeError: Attempted to assign to readonly property.. -
trunk/LayoutTests/fast/js/script-tests/basic-strict-mode.js
r69516 r69940 61 61 shouldThrow("'use strict'; (function (){ delete someDeclaredGlobal;})"); 62 62 shouldThrow("(function (){ 'use strict'; delete someDeclaredGlobal;})"); 63 shouldThrow("'use strict'; someGlobal = 'Shouldn\\'t be able to assign this.'; someGlobal;"); 63 shouldBeTrue("'use strict'; if (0) { someGlobal = 'Shouldn\\'t be able to assign this.'; }; true;"); 64 shouldThrow("'use strict'; someGlobal = 'Shouldn\\'t be able to assign this.'; "); 64 65 shouldThrow("'use strict'; eval('var introducedVariable = \"FAIL: variable introduced into containing scope\";'); introducedVariable"); 65 66 var objectWithReadonlyProperty = {};
Note: See TracChangeset
for help on using the changeset viewer.