shell_g
/obj/
/test/es5conform/data/
+/test/mozilla/data/
/test/sputnik/sputniktests/
/tools/oom_dump/oom_dump
/tools/oom_dump/oom_dump.o
if (property != NULL) {
Load(property->obj());
Load(property->key());
- frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, 2);
+ frame_->EmitPush(Operand(Smi::FromInt(strict_mode_flag())));
+ frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, 3);
frame_->EmitPush(r0);
} else if (variable != NULL) {
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // so this code can only be reached in non-strict mode.
+ ASSERT(strict_mode_flag() == kNonStrictMode);
Slot* slot = variable->AsSlot();
if (variable->is_global()) {
LoadGlobal();
frame_->EmitPush(Operand(variable->name()));
- frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, 2);
+ frame_->EmitPush(Operand(Smi::FromInt(kNonStrictMode)));
+ frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, 3);
frame_->EmitPush(r0);
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
} else {
VisitForStackValue(prop->obj());
VisitForStackValue(prop->key());
+ __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
+ __ push(r1);
__ InvokeBuiltin(Builtins::DELETE, CALL_JS);
context()->Plug(r0);
}
} else if (var != NULL) {
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // so this code can only be reached in non-strict mode.
+ ASSERT(strict_mode_flag() == kNonStrictMode);
if (var->is_global()) {
- __ ldr(r1, GlobalObjectOperand());
- __ mov(r0, Operand(var->name()));
- __ Push(r1, r0);
+ __ ldr(r2, GlobalObjectOperand());
+ __ mov(r1, Operand(var->name()));
+ __ mov(r0, Operand(Smi::FromInt(kNonStrictMode)));
+ __ Push(r2, r1, r0);
__ InvokeBuiltin(Builtins::DELETE, CALL_JS);
context()->Plug(r0);
} else if (var->AsSlot() != NULL &&
void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
Register object = ToRegister(instr->object());
Register key = ToRegister(instr->key());
- __ Push(object, key);
+ Register strict = scratch0();
+ __ mov(strict, Operand(Smi::FromInt(strict_mode_flag())));
+ __ Push(object, key, strict);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
bool is_done() const { return status_ == DONE; }
bool is_aborted() const { return status_ == ABORTED; }
+ int strict_mode_flag() const {
+ return info_->is_strict() ? kStrictMode : kNonStrictMode;
+ }
+
LChunk* chunk() const { return chunk_; }
Scope* scope() const { return scope_; }
HGraph* graph() const { return chunk_->graph(); }
V(SHL, 1) \
V(SAR, 1) \
V(SHR, 1) \
- V(DELETE, 1) \
+ V(DELETE, 2) \
V(IN, 1) \
V(INSTANCE_OF, 1) \
V(GET_KEYS, 0) \
if (property != NULL) {
Load(property->obj());
Load(property->key());
- Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2);
+ frame_->Push(Smi::FromInt(strict_mode_flag()));
+ Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 3);
frame_->Push(&answer);
return;
}
Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
if (variable != NULL) {
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // so this code can only be reached in non-strict mode.
+ ASSERT(strict_mode_flag() == kNonStrictMode);
Slot* slot = variable->AsSlot();
if (variable->is_global()) {
LoadGlobal();
frame_->Push(variable->name());
+ frame_->Push(Smi::FromInt(kNonStrictMode));
Result answer = frame_->InvokeBuiltin(Builtins::DELETE,
- CALL_FUNCTION, 2);
+ CALL_FUNCTION, 3);
frame_->Push(&answer);
return;
} else {
VisitForStackValue(prop->obj());
VisitForStackValue(prop->key());
+ __ push(Immediate(Smi::FromInt(strict_mode_flag())));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(eax);
}
} else if (var != NULL) {
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // so this code can only be reached in non-strict mode.
+ ASSERT(strict_mode_flag() == kNonStrictMode);
if (var->is_global()) {
__ push(GlobalObjectOperand());
__ push(Immediate(var->name()));
+ __ push(Immediate(Smi::FromInt(kNonStrictMode)));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(eax);
} else if (var->AsSlot() != NULL &&
pointers,
env->deoptimization_index());
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+ __ push(Immediate(Smi::FromInt(strict_mode_flag())));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
}
bool is_done() const { return status_ == DONE; }
bool is_aborted() const { return status_ == ABORTED; }
+ int strict_mode_flag() const {
+ return info_->is_strict() ? kStrictMode : kNonStrictMode;
+ }
+
LChunk* chunk() const { return chunk_; }
Scope* scope() const { return scope_; }
HGraph* graph() const { return chunk_->graph(); }
strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
strict_reserved_word: ["Use of future reserved word in strict mode"],
strict_delete: ["Delete of an unqualified identifier in strict mode."],
+ strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"],
};
}
var message_type = %MessageGetType(message);
if (!map()->is_extensible()) {
Handle<Object> args[1] = {Handle<String>(name)};
return Top::Throw(*Factory::NewTypeError("object_not_extensible",
- HandleVector(args, 1)));
+ HandleVector(args, 1)));
}
if (HasFastProperties()) {
// Ensure the descriptor array does not get too big.
NumberDictionary* dictionary = element_dictionary();
int entry = dictionary->FindEntry(index);
if (entry != NumberDictionary::kNotFound) {
- return dictionary->DeleteProperty(entry, mode);
+ Object* result = dictionary->DeleteProperty(entry, mode);
+ if (mode == STRICT_DELETION && result == Heap::false_value()) {
+ // In strict mode, deleting a non-configurable property throws
+ // exception. dictionary->DeleteProperty will return false_value()
+ // if a non-configurable property is being deleted.
+ HandleScope scope;
+ Handle<Object> i = Factory::NewNumberFromUint(index);
+ Handle<Object> args[2] = { i, Handle<Object>(this) };
+ return Top::Throw(*Factory::NewTypeError("strict_delete_property",
+ HandleVector(args, 2)));
+ }
}
break;
}
if (!result.IsProperty()) return Heap::true_value();
// Ignore attributes if forcing a deletion.
if (result.IsDontDelete() && mode != FORCE_DELETION) {
+ if (mode == STRICT_DELETION) {
+ // Deleting a non-configurable property in strict mode.
+ HandleScope scope;
+ Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
+ return Top::Throw(*Factory::NewTypeError("strict_delete_property",
+ HandleVector(args, 2)));
+ }
return Heap::false_value();
}
// Check for interceptor.
JSObject::DeleteMode mode) {
PropertyDetails details = DetailsAt(entry);
// Ignore attributes if forcing a deletion.
- if (details.IsDontDelete() && mode == JSObject::NORMAL_DELETION) {
+ if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) {
return Heap::false_value();
}
SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0));
// caching.
class JSObject: public HeapObject {
public:
- enum DeleteMode { NORMAL_DELETION, FORCE_DELETION };
+ enum DeleteMode {
+ NORMAL_DELETION,
+ STRICT_DELETION,
+ FORCE_DELETION
+ };
+
enum ElementsKind {
// The only "fast" kind.
FAST_ELEMENTS,
static MaybeObject* Runtime_DeleteProperty(Arguments args) {
NoHandleAllocation ha;
- ASSERT(args.length() == 2);
+ ASSERT(args.length() == 3);
CONVERT_CHECKED(JSObject, object, args[0]);
CONVERT_CHECKED(String, key, args[1]);
- return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
+ CONVERT_SMI_CHECKED(strict, args[2]);
+ return object->DeleteProperty(key, strict == kStrictMode
+ ? JSObject::STRICT_DELETION
+ : JSObject::NORMAL_DELETION);
}
/* Property access */ \
F(GetProperty, 2, 1) \
F(KeyedGetProperty, 2, 1) \
- F(DeleteProperty, 2, 1) \
+ F(DeleteProperty, 3, 1) \
F(HasLocalProperty, 2, 1) \
F(HasProperty, 2, 1) \
F(HasElement, 2, 1) \
*/
// ECMA-262, section 11.4.1, page 46.
-function DELETE(key) {
- return %DeleteProperty(%ToObject(this), %ToString(key));
+function DELETE(key, strict) {
+ return %DeleteProperty(%ToObject(this), %ToString(key), strict);
}
if (property != NULL) {
Load(property->obj());
Load(property->key());
- Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2);
+ frame_->Push(Smi::FromInt(strict_mode_flag()));
+ Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 3);
frame_->Push(&answer);
return;
}
Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
if (variable != NULL) {
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // so this code can only be reached in non-strict mode.
+ ASSERT(strict_mode_flag() == kNonStrictMode);
Slot* slot = variable->AsSlot();
if (variable->is_global()) {
LoadGlobal();
frame_->Push(variable->name());
+ frame_->Push(Smi::FromInt(kNonStrictMode));
Result answer = frame_->InvokeBuiltin(Builtins::DELETE,
- CALL_FUNCTION, 2);
+ CALL_FUNCTION, 3);
frame_->Push(&answer);
return;
} else {
VisitForStackValue(prop->obj());
VisitForStackValue(prop->key());
+ __ Push(Smi::FromInt(strict_mode_flag()));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(rax);
}
} else if (var != NULL) {
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // so this code can only be reached in non-strict mode.
+ ASSERT(strict_mode_flag() == kNonStrictMode);
if (var->is_global()) {
__ push(GlobalObjectOperand());
__ Push(var->name());
+ __ Push(Smi::FromInt(kNonStrictMode));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(rax);
} else if (var->AsSlot() != NULL &&
# in strict mode (Global.undefined)
chapter11/11.13/11.13.1/11.13.1-4-27-s: FAIL
-# delete operator throws TypeError when deleting a non-configurable data
-# property in strict mode
-chapter11/11.4/11.4.1/11.4.1-4.a-3-s: FAIL
# delete operator throws TypeError when when deleting a non-configurable
# data property in strict mode (Global.NaN)
-chapter11/11.4/11.4.1/11.4.1-4.a-4-s: FAIL
-# delete operator throws TypeError when deleting a non-configurable data
-# property in strict mode (Math.LN2)
-chapter11/11.4/11.4.1/11.4.1-4.a-9-s: FAIL
+# Invalid test case - "this" is not a global object within the test case.
+# (http://es5conform.codeplex.com/workitem/29151)
+chapter11/11.4/11.4.1/11.4.1-4.a-4-s: FAIL_OK
# delete operator throws ReferenceError when deleting a direct reference
# to a var in strict mode
CheckStrictMode("function strict() { var x = --eval; }", SyntaxError);
CheckStrictMode("function strict() { var x = --arguments; }", SyntaxError);
-// Delete of an unqialified identifier
+// Delete of an unqualified identifier
CheckStrictMode("delete unqualified;", SyntaxError);
CheckStrictMode("function strict() { delete unqualified; }", SyntaxError);
CheckStrictMode("function function_name() { delete function_name; }",
repeat(10, function() { testAssignToUndefined(true); });
possibly_undefined_variable_for_strict_mode_test = undefined;
repeat(10, function() { testAssignToUndefined(false); });
+
+(function testDeleteNonConfigurable() {
+ function delete_property(o) {
+ "use strict";
+ delete o.property;
+ }
+ function delete_element(o, i) {
+ "use strict";
+ delete o[i];
+ }
+
+ var object = {};
+
+ Object.defineProperty(object, "property", { value: "property_value" });
+ Object.defineProperty(object, "1", { value: "one" });
+ Object.defineProperty(object, 7, { value: "seven" });
+ Object.defineProperty(object, 3.14, { value: "pi" });
+
+ assertThrows(function() { delete_property(object); }, TypeError);
+ assertEquals(object.property, "property_value");
+ assertThrows(function() { delete_element(object, "1"); }, TypeError);
+ assertThrows(function() { delete_element(object, 1); }, TypeError);
+ assertEquals(object[1], "one");
+ assertThrows(function() { delete_element(object, "7"); }, TypeError);
+ assertThrows(function() { delete_element(object, 7); }, TypeError);
+ assertEquals(object[7], "seven");
+ assertThrows(function() { delete_element(object, "3.14"); }, TypeError);
+ assertThrows(function() { delete_element(object, 3.14); }, TypeError);
+ assertEquals(object[3.14], "pi");
+})();