class WithEnterStatement: public Statement {
public:
- explicit WithEnterStatement(Expression* expression)
- : expression_(expression) { }
+ explicit WithEnterStatement(Expression* expression, bool is_catch_block)
+ : expression_(expression), is_catch_block_(is_catch_block) { }
virtual void Accept(AstVisitor* v);
Expression* expression() const { return expression_; }
+ bool is_catch_block() const { return is_catch_block_; }
+
private:
Expression* expression_;
+ bool is_catch_block_;
};
Comment cmnt(masm_, "[ WithEnterStatement");
CodeForStatement(node);
Load(node->expression());
- __ CallRuntime(Runtime::kPushContext, 1);
+ if (node->is_catch_block()) {
+ __ CallRuntime(Runtime::kPushCatchContext, 1);
+ } else {
+ __ CallRuntime(Runtime::kPushContext, 1);
+ }
if (kDebug) {
Label verified_true;
__ cmp(r0, Operand(cp));
Comment cmnt(masm_, "[ WithEnterStatement");
CodeForStatement(node);
Load(node->expression());
- __ CallRuntime(Runtime::kPushContext, 1);
+ if (node->is_catch_block()) {
+ __ CallRuntime(Runtime::kPushCatchContext, 1);
+ } else {
+ __ CallRuntime(Runtime::kPushContext, 1);
+ }
if (kDebug) {
Label verified_true;
global_context()->set_out_of_memory(Heap::true_value());
}
+ // The exception holder is the object used as a with object in
+ // the implementation of a catch block.
+ bool is_exception_holder(Object* object) {
+ return IsCatchContext() && extension() == object;
+ }
+
#define GLOBAL_CONTEXT_FIELD_ACCESSORS(index, type, name) \
void set_##name(type* value) { \
ASSERT(IsGlobalContext()); \
Handle<Context> Factory::NewWithContext(Handle<Context> previous,
- Handle<JSObject> extension) {
- CALL_HEAP_FUNCTION(Heap::AllocateWithContext(*previous, *extension), Context);
+ Handle<JSObject> extension,
+ bool is_catch_context) {
+ CALL_HEAP_FUNCTION(Heap::AllocateWithContext(*previous,
+ *extension,
+ is_catch_context),
+ Context);
}
// Create a 'with' context.
static Handle<Context> NewWithContext(Handle<Context> previous,
- Handle<JSObject> extension);
+ Handle<JSObject> extension,
+ bool is_catch_context);
// Return the Symbol maching the passed in string.
static Handle<String> SymbolFromString(Handle<String> value);
obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
if (obj->IsFailure()) return false;
+ catch_context_map_ = Map::cast(obj);
+
+ obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
+ if (obj->IsFailure()) return false;
global_context_map_ = Map::cast(obj);
obj = AllocateMap(JS_FUNCTION_TYPE, JSFunction::kSize);
}
-Object* Heap::AllocateWithContext(Context* previous, JSObject* extension) {
+Object* Heap::AllocateWithContext(Context* previous,
+ JSObject* extension,
+ bool is_catch_context) {
Object* result = Heap::AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
if (result->IsFailure()) return result;
Context* context = reinterpret_cast<Context*>(result);
- context->set_map(context_map());
+ context->set_map(is_catch_context ? catch_context_map() : context_map());
context->set_closure(previous->closure());
context->set_fcontext(previous->fcontext());
context->set_previous(previous);
V(Map, fixed_array_map) \
V(Map, hash_table_map) \
V(Map, context_map) \
+ V(Map, catch_context_map) \
V(Map, global_context_map) \
V(Map, code_map) \
V(Map, oddball_map) \
static Object* AllocateFunctionContext(int length, JSFunction* closure);
// Allocate a 'with' context.
- static Object* AllocateWithContext(Context* previous, JSObject* extension);
+ static Object* AllocateWithContext(Context* previous,
+ JSObject* extension,
+ bool is_catch_context);
// Allocates a new utility object in the old generation.
static Object* AllocateStruct(InstanceType type);
bool Object::IsContext() {
return Object::IsHeapObject()
&& (HeapObject::cast(this)->map() == Heap::context_map() ||
+ HeapObject::cast(this)->map() == Heap::catch_context_map() ||
HeapObject::cast(this)->map() == Heap::global_context_map());
}
+bool Object::IsCatchContext() {
+ return Object::IsHeapObject()
+ && HeapObject::cast(this)->map() == Heap::catch_context_map();
+}
+
+
bool Object::IsGlobalContext() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map() == Heap::global_context_map();
inline bool IsFixedArray();
inline bool IsDescriptorArray();
inline bool IsContext();
+ inline bool IsCatchContext();
inline bool IsGlobalContext();
inline bool IsJSFunction();
inline bool IsCode();
Statement* ParseContinueStatement(bool* ok);
Statement* ParseBreakStatement(ZoneStringList* labels, bool* ok);
Statement* ParseReturnStatement(bool* ok);
- Block* WithHelper(Expression* obj, ZoneStringList* labels, bool* ok);
+ Block* WithHelper(Expression* obj,
+ ZoneStringList* labels,
+ bool is_catch_block,
+ bool* ok);
Statement* ParseWithStatement(ZoneStringList* labels, bool* ok);
CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok);
SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok);
}
-Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
+Block* Parser::WithHelper(Expression* obj,
+ ZoneStringList* labels,
+ bool is_catch_block,
+ bool* ok) {
// Parse the statement and collect escaping labels.
ZoneList<Label*>* label_list = NEW(ZoneList<Label*>(0));
LabelCollector collector(label_list);
Block* result = NEW(Block(NULL, 2, false));
if (result) {
- result->AddStatement(NEW(WithEnterStatement(obj)));
+ result->AddStatement(NEW(WithEnterStatement(obj, is_catch_block)));
// Create body block.
Block* body = NEW(Block(NULL, 1, false));
Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- return WithHelper(expr, labels, CHECK_OK);
+ return WithHelper(expr, labels, false, CHECK_OK);
}
catch_var = top_scope_->NewTemporary(Factory::catch_var_symbol());
Expression* obj = MakeCatchContext(name, catch_var);
{ Target target(this, &catch_collector);
- catch_block = WithHelper(obj, NULL, CHECK_OK);
+ catch_block = WithHelper(obj, NULL, true, CHECK_OK);
}
} else {
Expect(Token::LBRACE, CHECK_OK);
return result; // non-failure
}
-
-static Object* Runtime_PushContext(Arguments args) {
- NoHandleAllocation ha;
- ASSERT(args.length() == 1);
-
+static Object* PushContextHelper(Object* object, bool is_catch_context) {
// Convert the object to a proper JavaScript object.
- Object* object = args[0];
- if (!object->IsJSObject()) {
- object = object->ToObject();
- if (object->IsFailure()) {
- if (!Failure::cast(object)->IsInternalError()) return object;
+ Object* js_object = object;
+ if (!js_object->IsJSObject()) {
+ js_object = js_object->ToObject();
+ if (js_object->IsFailure()) {
+ if (!Failure::cast(js_object)->IsInternalError()) return js_object;
HandleScope scope;
- Handle<Object> handle(args[0]);
+ Handle<Object> handle(object);
Handle<Object> result =
Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
return Top::Throw(*result);
}
Object* result =
- Heap::AllocateWithContext(Top::context(), JSObject::cast(object));
+ Heap::AllocateWithContext(Top::context(),
+ JSObject::cast(js_object),
+ is_catch_context);
if (result->IsFailure()) return result;
- Top::set_context(Context::cast(result));
+ Context* context = Context::cast(result);
+ Top::set_context(context);
return result;
}
+static Object* Runtime_PushContext(Arguments args) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 1);
+ return PushContextHelper(args[0], false);
+}
+
+
+static Object* Runtime_PushCatchContext(Arguments args) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 1);
+ return PushContextHelper(args[0], true);
+}
+
+
static Object* Runtime_LookupContext(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 2);
if (!holder.is_null() && holder->IsJSObject()) {
ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
JSObject* object = JSObject::cast(*holder);
- JSObject* receiver = (object->IsGlobalObject())
- ? GlobalObject::cast(object)->global_receiver()
- : ComputeReceiverForNonGlobal(object);
+ JSObject* receiver;
+ if (object->IsGlobalObject()) {
+ receiver = GlobalObject::cast(object)->global_receiver();
+ } else if (context->is_exception_holder(*holder)) {
+ receiver = Top::context()->global()->global_receiver();
+ } else {
+ receiver = ComputeReceiverForNonGlobal(object);
+ }
// No need to unhole the value here. This is taken care of by the
// GetProperty function.
Object* value = object->GetProperty(*name);
Handle<Context> previous(context_chain->previous());
Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
return Factory::NewWithContext(
- CopyWithContextChain(function_context, previous), extension);
+ CopyWithContextChain(function_context, previous),
+ extension,
+ context_chain->IsCatchContext());
}
/* Contexts */ \
F(NewContext, 1) \
F(PushContext, 1) \
+ F(PushCatchContext, 1) \
F(LookupContext, 2) \
F(LoadContextSlot, 2) \
F(LoadContextSlotNoReferenceError, 2) \
--- /dev/null
+// Copyright 2008 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.
+
+var g = this;
+var x = new Object();
+x.e = function() { return this; };
+try {
+ throw x.e;
+} catch (e) {
+ assertTrue(e() === g);
+}
+try {
+ throw x.e;
+} catch (e) {
+ with(x) { assertTrue(e() === x); }
+}
+with(x) {
+ try { throw e; } catch (e) { assertTrue(e() === g); }
+}
+var e = 0;
+try {
+ throw x.e;
+} catch (e) {
+ var e = 7;
+}
+assertEquals(0, e);