Index: src/runtime.cc |
=================================================================== |
--- src/runtime.cc (revision 1544) |
+++ src/runtime.cc (working copy) |
@@ -44,6 +44,7 @@ |
#include "scopeinfo.h" |
#include "v8threads.h" |
#include "smart-pointer.h" |
+#include "parser.h" |
namespace v8 { namespace internal { |
@@ -70,6 +71,13 @@ |
RUNTIME_ASSERT(obj->IsBoolean()); \ |
bool name = (obj)->IsTrue(); |
+// Cast the given object to a Smi and store its value in an int variable |
+// with the given name. If the object is not a Smi call IllegalOperation |
+// and return. |
+#define CONVERT_SMI_CHECKED(name, obj) \ |
+ RUNTIME_ASSERT(obj->IsSmi()); \ |
+ int name = Smi::cast(obj)->value(); |
+ |
// Cast the given object to a double and store it in a variable with |
// the given name. If the object is not a number (as opposed to |
// the number not-a-number) call IllegalOperation and return. |
@@ -93,8 +101,103 @@ |
} |
-static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) { |
+static Object* DeepCopyBoilerplate(JSObject* boilerplate) { |
+ StackLimitCheck check; |
+ if (check.HasOverflowed()) return Top::StackOverflow(); |
+ |
+ Object* result = Heap::CopyJSObject(boilerplate); |
+ if (result->IsFailure()) return result; |
+ JSObject* copy = JSObject::cast(result); |
+ |
+ // Deep copy local properties. |
+ if (copy->HasFastProperties()) { |
+ FixedArray* properties = copy->properties(); |
+ WriteBarrierMode mode = properties->GetWriteBarrierMode(); |
+ for (int i = 0; i < properties->length(); i++) { |
+ Object* value = properties->get(i); |
+ if (value->IsJSObject()) { |
+ JSObject* jsObject = JSObject::cast(value); |
+ result = DeepCopyBoilerplate(jsObject); |
+ if (result->IsFailure()) return result; |
+ properties->set(i, result, mode); |
+ } |
+ } |
+ mode = copy->GetWriteBarrierMode(); |
+ for (int i = 0; i < copy->map()->inobject_properties(); i++) { |
+ Object* value = copy->InObjectPropertyAt(i); |
+ if (value->IsJSObject()) { |
+ JSObject* jsObject = JSObject::cast(value); |
+ result = DeepCopyBoilerplate(jsObject); |
+ if (result->IsFailure()) return result; |
+ copy->InObjectPropertyAtPut(i, result, mode); |
+ } |
+ } |
+ } else { |
+ result = Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE)); |
+ if (result->IsFailure()) return result; |
+ FixedArray* names = FixedArray::cast(result); |
+ copy->GetLocalPropertyNames(names, 0); |
+ for (int i = 0; i < names->length(); i++) { |
+ ASSERT(names->get(i)->IsString()); |
+ String* keyString = String::cast(names->get(i)); |
+ PropertyAttributes attributes = copy->GetLocalPropertyAttribute(keyString); |
+ // Only deep copy fields from the object literal expression. |
+ // In particular, don't try to copy the length attribute of |
+ // an array. |
+ if (attributes != NONE) continue; |
+ Object* value = copy->GetProperty(keyString, &attributes); |
+ ASSERT(!value->IsFailure()); |
+ if (value->IsJSObject()) { |
+ JSObject* jsObject = JSObject::cast(value); |
+ result = DeepCopyBoilerplate(jsObject); |
+ if (result->IsFailure()) return result; |
+ result = copy->SetProperty(keyString, result, NONE); |
+ if (result->IsFailure()) return result; |
+ } |
+ } |
+ } |
+ |
+ // Deep copy local elements. |
+ if (copy->HasFastElements()) { |
+ FixedArray* elements = copy->elements(); |
+ WriteBarrierMode mode = elements->GetWriteBarrierMode(); |
+ for (int i = 0; i < elements->length(); i++) { |
+ Object* value = elements->get(i); |
+ if (value->IsJSObject()) { |
+ JSObject* jsObject = JSObject::cast(value); |
+ result = DeepCopyBoilerplate(jsObject); |
+ if (result->IsFailure()) return result; |
+ elements->set(i, result, mode); |
+ } |
+ } |
+ } else { |
+ Dictionary* element_dictionary = copy->element_dictionary(); |
+ int capacity = element_dictionary->Capacity(); |
+ for (int i = 0; i < capacity; i++) { |
+ Object* k = element_dictionary->KeyAt(i); |
+ if (element_dictionary->IsKey(k)) { |
+ Object* value = element_dictionary->ValueAt(i); |
+ if (value->IsJSObject()) { |
+ JSObject* jsObject = JSObject::cast(value); |
+ result = DeepCopyBoilerplate(jsObject); |
+ if (result->IsFailure()) return result; |
+ element_dictionary->ValueAtPut(i, result); |
+ } |
+ } |
+ } |
+ } |
+ return copy; |
+} |
+ |
+ |
+static Object* Runtime_CloneLiteralBoilerplate(Arguments args) { |
CONVERT_CHECKED(JSObject, boilerplate, args[0]); |
+ return DeepCopyBoilerplate(boilerplate); |
+} |
+ |
+ |
+static Object* Runtime_CloneShallowLiteralBoilerplate(Arguments args) { |
+ CONVERT_CHECKED(JSObject, boilerplate, args[0]); |
return Heap::CopyJSObject(boilerplate); |
} |
@@ -132,14 +235,14 @@ |
} |
-static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) { |
- HandleScope scope; |
- ASSERT(args.length() == 3); |
- // Copy the arguments. |
- Handle<FixedArray> literals = args.at<FixedArray>(0); |
- int literals_index = Smi::cast(args[1])->value(); |
- Handle<FixedArray> constant_properties = args.at<FixedArray>(2); |
+static Handle<Object> CreateLiteralBoilerplate( |
+ Handle<FixedArray> literals, |
+ Handle<FixedArray> constant_properties); |
+ |
+static Handle<Object> CreateObjectLiteralBoilerplate( |
+ Handle<FixedArray> literals, |
+ Handle<FixedArray> constant_properties) { |
// Get the global context from the literals array. This is the |
// context in which the function was created and we use the object |
// function from this context to create the object literal. We do |
@@ -162,6 +265,13 @@ |
for (int index = 0; index < length; index +=2) { |
Handle<Object> key(constant_properties->get(index+0)); |
Handle<Object> value(constant_properties->get(index+1)); |
+ if (value->IsFixedArray()) { |
+ // The value contains the constant_properties of a |
+ // simple object literal. |
+ Handle<FixedArray> array = Handle<FixedArray>::cast(value); |
+ value = CreateLiteralBoilerplate(literals, array); |
+ if (value.is_null()) return value; |
+ } |
Handle<Object> result; |
uint32_t element_index = 0; |
if (key->IsSymbol()) { |
@@ -186,39 +296,97 @@ |
// exception, the exception is converted to an empty handle in |
// the handle based operations. In that case, we need to |
// convert back to an exception. |
- if (result.is_null()) return Failure::Exception(); |
+ if (result.is_null()) return result; |
} |
} |
+ return boilerplate; |
+} |
+ |
+ |
+static Handle<Object> CreateArrayLiteralBoilerplate( |
+ Handle<FixedArray> literals, |
+ Handle<FixedArray> elements) { |
+ // Create the JSArray. |
+ Handle<JSFunction> constructor( |
+ JSFunction::GlobalContextFromLiterals(*literals)->array_function()); |
+ Handle<Object> object = Factory::NewJSObject(constructor); |
+ |
+ Handle<Object> copied_elements = Factory::CopyFixedArray(elements); |
+ |
+ Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements); |
+ for (int i = 0; i < content->length(); i++) { |
+ if (content->get(i)->IsFixedArray()) { |
+ // The value contains the constant_properties of a |
+ // simple object literal. |
+ Handle<FixedArray> fa(FixedArray::cast(content->get(i))); |
+ Handle<Object> result = |
+ CreateLiteralBoilerplate(literals, fa); |
+ if (result.is_null()) return result; |
+ content->set(i, *result); |
+ } |
+ } |
+ |
+ // Set the elements. |
+ Handle<JSArray>::cast(object)->SetContent(*content); |
+ return object; |
+} |
+ |
+ |
+static Handle<Object> CreateLiteralBoilerplate( |
+ Handle<FixedArray> literals, |
+ Handle<FixedArray> array) { |
+ Handle<FixedArray> elements = CompileTimeValue::GetElements(array); |
+ switch (CompileTimeValue::GetType(array)) { |
+ case CompileTimeValue::OBJECT_LITERAL: |
+ return CreateObjectLiteralBoilerplate(literals, elements); |
+ case CompileTimeValue::ARRAY_LITERAL: |
+ return CreateArrayLiteralBoilerplate(literals, elements); |
+ default: |
+ UNREACHABLE(); |
+ return Handle<Object>::null(); |
+ } |
+} |
+ |
+ |
+static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) { |
+ HandleScope scope; |
+ ASSERT(args.length() == 3); |
+ // Copy the arguments. |
+ CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
+ CONVERT_SMI_CHECKED(literals_index, args[1]); |
+ CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); |
+ |
+ Handle<Object> result = |
+ CreateObjectLiteralBoilerplate(literals, constant_properties); |
+ |
+ if (result.is_null()) return Failure::Exception(); |
+ |
// Update the functions literal and return the boilerplate. |
- literals->set(literals_index, *boilerplate); |
+ literals->set(literals_index, *result); |
- return *boilerplate; |
+ return *result; |
} |
-static Object* Runtime_CreateArrayLiteral(Arguments args) { |
+static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { |
// Takes a FixedArray of elements containing the literal elements of |
// the array literal and produces JSArray with those elements. |
// Additionally takes the literals array of the surrounding function |
// which contains the context from which to get the Array function |
// to use for creating the array literal. |
- ASSERT(args.length() == 2); |
- CONVERT_CHECKED(FixedArray, elements, args[0]); |
- CONVERT_CHECKED(FixedArray, literals, args[1]); |
- JSFunction* constructor = |
- JSFunction::GlobalContextFromLiterals(literals)->array_function(); |
- // Create the JSArray. |
- Object* object = Heap::AllocateJSObject(constructor); |
- if (object->IsFailure()) return object; |
+ HandleScope scope; |
+ ASSERT(args.length() == 3); |
+ CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
+ CONVERT_SMI_CHECKED(literals_index, args[1]); |
+ CONVERT_ARG_CHECKED(FixedArray, elements, 2); |
- // Copy the elements. |
- Object* content = elements->Copy(); |
- if (content->IsFailure()) return content; |
+ Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements); |
+ if (object.is_null()) return Failure::Exception(); |
- // Set the elements. |
- JSArray::cast(object)->SetContent(FixedArray::cast(content)); |
- return object; |
+ // Update the functions literal and return the boilerplate. |
+ literals->set(literals_index, *object); |
+ return *object; |
} |