OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 25 matching lines...) Expand all Loading... |
36 #include "cpu.h" | 36 #include "cpu.h" |
37 #include "dateparser.h" | 37 #include "dateparser.h" |
38 #include "debug.h" | 38 #include "debug.h" |
39 #include "execution.h" | 39 #include "execution.h" |
40 #include "jsregexp.h" | 40 #include "jsregexp.h" |
41 #include "platform.h" | 41 #include "platform.h" |
42 #include "runtime.h" | 42 #include "runtime.h" |
43 #include "scopeinfo.h" | 43 #include "scopeinfo.h" |
44 #include "v8threads.h" | 44 #include "v8threads.h" |
45 #include "smart-pointer.h" | 45 #include "smart-pointer.h" |
46 #include "parser.h" | |
47 | 46 |
48 namespace v8 { namespace internal { | 47 namespace v8 { namespace internal { |
49 | 48 |
50 | 49 |
51 #define RUNTIME_ASSERT(value) do { \ | 50 #define RUNTIME_ASSERT(value) do { \ |
52 if (!(value)) return IllegalOperation(); \ | 51 if (!(value)) return IllegalOperation(); \ |
53 } while (false) | 52 } while (false) |
54 | 53 |
55 // Cast the given object to a value of the specified type and store | 54 // Cast the given object to a value of the specified type and store |
56 // it in a variable with the given name. If the object is not of the | 55 // it in a variable with the given name. If the object is not of the |
57 // expected type call IllegalOperation and return. | 56 // expected type call IllegalOperation and return. |
58 #define CONVERT_CHECKED(Type, name, obj) \ | 57 #define CONVERT_CHECKED(Type, name, obj) \ |
59 RUNTIME_ASSERT(obj->Is##Type()); \ | 58 RUNTIME_ASSERT(obj->Is##Type()); \ |
60 Type* name = Type::cast(obj); | 59 Type* name = Type::cast(obj); |
61 | 60 |
62 #define CONVERT_ARG_CHECKED(Type, name, index) \ | 61 #define CONVERT_ARG_CHECKED(Type, name, index) \ |
63 RUNTIME_ASSERT(args[index]->Is##Type()); \ | 62 RUNTIME_ASSERT(args[index]->Is##Type()); \ |
64 Handle<Type> name = args.at<Type>(index); | 63 Handle<Type> name = args.at<Type>(index); |
65 | 64 |
66 // Cast the given object to a boolean and store it in a variable with | 65 // Cast the given object to a boolean and store it in a variable with |
67 // the given name. If the object is not a boolean call IllegalOperation | 66 // the given name. If the object is not a boolean call IllegalOperation |
68 // and return. | 67 // and return. |
69 #define CONVERT_BOOLEAN_CHECKED(name, obj) \ | 68 #define CONVERT_BOOLEAN_CHECKED(name, obj) \ |
70 RUNTIME_ASSERT(obj->IsBoolean()); \ | 69 RUNTIME_ASSERT(obj->IsBoolean()); \ |
71 bool name = (obj)->IsTrue(); | 70 bool name = (obj)->IsTrue(); |
72 | 71 |
73 // Cast the given object to an int and store it in a variable with | |
74 // the given name. If the object is not a Smi call IllegalOperation | |
75 // and return. | |
76 #define CONVERT_INT_CHECKED(name, obj) \ | |
77 RUNTIME_ASSERT(obj->IsSmi()); \ | |
78 int name = Smi::cast(obj)->value(); | |
79 | |
80 // Cast the given object to a double and store it in a variable with | 72 // Cast the given object to a double and store it in a variable with |
81 // the given name. If the object is not a number (as opposed to | 73 // the given name. If the object is not a number (as opposed to |
82 // the number not-a-number) call IllegalOperation and return. | 74 // the number not-a-number) call IllegalOperation and return. |
83 #define CONVERT_DOUBLE_CHECKED(name, obj) \ | 75 #define CONVERT_DOUBLE_CHECKED(name, obj) \ |
84 RUNTIME_ASSERT(obj->IsNumber()); \ | 76 RUNTIME_ASSERT(obj->IsNumber()); \ |
85 double name = (obj)->Number(); | 77 double name = (obj)->Number(); |
86 | 78 |
87 // Call the specified converter on the object *comand store the result in | 79 // Call the specified converter on the object *comand store the result in |
88 // a variable of the specified type with the given name. If the | 80 // a variable of the specified type with the given name. If the |
89 // object is not a Number call IllegalOperation and return. | 81 // object is not a Number call IllegalOperation and return. |
90 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ | 82 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ |
91 RUNTIME_ASSERT(obj->IsNumber()); \ | 83 RUNTIME_ASSERT(obj->IsNumber()); \ |
92 type name = NumberTo##Type(obj); | 84 type name = NumberTo##Type(obj); |
93 | 85 |
94 // Non-reentrant string buffer for efficient general use in this file. | 86 // Non-reentrant string buffer for efficient general use in this file. |
95 static StaticResource<StringInputBuffer> runtime_string_input_buffer; | 87 static StaticResource<StringInputBuffer> runtime_string_input_buffer; |
96 | 88 |
97 | 89 |
98 static Object* IllegalOperation() { | 90 static Object* IllegalOperation() { |
99 return Top::Throw(Heap::illegal_access_symbol()); | 91 return Top::Throw(Heap::illegal_access_symbol()); |
100 } | 92 } |
101 | 93 |
102 | 94 |
103 static Object* Runtime_CloneLiteralBoilerplate(Arguments args) { | 95 static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) { |
104 CONVERT_CHECKED(JSObject, boilerplate, args[0]); | 96 CONVERT_CHECKED(JSObject, boilerplate, args[0]); |
105 return Heap::CopyJSObject(boilerplate); | 97 return Heap::CopyJSObject(boilerplate); |
106 } | 98 } |
107 | 99 |
108 | 100 |
109 static Handle<Map> ComputeObjectLiteralMap( | 101 static Handle<Map> ComputeObjectLiteralMap( |
110 Handle<Context> context, | 102 Handle<Context> context, |
111 Handle<FixedArray> constant_properties, | 103 Handle<FixedArray> constant_properties, |
112 bool* is_result_from_cache) { | 104 bool* is_result_from_cache) { |
113 int number_of_properties = constant_properties->length() / 2; | 105 int number_of_properties = constant_properties->length() / 2; |
(...skipping 18 matching lines...) Expand all Loading... |
132 return Factory::ObjectLiteralMapFromCache(context, keys); | 124 return Factory::ObjectLiteralMapFromCache(context, keys); |
133 } | 125 } |
134 } | 126 } |
135 *is_result_from_cache = false; | 127 *is_result_from_cache = false; |
136 return Factory::CopyMap( | 128 return Factory::CopyMap( |
137 Handle<Map>(context->object_function()->initial_map()), | 129 Handle<Map>(context->object_function()->initial_map()), |
138 number_of_properties); | 130 number_of_properties); |
139 } | 131 } |
140 | 132 |
141 | 133 |
142 static Handle<Object> CreateLiteralBoilerplate( | 134 static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) { |
143 Handle<FixedArray> literals, | 135 HandleScope scope; |
144 Handle<FixedArray> constant_properties); | 136 ASSERT(args.length() == 3); |
| 137 // Copy the arguments. |
| 138 Handle<FixedArray> literals = args.at<FixedArray>(0); |
| 139 int literals_index = Smi::cast(args[1])->value(); |
| 140 Handle<FixedArray> constant_properties = args.at<FixedArray>(2); |
145 | 141 |
146 | |
147 static Handle<Object> CreateObjectLiteralBoilerplate( | |
148 Handle<FixedArray> literals, | |
149 Handle<FixedArray> constant_properties) { | |
150 // Get the global context from the literals array. This is the | 142 // Get the global context from the literals array. This is the |
151 // context in which the function was created and we use the object | 143 // context in which the function was created and we use the object |
152 // function from this context to create the object literal. We do | 144 // function from this context to create the object literal. We do |
153 // not use the object function from the current global context | 145 // not use the object function from the current global context |
154 // because this might be the object function from another context | 146 // because this might be the object function from another context |
155 // which we should not have access to. | 147 // which we should not have access to. |
156 Handle<Context> context = | 148 Handle<Context> context = |
157 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals)); | 149 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals)); |
158 | 150 |
159 bool is_result_from_cache; | 151 bool is_result_from_cache; |
160 Handle<Map> map = ComputeObjectLiteralMap(context, | 152 Handle<Map> map = ComputeObjectLiteralMap(context, |
161 constant_properties, | 153 constant_properties, |
162 &is_result_from_cache); | 154 &is_result_from_cache); |
163 | 155 |
164 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map); | 156 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map); |
165 { // Add the constant properties to the boilerplate. | 157 { // Add the constant properties to the boilerplate. |
166 int length = constant_properties->length(); | 158 int length = constant_properties->length(); |
167 OptimizedObjectForAddingMultipleProperties opt(boilerplate, | 159 OptimizedObjectForAddingMultipleProperties opt(boilerplate, |
168 !is_result_from_cache); | 160 !is_result_from_cache); |
169 for (int index = 0; index < length; index +=2) { | 161 for (int index = 0; index < length; index +=2) { |
170 Handle<Object> key(constant_properties->get(index+0)); | 162 Handle<Object> key(constant_properties->get(index+0)); |
171 Handle<Object> value(constant_properties->get(index+1)); | 163 Handle<Object> value(constant_properties->get(index+1)); |
172 if (value->IsFixedArray()) { | |
173 // The value contains the constant_properties of a | |
174 // simple object literal. | |
175 Handle<FixedArray> array = Handle<FixedArray>::cast(value); | |
176 value = CreateLiteralBoilerplate(literals, array); | |
177 if (value.is_null()) return value; | |
178 } | |
179 Handle<Object> result; | 164 Handle<Object> result; |
180 uint32_t element_index = 0; | 165 uint32_t element_index = 0; |
181 if (key->IsSymbol()) { | 166 if (key->IsSymbol()) { |
182 // If key is a symbol it is not an array element. | 167 // If key is a symbol it is not an array element. |
183 Handle<String> name(String::cast(*key)); | 168 Handle<String> name(String::cast(*key)); |
184 ASSERT(!name->AsArrayIndex(&element_index)); | 169 ASSERT(!name->AsArrayIndex(&element_index)); |
185 result = SetProperty(boilerplate, name, value, NONE); | 170 result = SetProperty(boilerplate, name, value, NONE); |
186 } else if (Array::IndexFromObject(*key, &element_index)) { | 171 } else if (Array::IndexFromObject(*key, &element_index)) { |
187 // Array index (uint32). | 172 // Array index (uint32). |
188 result = SetElement(boilerplate, element_index, value); | 173 result = SetElement(boilerplate, element_index, value); |
189 } else { | 174 } else { |
190 // Non-uint32 number. | 175 // Non-uint32 number. |
191 ASSERT(key->IsNumber()); | 176 ASSERT(key->IsNumber()); |
192 double num = key->Number(); | 177 double num = key->Number(); |
193 char arr[100]; | 178 char arr[100]; |
194 Vector<char> buffer(arr, ARRAY_SIZE(arr)); | 179 Vector<char> buffer(arr, ARRAY_SIZE(arr)); |
195 const char* str = DoubleToCString(num, buffer); | 180 const char* str = DoubleToCString(num, buffer); |
196 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str)); | 181 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str)); |
197 result = SetProperty(boilerplate, name, value, NONE); | 182 result = SetProperty(boilerplate, name, value, NONE); |
198 } | 183 } |
199 // If setting the property on the boilerplate throws an | 184 // If setting the property on the boilerplate throws an |
200 // exception, the exception is converted to an empty handle in | 185 // exception, the exception is converted to an empty handle in |
201 // the handle based operations. In that case, we need to | 186 // the handle based operations. In that case, we need to |
202 // convert back to an exception. | 187 // convert back to an exception. |
203 if (result.is_null()) return result; | 188 if (result.is_null()) return Failure::Exception(); |
204 } | 189 } |
205 } | 190 } |
206 | 191 |
207 return boilerplate; | 192 // Update the functions literal and return the boilerplate. |
| 193 literals->set(literals_index, *boilerplate); |
| 194 |
| 195 return *boilerplate; |
208 } | 196 } |
209 | 197 |
210 | 198 |
211 static Handle<Object> CreateArrayLiteralBoilerplate( | 199 static Object* Runtime_CreateArrayLiteral(Arguments args) { |
212 Handle<FixedArray> literals, | |
213 Handle<FixedArray> elements) { | |
214 // Create the JSArray. | |
215 Handle<JSFunction> constructor( | |
216 JSFunction::GlobalContextFromLiterals(*literals)->array_function()); | |
217 Handle<Object> object = Factory::NewJSObject(constructor); | |
218 | |
219 Handle<Object> copied_elements = Factory::CopyFixedArray(elements); | |
220 | |
221 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements); | |
222 for (int i = 0; i < content->length(); i++) { | |
223 if (content->get(i)->IsFixedArray()) { | |
224 // The value contains the constant_properties of a | |
225 // simple object literal. | |
226 Handle<FixedArray> fa(FixedArray::cast(content->get(i))); | |
227 Handle<Object> result = CreateLiteralBoilerplate(literals, fa); | |
228 if (result.is_null()) return result; | |
229 content->set(i, *result); | |
230 } | |
231 } | |
232 | |
233 // Set the elements. | |
234 Handle<JSArray>::cast(object)->SetContent(*content); | |
235 return object; | |
236 } | |
237 | |
238 | |
239 static Handle<Object> CreateLiteralBoilerplate( | |
240 Handle<FixedArray> literals, | |
241 Handle<FixedArray> array) { | |
242 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); | |
243 switch (CompileTimeValue::GetType(array)) { | |
244 case CompileTimeValue::OBJECT_LITERAL: | |
245 return CreateObjectLiteralBoilerplate(literals, elements); | |
246 case CompileTimeValue::ARRAY_LITERAL: | |
247 return CreateArrayLiteralBoilerplate(literals, elements); | |
248 default: | |
249 UNREACHABLE(); | |
250 return Handle<Object>::null(); | |
251 } | |
252 } | |
253 | |
254 | |
255 static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) { | |
256 HandleScope scope; | |
257 ASSERT(args.length() == 3); | |
258 // Copy the arguments. | |
259 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | |
260 CONVERT_INT_CHECKED(literals_index, args[1]); | |
261 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); | |
262 | |
263 Handle<Object> result = | |
264 CreateObjectLiteralBoilerplate(literals, constant_properties); | |
265 | |
266 if (result.is_null()) return Failure::Exception(); | |
267 | |
268 // Update the functions literal and return the boilerplate. | |
269 literals->set(literals_index, *result); | |
270 | |
271 return *result; | |
272 } | |
273 | |
274 | |
275 static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { | |
276 // Takes a FixedArray of elements containing the literal elements of | 200 // Takes a FixedArray of elements containing the literal elements of |
277 // the array literal and produces JSArray with those elements. | 201 // the array literal and produces JSArray with those elements. |
278 // Additionally takes the literals array of the surrounding function | 202 // Additionally takes the literals array of the surrounding function |
279 // which contains the context from which to get the Array function | 203 // which contains the context from which to get the Array function |
280 // to use for creating the array literal. | 204 // to use for creating the array literal. |
281 HandleScope scope; | 205 ASSERT(args.length() == 2); |
282 ASSERT(args.length() == 3); | 206 CONVERT_CHECKED(FixedArray, elements, args[0]); |
283 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 207 CONVERT_CHECKED(FixedArray, literals, args[1]); |
284 CONVERT_INT_CHECKED(literals_index, args[1]); | 208 JSFunction* constructor = |
285 CONVERT_ARG_CHECKED(FixedArray, elements, 2); | 209 JSFunction::GlobalContextFromLiterals(literals)->array_function(); |
| 210 // Create the JSArray. |
| 211 Object* object = Heap::AllocateJSObject(constructor); |
| 212 if (object->IsFailure()) return object; |
286 | 213 |
287 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements); | 214 // Copy the elements. |
288 if (object.is_null()) return Failure::Exception(); | 215 Object* content = elements->Copy(); |
| 216 if (content->IsFailure()) return content; |
289 | 217 |
290 // Update the functions literal and return the boilerplate. | 218 // Set the elements. |
291 literals->set(literals_index, *object); | 219 JSArray::cast(object)->SetContent(FixedArray::cast(content)); |
292 return *object; | 220 return object; |
293 } | 221 } |
294 | 222 |
295 | 223 |
296 static Object* Runtime_CreateCatchExtensionObject(Arguments args) { | 224 static Object* Runtime_CreateCatchExtensionObject(Arguments args) { |
297 ASSERT(args.length() == 2); | 225 ASSERT(args.length() == 2); |
298 CONVERT_CHECKED(String, key, args[0]); | 226 CONVERT_CHECKED(String, key, args[0]); |
299 Object* value = args[1]; | 227 Object* value = args[1]; |
300 // Create a catch context extension object. | 228 // Create a catch context extension object. |
301 JSFunction* constructor = | 229 JSFunction* constructor = |
302 Top::context()->global_context()->context_extension_function(); | 230 Top::context()->global_context()->context_extension_function(); |
(...skipping 6421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6724 } else { | 6652 } else { |
6725 // Handle last resort GC and make sure to allow future allocations | 6653 // Handle last resort GC and make sure to allow future allocations |
6726 // to grow the heap without causing GCs (if possible). | 6654 // to grow the heap without causing GCs (if possible). |
6727 Counters::gc_last_resort_from_js.Increment(); | 6655 Counters::gc_last_resort_from_js.Increment(); |
6728 Heap::CollectAllGarbage(); | 6656 Heap::CollectAllGarbage(); |
6729 } | 6657 } |
6730 } | 6658 } |
6731 | 6659 |
6732 | 6660 |
6733 } } // namespace v8::internal | 6661 } } // namespace v8::internal |
OLD | NEW |