Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index dfec3281b625240f2859fc38b02ab033e7124295..51ff5c0dea4d95adb72a9dfadfb047a6b4efdaba 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -614,31 +614,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) { |
} |
-RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) { |
- ASSERT(args.length() == 2); |
- CONVERT_CHECKED(String, key, args[0]); |
- Object* value = args[1]; |
- ASSERT(!value->IsFailure()); |
- // Create a catch context extension object. |
- JSFunction* constructor = |
- isolate->context()->global_context()-> |
- context_extension_function(); |
- Object* object; |
- { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor); |
- if (!maybe_object->ToObject(&object)) return maybe_object; |
- } |
- // Assign the exception value to the catch variable and make sure |
- // that the catch variable is DontDelete. |
- { MaybeObject* maybe_value = |
- // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4. |
- JSObject::cast(object)->SetProperty( |
- key, value, DONT_DELETE, kNonStrictMode); |
- if (!maybe_value->ToObject(&value)) return maybe_value; |
- } |
- return object; |
-} |
- |
- |
RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) { |
NoHandleAllocation ha; |
ASSERT(args.length() == 1); |
@@ -901,13 +876,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) { |
ASSERT(proto->IsJSGlobalObject()); |
holder = Handle<JSObject>(JSObject::cast(proto)); |
} |
- FixedArray* elements = FixedArray::cast(holder->elements()); |
- NumberDictionary* dictionary = NULL; |
- if (elements->map() == heap->non_strict_arguments_elements_map()) { |
- dictionary = NumberDictionary::cast(elements->get(1)); |
- } else { |
- dictionary = NumberDictionary::cast(elements); |
- } |
+ NumberDictionary* dictionary = holder->element_dictionary(); |
int entry = dictionary->FindEntry(index); |
ASSERT(entry != NumberDictionary::kNotFound); |
PropertyDetails details = dictionary->DetailsAt(entry); |
@@ -1263,6 +1232,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { |
// Declarations are always done in the function context. |
context = Handle<Context>(context->fcontext()); |
+ ASSERT(context->IsFunctionContext() || context->IsGlobalContext()); |
int index; |
PropertyAttributes attributes; |
@@ -1316,7 +1286,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { |
Handle<JSObject> context_ext; |
if (context->has_extension()) { |
// The function context's extension context exists - use it. |
- context_ext = Handle<JSObject>(context->extension()); |
+ context_ext = Handle<JSObject>(JSObject::cast(context->extension())); |
} else { |
// The function context's extension context does not exists - allocate |
// it. |
@@ -3975,6 +3945,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) { |
} |
+// Special case for elements if any of the flags are true. |
+// If elements are in fast case we always implicitly assume that: |
+// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false. |
+static MaybeObject* NormalizeObjectSetElement(Isolate* isolate, |
+ Handle<JSObject> js_object, |
+ uint32_t index, |
+ Handle<Object> value, |
+ PropertyAttributes attr) { |
+ // Normalize the elements to enable attributes on the property. |
+ NormalizeElements(js_object); |
+ Handle<NumberDictionary> dictionary(js_object->element_dictionary()); |
+ // Make sure that we never go back to fast case. |
+ dictionary->set_requires_slow_elements(); |
+ PropertyDetails details = PropertyDetails(attr, NORMAL); |
+ Handle<NumberDictionary> extended_dictionary = |
+ NumberDictionarySet(dictionary, index, value, details); |
+ if (*extended_dictionary != *dictionary) { |
+ js_object->set_elements(*extended_dictionary); |
+ } |
+ return *value; |
+} |
+ |
+ |
MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, |
Handle<Object> object, |
Handle<Object> key, |
@@ -4010,6 +4003,10 @@ MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, |
return *value; |
} |
+ if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) { |
+ return NormalizeObjectSetElement(isolate, js_object, index, value, attr); |
+ } |
+ |
Handle<Object> result = SetElement(js_object, index, value, strict_mode); |
if (result.is_null()) return Failure::Exception(); |
return *value; |
@@ -4018,6 +4015,13 @@ MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, |
if (key->IsString()) { |
Handle<Object> result; |
if (Handle<String>::cast(key)->AsArrayIndex(&index)) { |
+ if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) { |
+ return NormalizeObjectSetElement(isolate, |
+ js_object, |
+ index, |
+ value, |
+ attr); |
+ } |
result = SetElement(js_object, index, value, strict_mode); |
} else { |
Handle<String> key_string = Handle<String>::cast(key); |
@@ -4035,7 +4039,7 @@ MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, |
Handle<String> name = Handle<String>::cast(converted); |
if (name->AsArrayIndex(&index)) { |
- return js_object->SetElement(index, *value, strict_mode, true); |
+ return js_object->SetElement(index, *value, strict_mode); |
} else { |
return js_object->SetProperty(*name, *value, attr, strict_mode); |
} |
@@ -4063,12 +4067,12 @@ MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate, |
return *value; |
} |
- return js_object->SetElement(index, *value, kNonStrictMode, true); |
+ return js_object->SetElement(index, *value, kNonStrictMode); |
} |
if (key->IsString()) { |
if (Handle<String>::cast(key)->AsArrayIndex(&index)) { |
- return js_object->SetElement(index, *value, kNonStrictMode, true); |
+ return js_object->SetElement(index, *value, kNonStrictMode); |
} else { |
Handle<String> key_string = Handle<String>::cast(key); |
key_string->TryFlatten(); |
@@ -4085,7 +4089,7 @@ MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate, |
Handle<String> name = Handle<String>::cast(converted); |
if (name->AsArrayIndex(&index)) { |
- return js_object->SetElement(index, *value, kNonStrictMode, true); |
+ return js_object->SetElement(index, *value, kNonStrictMode); |
} else { |
return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr); |
} |
@@ -7339,103 +7343,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) { |
RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) { |
- HandleScope scope(isolate); |
- ASSERT(args.length() == 3); |
- |
- Handle<JSFunction> callee = args.at<JSFunction>(0); |
- Object** parameters = reinterpret_cast<Object**>(args[1]); |
- const int argument_count = Smi::cast(args[2])->value(); |
- |
- Handle<JSObject> result = |
- isolate->factory()->NewArgumentsObject(callee, argument_count); |
- // Allocate the elements if needed. |
- int parameter_count = callee->shared()->formal_parameter_count(); |
- if (argument_count > 0) { |
- if (parameter_count > 0) { |
- int mapped_count = Min(argument_count, parameter_count); |
- Handle<FixedArray> parameter_map = |
- isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED); |
- parameter_map->set_map( |
- isolate->heap()->non_strict_arguments_elements_map()); |
- |
- Handle<Map> old_map(result->map()); |
- Handle<Map> new_map = |
- isolate->factory()->CopyMapDropTransitions(old_map); |
- new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS); |
- |
- result->set_map(*new_map); |
- result->set_elements(*parameter_map); |
- |
- // Store the context and the arguments array at the beginning of the |
- // parameter map. |
- Handle<Context> context(isolate->context()); |
- Handle<FixedArray> arguments = |
- isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); |
- parameter_map->set(0, *context); |
- parameter_map->set(1, *arguments); |
- |
- // Loop over the actual parameters backwards. |
- int index = argument_count - 1; |
- while (index >= mapped_count) { |
- // These go directly in the arguments array and have no |
- // corresponding slot in the parameter map. |
- arguments->set(index, *(parameters - index - 1)); |
- --index; |
- } |
- |
- ScopeInfo<> scope_info(callee->shared()->scope_info()); |
- while (index >= 0) { |
- // Detect duplicate names to the right in the parameter list. |
- Handle<String> name = scope_info.parameter_name(index); |
- int context_slot_count = scope_info.number_of_context_slots(); |
- bool duplicate = false; |
- for (int j = index + 1; j < parameter_count; ++j) { |
- if (scope_info.parameter_name(j).is_identical_to(name)) { |
- duplicate = true; |
- break; |
- } |
- } |
- |
- if (duplicate) { |
- // This goes directly in the arguments array with a hole in the |
- // parameter map. |
- arguments->set(index, *(parameters - index - 1)); |
- parameter_map->set_the_hole(index + 2); |
- } else { |
- // The context index goes in the parameter map with a hole in the |
- // arguments array. |
- int context_index = -1; |
- for (int j = Context::MIN_CONTEXT_SLOTS; |
- j < context_slot_count; |
- ++j) { |
- if (scope_info.context_slot_name(j).is_identical_to(name)) { |
- context_index = j; |
- break; |
- } |
- } |
- ASSERT(context_index >= 0); |
- arguments->set_the_hole(index); |
- parameter_map->set(index + 2, Smi::FromInt(context_index)); |
- } |
- |
- --index; |
- } |
- } else { |
- // If there is no aliasing, the arguments object elements are not |
- // special in any way. |
- Handle<FixedArray> elements = |
- isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); |
- result->set_elements(*elements); |
- for (int i = 0; i < argument_count; ++i) { |
- elements->set(i, *(parameters - i - 1)); |
- } |
- } |
- } |
- return *result; |
-} |
- |
- |
-RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) { |
NoHandleAllocation ha; |
ASSERT(args.length() == 3); |
@@ -7877,7 +7784,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { |
CONVERT_ARG_CHECKED(JSFunction, function, 0); |
// We're not prepared to handle a function with arguments object. |
- ASSERT(!function->shared()->uses_arguments()); |
+ ASSERT(!function->shared()->scope_info()->HasArgumentsShadow()); |
// We have hit a back edge in an unoptimized frame for a function that was |
// selected for on-stack replacement. Find the unoptimized code object. |
@@ -8054,12 +7961,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) { |
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) { |
NoHandleAllocation ha; |
- ASSERT(args.length() == 1); |
- JSObject* extension_object = JSObject::cast(args[0]); |
+ ASSERT(args.length() == 2); |
+ String* name = String::cast(args[0]); |
+ Object* thrown_object = args[1]; |
Context* context; |
MaybeObject* maybe_context = |
isolate->heap()->AllocateCatchContext(isolate->context(), |
- extension_object); |
+ name, |
+ thrown_object); |
if (!maybe_context->To(&context)) return maybe_context; |
isolate->set_context(context); |
return context; |
@@ -8840,8 +8749,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) { |
} |
Object* obj; |
// Strict not needed. Used for cycle detection in Array join implementation. |
- { MaybeObject* maybe_obj = |
- array->SetFastElement(length, element, kNonStrictMode, true); |
+ { MaybeObject* maybe_obj = array->SetFastElement(length, element, |
+ kNonStrictMode); |
if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
} |
return isolate->heap()->true_value(); |
@@ -10152,14 +10061,18 @@ static bool CopyContextLocalsToScopeObject( |
int context_index = serialized_scope_info->ContextSlotIndex( |
*scope_info.context_slot_name(i), NULL); |
- RETURN_IF_EMPTY_HANDLE_VALUE( |
- isolate, |
- SetProperty(scope_object, |
- scope_info.context_slot_name(i), |
- Handle<Object>(context->get(context_index), isolate), |
- NONE, |
- kNonStrictMode), |
- false); |
+ // Don't include the arguments shadow (.arguments) context variable. |
+ if (*scope_info.context_slot_name(i) != |
+ isolate->heap()->arguments_shadow_symbol()) { |
+ RETURN_IF_EMPTY_HANDLE_VALUE( |
+ isolate, |
+ SetProperty(scope_object, |
+ scope_info.context_slot_name(i), |
+ Handle<Object>(context->get(context_index), isolate), |
+ NONE, |
+ kNonStrictMode), |
+ false); |
+ } |
} |
return true; |
@@ -10254,6 +10167,29 @@ static Handle<JSObject> MaterializeClosure(Isolate* isolate, |
Handle<JSObject> closure_scope = |
isolate->factory()->NewJSObject(isolate->object_function()); |
+ // Check whether the arguments shadow object exists. |
+ int arguments_shadow_index = |
+ shared->scope_info()->ContextSlotIndex( |
+ isolate->heap()->arguments_shadow_symbol(), NULL); |
+ if (arguments_shadow_index >= 0) { |
+ // In this case all the arguments are available in the arguments shadow |
+ // object. |
+ Handle<JSObject> arguments_shadow( |
+ JSObject::cast(context->get(arguments_shadow_index))); |
+ for (int i = 0; i < scope_info.number_of_parameters(); ++i) { |
+ // We don't expect exception-throwing getters on the arguments shadow. |
+ Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked(); |
+ RETURN_IF_EMPTY_HANDLE_VALUE( |
+ isolate, |
+ SetProperty(closure_scope, |
+ scope_info.parameter_name(i), |
+ Handle<Object>(element, isolate), |
+ NONE, |
+ kNonStrictMode), |
+ Handle<JSObject>()); |
+ } |
+ } |
+ |
// Fill all context locals to the context extension. |
if (!CopyContextLocalsToScopeObject(isolate, |
serialized_scope_info, scope_info, |
@@ -10285,6 +10221,23 @@ static Handle<JSObject> MaterializeClosure(Isolate* isolate, |
} |
+// Create a plain JSObject which materializes the scope for the specified |
+// catch context. |
+static Handle<JSObject> MaterializeCatchScope(Isolate* isolate, |
+ Handle<Context> context) { |
+ ASSERT(context->IsCatchContext()); |
+ Handle<String> name(String::cast(context->extension())); |
+ Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX)); |
+ Handle<JSObject> catch_scope = |
+ isolate->factory()->NewJSObject(isolate->object_function()); |
+ RETURN_IF_EMPTY_HANDLE_VALUE( |
+ isolate, |
+ SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode), |
+ Handle<JSObject>()); |
+ return catch_scope; |
+} |
+ |
+ |
// Iterate over the actual scopes visible from a stack frame. All scopes are |
// backed by an actual context except the local scope, which is inserted |
// "artifically" in the context chain. |
@@ -10295,10 +10248,6 @@ class ScopeIterator { |
ScopeTypeLocal, |
ScopeTypeWith, |
ScopeTypeClosure, |
- // Every catch block contains an implicit with block (its parameter is |
- // a JSContextExtensionObject) that extends current scope with a variable |
- // holding exception object. Such with blocks are treated as scopes of their |
- // own type. |
ScopeTypeCatch |
}; |
@@ -10322,8 +10271,8 @@ class ScopeIterator { |
} else if (context_->IsFunctionContext()) { |
at_local_ = true; |
} else if (context_->closure() != *function_) { |
- // The context_ is a with block from the outer function. |
- ASSERT(context_->has_extension()); |
+ // The context_ is a with or catch block from the outer function. |
+ ASSERT(context_->IsWithContext() || context_->IsCatchContext()); |
at_local_ = true; |
} |
} |
@@ -10375,15 +10324,10 @@ class ScopeIterator { |
if (context_->IsFunctionContext()) { |
return ScopeTypeClosure; |
} |
- ASSERT(context_->has_extension()); |
- // Current scope is either an explicit with statement or a with statement |
- // implicitely generated for a catch block. |
- // If the extension object here is a JSContextExtensionObject then |
- // current with statement is one frome a catch block otherwise it's a |
- // regular with statement. |
- if (context_->extension()->IsJSContextExtensionObject()) { |
+ if (context_->IsCatchContext()) { |
return ScopeTypeCatch; |
} |
+ ASSERT(context_->IsWithContext()); |
return ScopeTypeWith; |
} |
@@ -10392,20 +10336,17 @@ class ScopeIterator { |
switch (Type()) { |
case ScopeIterator::ScopeTypeGlobal: |
return Handle<JSObject>(CurrentContext()->global()); |
- break; |
case ScopeIterator::ScopeTypeLocal: |
// Materialize the content of the local scope into a JSObject. |
return MaterializeLocalScope(isolate_, frame_); |
- break; |
case ScopeIterator::ScopeTypeWith: |
- case ScopeIterator::ScopeTypeCatch: |
// Return the with object. |
- return Handle<JSObject>(CurrentContext()->extension()); |
- break; |
+ return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); |
+ case ScopeIterator::ScopeTypeCatch: |
+ return MaterializeCatchScope(isolate_, CurrentContext()); |
case ScopeIterator::ScopeTypeClosure: |
// Materialize the content of the closure scope into a JSObject. |
return MaterializeClosure(isolate_, CurrentContext()); |
- break; |
} |
UNREACHABLE(); |
return Handle<JSObject>(); |
@@ -10436,8 +10377,7 @@ class ScopeIterator { |
if (!CurrentContext().is_null()) { |
CurrentContext()->Print(); |
if (CurrentContext()->has_extension()) { |
- Handle<JSObject> extension = |
- Handle<JSObject>(CurrentContext()->extension()); |
+ Handle<Object> extension(CurrentContext()->extension()); |
if (extension->IsJSContextExtensionObject()) { |
extension->Print(); |
} |
@@ -10446,34 +10386,27 @@ class ScopeIterator { |
break; |
} |
- case ScopeIterator::ScopeTypeWith: { |
+ case ScopeIterator::ScopeTypeWith: |
PrintF("With:\n"); |
- Handle<JSObject> extension = |
- Handle<JSObject>(CurrentContext()->extension()); |
- extension->Print(); |
+ CurrentContext()->extension()->Print(); |
break; |
- } |
- case ScopeIterator::ScopeTypeCatch: { |
+ case ScopeIterator::ScopeTypeCatch: |
PrintF("Catch:\n"); |
- Handle<JSObject> extension = |
- Handle<JSObject>(CurrentContext()->extension()); |
- extension->Print(); |
+ CurrentContext()->extension()->Print(); |
+ CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(); |
break; |
- } |
- case ScopeIterator::ScopeTypeClosure: { |
+ case ScopeIterator::ScopeTypeClosure: |
PrintF("Closure:\n"); |
CurrentContext()->Print(); |
if (CurrentContext()->has_extension()) { |
- Handle<JSObject> extension = |
- Handle<JSObject>(CurrentContext()->extension()); |
+ Handle<Object> extension(CurrentContext()->extension()); |
if (extension->IsJSContextExtensionObject()) { |
extension->Print(); |
} |
} |
break; |
- } |
default: |
UNREACHABLE(); |
@@ -10952,10 +10885,17 @@ static Handle<Context> CopyWithContextChain(Isolate* isolate, |
HandleScope scope(isolate); |
Handle<Context> previous(current->previous()); |
Handle<Context> new_previous = CopyWithContextChain(isolate, previous, base); |
- Handle<JSObject> extension(JSObject::cast(current->extension())); |
- Handle<Context> new_current = current->IsCatchContext() |
- ? isolate->factory()->NewCatchContext(new_previous, extension) |
- : isolate->factory()->NewWithContext(new_previous, extension); |
+ Handle<Context> new_current; |
+ if (current->IsCatchContext()) { |
+ Handle<String> name(String::cast(current->extension())); |
+ Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX)); |
+ new_current = |
+ isolate->factory()->NewCatchContext(new_previous, name, thrown_object); |
+ } else { |
+ Handle<JSObject> extension(JSObject::cast(current->extension())); |
+ new_current = |
+ isolate->factory()->NewWithContext(new_previous, extension); |
+ } |
return scope.CloseAndEscape(new_current); |
} |