V(RegExpLiteral) \
V(ObjectLiteral) \
V(ArrayLiteral) \
+ V(CatchExtensionObject) \
V(Assignment) \
V(Throw) \
V(Property) \
};
+// Node for constructing a context extension object for a catch block.
+// The catch context extension object has one property, the catch
+// variable, which should be DontDelete.
+class CatchExtensionObject: public Expression {
+ public:
+ CatchExtensionObject(Literal* key, VariableProxy* value)
+ : key_(key), value_(value) {
+ }
+
+ virtual void Accept(AstVisitor* v);
+
+ Literal* key() const { return key_; }
+ VariableProxy* value() const { return value_; }
+
+ private:
+ Literal* key_;
+ VariableProxy* value_;
+};
+
+
class VariableProxy: public Expression {
public:
virtual void Accept(AstVisitor* v);
}
+void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) {
+ // Call runtime routine to allocate the catch extension object and
+ // assign the exception value to the catch variable.
+ Comment cmnt(masm_, "[CatchExtensionObject ");
+ Load(node->key());
+ Load(node->value());
+ __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
+ frame_->Push(r0);
+}
+
+
void CodeGenerator::VisitAssignment(Assignment* node) {
Comment cmnt(masm_, "[ Assignment");
CodeForStatement(node);
for (int i = 0; i < node->properties()->length(); i++) {
- ObjectLiteral::Property* property = node->properties()->at(i);
+ ObjectLiteral::Property* property = node->properties()->at(i);
switch (property->kind()) {
case ObjectLiteral::Property::CONSTANT: break;
case ObjectLiteral::Property::COMPUTED: {
}
+void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) {
+ // Call runtime routine to allocate the catch extension object and
+ // assign the exception value to the catch variable.
+ Comment cmnt(masm_, "[CatchExtensionObject ");
+ Load(node->key());
+ Load(node->value());
+ __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
+ frame_->Push(eax);
+}
+
+
bool CodeGenerator::IsInlineSmi(Literal* literal) {
if (literal == NULL || !literal->handle()->IsSmi()) return false;
int int_value = Smi::cast(*literal->handle())->value();
}
-Expression* Parser::MakeCatchContext(Handle<String> id, VariableProxy* value) {
- ZoneListWrapper<ObjectLiteral::Property> properties =
- factory()->NewList<ObjectLiteral::Property>(1);
- Literal* key = NEW(Literal(id));
- ObjectLiteral::Property* property = NEW(ObjectLiteral::Property(key, value));
- properties.Add(property);
-
- // This must be called always, even during pre-parsing!
- // (Computation of literal index must happen before pre-parse bailout.)
- int literal_index = temp_scope_->NextMaterializedLiteralIndex();
- if (is_pre_parsing_) {
- return NULL;
- }
-
- // Construct the expression for calling Runtime::CreateObjectLiteral
- // with the literal array as argument.
- Handle<FixedArray> constant_properties = Factory::empty_fixed_array();
- ZoneList<Expression*>* arguments = new ZoneList<Expression*>(1);
- arguments->Add(new Literal(constant_properties));
-
- return new ObjectLiteral(constant_properties,
- properties.elements(),
- literal_index);
-}
-
-
TryStatement* Parser::ParseTryStatement(bool* ok) {
// TryStatement ::
// 'try' Block Catch
// Allocate a temporary for holding the finally state while
// executing the finally block.
catch_var = top_scope_->NewTemporary(Factory::catch_var_symbol());
- Expression* obj = MakeCatchContext(name, catch_var);
+ Literal* name_literal = NEW(Literal(name));
+ Expression* obj = NEW(CatchExtensionObject(name_literal, catch_var));
{ Target target(this, &catch_collector);
catch_block = WithHelper(obj, NULL, true, CHECK_OK);
}
constant_properties->set(position++, *literal->handle());
}
- // Construct the expression for calling Runtime::CreateObjectLiteral
- // with the literal array as argument.
- ZoneList<Expression*>* arguments = new ZoneList<Expression*>(1);
- arguments->Add(new Literal(constant_properties));
return new ObjectLiteral(constant_properties,
properties.elements(),
literal_index);
}
+void PrettyPrinter::VisitCatchExtensionObject(CatchExtensionObject* node) {
+ Print("{ ");
+ Visit(node->key());
+ Print(": ");
+ Visit(node->value());
+ Print(" }");
+}
+
+
void PrettyPrinter::VisitSlot(Slot* node) {
switch (node->type()) {
case Slot::PARAMETER:
}
+void AstPrinter::VisitCatchExtensionObject(CatchExtensionObject* node) {
+ IndentedScope indent("CatchExtensionObject");
+ PrintIndentedVisit("KEY", node->key());
+ PrintIndentedVisit("VALUE", node->value());
+}
+
+
void AstPrinter::VisitSlot(Slot* node) {
PrintIndented("SLOT ");
switch (node->type()) {
}
+void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) {
+ Visit(node->key());
+ Visit(node->value());
+}
+
+
void AstOptimizer::VisitAssignment(Assignment* node) {
switch (node->op()) {
case Token::INIT_VAR:
}
+void Processor::VisitCatchExtensionObject(CatchExtensionObject* node) {
+ USE(node);
+ UNREACHABLE();
+}
+
+
void Processor::VisitAssignment(Assignment* node) {
USE(node);
UNREACHABLE();
}
+static Object* Runtime_CreateCatchExtensionObject(Arguments args) {
+ ASSERT(args.length() == 2);
+ CONVERT_CHECKED(String, key, args[0]);
+ Object* value = args[1];
+ // Create a catch context extension object.
+ JSFunction* constructor =
+ Top::context()->global_context()->context_extension_function();
+ Object* object = Heap::AllocateJSObject(constructor);
+ if (object->IsFailure()) return object;
+ // Assign the exception value to the catch variable and make sure
+ // that the catch variable is DontDelete.
+ value = JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
+ if (value->IsFailure()) return value;
+ return object;
+}
+
+
static Object* Runtime_ClassOf(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
F(CreateObjectLiteralBoilerplate, 3) \
F(CloneObjectLiteralBoilerplate, 1) \
\
+ /* Catch context extension objects */ \
+ F(CreateCatchExtensionObject, 2) \
+ \
/* Statements */ \
F(NewClosure, 2) \
F(NewObject, 1) \
void VisitRegExpLiteral(RegExpLiteral* node);
void VisitObjectLiteral(ObjectLiteral* node);
void VisitArrayLiteral(ArrayLiteral* node);
+ void VisitCatchExtensionObject(CatchExtensionObject* node);
void VisitAssignment(Assignment* node);
void VisitThrow(Throw* node);
void VisitProperty(Property* node);
}
+void UsageComputer::VisitCatchExtensionObject(CatchExtensionObject* node) {
+ Read(node->value());
+}
+
+
void UsageComputer::VisitAssignment(Assignment* node) {
if (node->op() != Token::ASSIGN)
Read(node->target());
ChangeBreakOnException(false, true);
step_action = StepIn;
break_point_hit_count = 0;
- expected_step_sequence = "ddedd";
+ expected_step_sequence = "dded";
d->Call(env->Global(), 0, NULL);
CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
ChangeBreakOnException(true, true);
step_action = StepIn;
break_point_hit_count = 0;
- expected_step_sequence = "ddeedd";
+ expected_step_sequence = "ddeed";
d->Call(env->Global(), 0, NULL);
CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
ChangeBreakOnException(false, true);
step_action = StepIn;
break_point_hit_count = 0;
- expected_step_sequence = "ffghff";
+ expected_step_sequence = "ffghf";
f->Call(env->Global(), 0, NULL);
CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
ChangeBreakOnException(true, true);
step_action = StepIn;
break_point_hit_count = 0;
- expected_step_sequence = "ffghhff";
+ expected_step_sequence = "ffghhf";
f->Call(env->Global(), 0, NULL);
CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
--- /dev/null
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that the variable introduced by catch blocks is DontDelete.
+// See http://code.google.com/p/v8/issues/detail?id=74
+
+function test() {
+ try {
+ throw 42;
+ } catch(e) {
+ assertFalse(delete e, "deleting catch variable");
+ assertEquals(42, e);
+ }
+}
+
+test();
+
--- /dev/null
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Try catch scopes should be implemented with special extension
+// objects so that __proto__ accessors and accessor setters in the
+// Object prototype have no effect.
+
+var setterCalled = false;
+Object.prototype.__defineSetter__("x", function() { setterCalled = true; });
+
+function runTest(test) {
+ setterCalled = false;
+ test();
+}
+
+function testProto() {
+ try {
+ throw 42;
+ } catch(__proto__) {
+ assertEquals(42, __proto__);
+ }
+}
+
+function testAccessorSetter() {
+ try {
+ throw 42;
+ } catch(x) {
+ assertFalse(setterCalled);
+ assertEquals(42, x);
+ }
+}
+
+runTest(testProto);
+runTest(testAccessorSetter);