blob: dce2e15674b52fcc3ec30b8922923220112c14a6 [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
43#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000044#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000045#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "platform.h"
47#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000050#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000051#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000053#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
kasperl@chromium.org71affb52009-05-26 05:44:31 +000055namespace v8 {
56namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
58
ager@chromium.org3e875802009-06-29 08:26:34 +000059#define RUNTIME_ASSERT(value) \
60 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62// Cast the given object to a value of the specified type and store
63// it in a variable with the given name. If the object is not of the
64// expected type call IllegalOperation and return.
65#define CONVERT_CHECKED(Type, name, obj) \
66 RUNTIME_ASSERT(obj->Is##Type()); \
67 Type* name = Type::cast(obj);
68
69#define CONVERT_ARG_CHECKED(Type, name, index) \
70 RUNTIME_ASSERT(args[index]->Is##Type()); \
71 Handle<Type> name = args.at<Type>(index);
72
kasper.lundbd3ec4e2008-07-09 11:06:54 +000073// Cast the given object to a boolean and store it in a variable with
74// the given name. If the object is not a boolean call IllegalOperation
75// and return.
76#define CONVERT_BOOLEAN_CHECKED(name, obj) \
77 RUNTIME_ASSERT(obj->IsBoolean()); \
78 bool name = (obj)->IsTrue();
79
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000080// Cast the given object to a Smi and store its value in an int variable
81// with the given name. If the object is not a Smi call IllegalOperation
82// and return.
83#define CONVERT_SMI_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsSmi()); \
85 int name = Smi::cast(obj)->value();
86
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087// Cast the given object to a double and store it in a variable with
88// the given name. If the object is not a number (as opposed to
89// the number not-a-number) call IllegalOperation and return.
90#define CONVERT_DOUBLE_CHECKED(name, obj) \
91 RUNTIME_ASSERT(obj->IsNumber()); \
92 double name = (obj)->Number();
93
94// Call the specified converter on the object *comand store the result in
95// a variable of the specified type with the given name. If the
96// object is not a Number call IllegalOperation and return.
97#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
98 RUNTIME_ASSERT(obj->IsNumber()); \
99 type name = NumberTo##Type(obj);
100
101// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000102static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104
lrn@chromium.org303ada72010-10-27 09:33:13 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000106 StackLimitCheck check;
107 if (check.HasOverflowed()) return Top::StackOverflow();
108
lrn@chromium.org303ada72010-10-27 09:33:13 +0000109 Object* result;
110 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
111 if (!maybe_result->ToObject(&result)) return maybe_result;
112 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000113 JSObject* copy = JSObject::cast(result);
114
115 // Deep copy local properties.
116 if (copy->HasFastProperties()) {
117 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 for (int i = 0; i < properties->length(); i++) {
119 Object* value = properties->get(i);
120 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000121 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000122 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
123 if (!maybe_result->ToObject(&result)) return maybe_result;
124 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126 }
127 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000128 int nof = copy->map()->inobject_properties();
129 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 Object* value = copy->InObjectPropertyAt(i);
131 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000132 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000133 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
134 if (!maybe_result->ToObject(&result)) return maybe_result;
135 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000137 }
138 }
139 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 { MaybeObject* maybe_result =
141 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
142 if (!maybe_result->ToObject(&result)) return maybe_result;
143 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000144 FixedArray* names = FixedArray::cast(result);
145 copy->GetLocalPropertyNames(names, 0);
146 for (int i = 0; i < names->length(); i++) {
147 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 // Only deep copy fields from the object literal expression.
152 // In particular, don't try to copy the length attribute of
153 // an array.
154 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000155 Object* value =
156 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000158 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
160 if (!maybe_result->ToObject(&result)) return maybe_result;
161 }
162 { MaybeObject* maybe_result =
163 copy->SetProperty(key_string, result, NONE);
164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 }
167 }
168 }
169
170 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000171 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000172 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 switch (copy->GetElementsKind()) {
174 case JSObject::FAST_ELEMENTS: {
175 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000176 if (elements->map() == Heap::fixed_cow_array_map()) {
177 Counters::cow_arrays_created_runtime.Increment();
178#ifdef DEBUG
179 for (int i = 0; i < elements->length(); i++) {
180 ASSERT(!elements->get(i)->IsJSObject());
181 }
182#endif
183 } else {
184 for (int i = 0; i < elements->length(); i++) {
185 Object* value = elements->get(i);
186 if (value->IsJSObject()) {
187 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000188 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
189 if (!maybe_result->ToObject(&result)) return maybe_result;
190 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000191 elements->set(i, result);
192 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 }
194 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000195 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000197 case JSObject::DICTIONARY_ELEMENTS: {
198 NumberDictionary* element_dictionary = copy->element_dictionary();
199 int capacity = element_dictionary->Capacity();
200 for (int i = 0; i < capacity; i++) {
201 Object* k = element_dictionary->KeyAt(i);
202 if (element_dictionary->IsKey(k)) {
203 Object* value = element_dictionary->ValueAt(i);
204 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000205 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000206 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
207 if (!maybe_result->ToObject(&result)) return maybe_result;
208 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 element_dictionary->ValueAtPut(i, result);
210 }
211 }
212 }
213 break;
214 }
215 default:
216 UNREACHABLE();
217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
219 return copy;
220}
221
222
lrn@chromium.org303ada72010-10-27 09:33:13 +0000223static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
225 return DeepCopyBoilerplate(boilerplate);
226}
227
228
lrn@chromium.org303ada72010-10-27 09:33:13 +0000229static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000231 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232}
233
234
ager@chromium.org236ad962008-09-25 09:45:57 +0000235static Handle<Map> ComputeObjectLiteralMap(
236 Handle<Context> context,
237 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000238 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000239 int properties_length = constant_properties->length();
240 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000241 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000242 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000243 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 for (int p = 0; p != properties_length; p += 2) {
245 Object* key = constant_properties->get(p);
246 uint32_t element_index = 0;
247 if (key->IsSymbol()) {
248 number_of_symbol_keys++;
249 } else if (key->ToArrayIndex(&element_index)) {
250 // An index key does not require space in the property backing store.
251 number_of_properties--;
252 } else {
253 // Bail out as a non-symbol non-index key makes caching impossible.
254 // ASSERT to make sure that the if condition after the loop is false.
255 ASSERT(number_of_symbol_keys != number_of_properties);
256 break;
257 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000258 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 // If we only have symbols and array indices among keys then we can
260 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000262 if ((number_of_symbol_keys == number_of_properties) &&
263 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 // Create the fixed array with the key.
265 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 if (number_of_symbol_keys > 0) {
267 int index = 0;
268 for (int p = 0; p < properties_length; p += 2) {
269 Object* key = constant_properties->get(p);
270 if (key->IsSymbol()) {
271 keys->set(index++, key);
272 }
273 }
274 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000275 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000276 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 return Factory::ObjectLiteralMapFromCache(context, keys);
278 }
279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000281 return Factory::CopyMap(
282 Handle<Map>(context->object_function()->initial_map()),
283 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284}
285
286
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000287static Handle<Object> CreateLiteralBoilerplate(
288 Handle<FixedArray> literals,
289 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000290
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000291
292static Handle<Object> CreateObjectLiteralBoilerplate(
293 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000294 Handle<FixedArray> constant_properties,
295 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000296 // Get the global context from the literals array. This is the
297 // context in which the function was created and we use the object
298 // function from this context to create the object literal. We do
299 // not use the object function from the current global context
300 // because this might be the object function from another context
301 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 Handle<Context> context =
303 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
304
305 bool is_result_from_cache;
306 Handle<Map> map = ComputeObjectLiteralMap(context,
307 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000308 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309
ager@chromium.org236ad962008-09-25 09:45:57 +0000310 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000311
312 // Normalize the elements of the boilerplate to save space if needed.
313 if (!should_have_fast_elements) NormalizeElements(boilerplate);
314
ager@chromium.org32912102009-01-16 10:38:43 +0000315 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000318 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 for (int index = 0; index < length; index +=2) {
321 Handle<Object> key(constant_properties->get(index+0));
322 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323 if (value->IsFixedArray()) {
324 // The value contains the constant_properties of a
325 // simple object literal.
326 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
327 value = CreateLiteralBoilerplate(literals, array);
328 if (value.is_null()) return value;
329 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000330 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000332 if (key->IsSymbol()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000333 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
334 // Array index as string (uint32).
335 result = SetOwnElement(boilerplate, element_index, value);
336 } else {
337 Handle<String> name(String::cast(*key));
338 ASSERT(!name->AsArrayIndex(&element_index));
339 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
340 value, NONE);
341 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000342 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 // Array index (uint32).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000344 result = SetOwnElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 } else {
346 // Non-uint32 number.
347 ASSERT(key->IsNumber());
348 double num = key->Number();
349 char arr[100];
350 Vector<char> buffer(arr, ARRAY_SIZE(arr));
351 const char* str = DoubleToCString(num, buffer);
352 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000353 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
354 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000356 // If setting the property on the boilerplate throws an
357 // exception, the exception is converted to an empty handle in
358 // the handle based operations. In that case, we need to
359 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000360 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 }
362 }
363
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000364 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000365}
366
367
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000368static Handle<Object> CreateArrayLiteralBoilerplate(
369 Handle<FixedArray> literals,
370 Handle<FixedArray> elements) {
371 // Create the JSArray.
372 Handle<JSFunction> constructor(
373 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
374 Handle<Object> object = Factory::NewJSObject(constructor);
375
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000376 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
377 Handle<FixedArray> copied_elements =
378 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000379
380 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000381 if (is_cow) {
382#ifdef DEBUG
383 // Copy-on-write arrays must be shallow (and simple).
384 for (int i = 0; i < content->length(); i++) {
385 ASSERT(!content->get(i)->IsFixedArray());
386 }
387#endif
388 } else {
389 for (int i = 0; i < content->length(); i++) {
390 if (content->get(i)->IsFixedArray()) {
391 // The value contains the constant_properties of a
392 // simple object literal.
393 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
394 Handle<Object> result =
395 CreateLiteralBoilerplate(literals, fa);
396 if (result.is_null()) return result;
397 content->set(i, *result);
398 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000399 }
400 }
401
402 // Set the elements.
403 Handle<JSArray>::cast(object)->SetContent(*content);
404 return object;
405}
406
407
408static Handle<Object> CreateLiteralBoilerplate(
409 Handle<FixedArray> literals,
410 Handle<FixedArray> array) {
411 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
412 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000413 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
414 return CreateObjectLiteralBoilerplate(literals, elements, true);
415 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
416 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417 case CompileTimeValue::ARRAY_LITERAL:
418 return CreateArrayLiteralBoilerplate(literals, elements);
419 default:
420 UNREACHABLE();
421 return Handle<Object>::null();
422 }
423}
424
425
lrn@chromium.org303ada72010-10-27 09:33:13 +0000426static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000427 // Takes a FixedArray of elements containing the literal elements of
428 // the array literal and produces JSArray with those elements.
429 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000430 // which contains the context from which to get the Array function
431 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432 HandleScope scope;
433 ASSERT(args.length() == 3);
434 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
435 CONVERT_SMI_CHECKED(literals_index, args[1]);
436 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
439 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 // Update the functions literal and return the boilerplate.
442 literals->set(literals_index, *object);
443 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444}
445
446
lrn@chromium.org303ada72010-10-27 09:33:13 +0000447static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000448 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000449 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000450 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
451 CONVERT_SMI_CHECKED(literals_index, args[1]);
452 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 CONVERT_SMI_CHECKED(fast_elements, args[3]);
454 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000455
456 // Check if boilerplate exists. If not, create it first.
457 Handle<Object> boilerplate(literals->get(literals_index));
458 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 boilerplate = CreateObjectLiteralBoilerplate(literals,
460 constant_properties,
461 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000462 if (boilerplate.is_null()) return Failure::Exception();
463 // Update the functions literal and return the boilerplate.
464 literals->set(literals_index, *boilerplate);
465 }
466 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
467}
468
469
lrn@chromium.org303ada72010-10-27 09:33:13 +0000470static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000471 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000472 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000473 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
474 CONVERT_SMI_CHECKED(literals_index, args[1]);
475 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000476 CONVERT_SMI_CHECKED(fast_elements, args[3]);
477 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000478
479 // Check if boilerplate exists. If not, create it first.
480 Handle<Object> boilerplate(literals->get(literals_index));
481 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000482 boilerplate = CreateObjectLiteralBoilerplate(literals,
483 constant_properties,
484 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000485 if (boilerplate.is_null()) return Failure::Exception();
486 // Update the functions literal and return the boilerplate.
487 literals->set(literals_index, *boilerplate);
488 }
489 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
490}
491
492
lrn@chromium.org303ada72010-10-27 09:33:13 +0000493static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000494 HandleScope scope;
495 ASSERT(args.length() == 3);
496 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
497 CONVERT_SMI_CHECKED(literals_index, args[1]);
498 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
499
500 // Check if boilerplate exists. If not, create it first.
501 Handle<Object> boilerplate(literals->get(literals_index));
502 if (*boilerplate == Heap::undefined_value()) {
503 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
504 if (boilerplate.is_null()) return Failure::Exception();
505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *boilerplate);
507 }
508 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
509}
510
511
lrn@chromium.org303ada72010-10-27 09:33:13 +0000512static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000513 HandleScope scope;
514 ASSERT(args.length() == 3);
515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
516 CONVERT_SMI_CHECKED(literals_index, args[1]);
517 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
518
519 // Check if boilerplate exists. If not, create it first.
520 Handle<Object> boilerplate(literals->get(literals_index));
521 if (*boilerplate == Heap::undefined_value()) {
522 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
523 if (boilerplate.is_null()) return Failure::Exception();
524 // Update the functions literal and return the boilerplate.
525 literals->set(literals_index, *boilerplate);
526 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000527 if (JSObject::cast(*boilerplate)->elements()->map() ==
528 Heap::fixed_cow_array_map()) {
529 Counters::cow_arrays_created_runtime.Increment();
530 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
532}
533
534
lrn@chromium.org303ada72010-10-27 09:33:13 +0000535static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000536 ASSERT(args.length() == 2);
537 CONVERT_CHECKED(String, key, args[0]);
538 Object* value = args[1];
539 // Create a catch context extension object.
540 JSFunction* constructor =
541 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000542 Object* object;
543 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
544 if (!maybe_object->ToObject(&object)) return maybe_object;
545 }
ager@chromium.org32912102009-01-16 10:38:43 +0000546 // Assign the exception value to the catch variable and make sure
547 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000548 { MaybeObject* maybe_value =
549 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
550 if (!maybe_value->ToObject(&value)) return maybe_value;
551 }
ager@chromium.org32912102009-01-16 10:38:43 +0000552 return object;
553}
554
555
lrn@chromium.org303ada72010-10-27 09:33:13 +0000556static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 NoHandleAllocation ha;
558 ASSERT(args.length() == 1);
559 Object* obj = args[0];
560 if (!obj->IsJSObject()) return Heap::null_value();
561 return JSObject::cast(obj)->class_name();
562}
563
ager@chromium.org7c537e22008-10-16 08:43:32 +0000564
lrn@chromium.org303ada72010-10-27 09:33:13 +0000565static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 NoHandleAllocation ha;
567 ASSERT(args.length() == 2);
568 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
569 Object* O = args[0];
570 Object* V = args[1];
571 while (true) {
572 Object* prototype = V->GetPrototype();
573 if (prototype->IsNull()) return Heap::false_value();
574 if (O == prototype) return Heap::true_value();
575 V = prototype;
576 }
577}
578
579
ager@chromium.org9085a012009-05-11 19:22:57 +0000580// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000581static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000582 NoHandleAllocation ha;
583 ASSERT(args.length() == 2);
584 CONVERT_CHECKED(JSObject, jsobject, args[0]);
585 CONVERT_CHECKED(JSObject, proto, args[1]);
586
587 // Sanity checks. The old prototype (that we are replacing) could
588 // theoretically be null, but if it is not null then check that we
589 // didn't already install a hidden prototype here.
590 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
591 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
592 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
593
594 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000595 Object* map_or_failure;
596 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
597 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
598 return maybe_map_or_failure;
599 }
600 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000601 Map* new_proto_map = Map::cast(map_or_failure);
602
lrn@chromium.org303ada72010-10-27 09:33:13 +0000603 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
604 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
605 return maybe_map_or_failure;
606 }
607 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000608 Map* new_map = Map::cast(map_or_failure);
609
610 // Set proto's prototype to be the old prototype of the object.
611 new_proto_map->set_prototype(jsobject->GetPrototype());
612 proto->set_map(new_proto_map);
613 new_proto_map->set_is_hidden_prototype();
614
615 // Set the object's prototype to proto.
616 new_map->set_prototype(proto);
617 jsobject->set_map(new_map);
618
619 return Heap::undefined_value();
620}
621
622
lrn@chromium.org303ada72010-10-27 09:33:13 +0000623static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000625 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 JavaScriptFrameIterator it;
627 return Heap::ToBoolean(it.frame()->IsConstructor());
628}
629
630
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000631// Recursively traverses hidden prototypes if property is not found
632static void GetOwnPropertyImplementation(JSObject* obj,
633 String* name,
634 LookupResult* result) {
635 obj->LocalLookupRealNamedProperty(name, result);
636
637 if (!result->IsProperty()) {
638 Object* proto = obj->GetPrototype();
639 if (proto->IsJSObject() &&
640 JSObject::cast(proto)->map()->is_hidden_prototype())
641 GetOwnPropertyImplementation(JSObject::cast(proto),
642 name, result);
643 }
644}
645
646
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000647static bool CheckAccessException(LookupResult* result,
648 v8::AccessType access_type) {
649 if (result->type() == CALLBACKS) {
650 Object* callback = result->GetCallbackObject();
651 if (callback->IsAccessorInfo()) {
652 AccessorInfo* info = AccessorInfo::cast(callback);
653 bool can_access =
654 (access_type == v8::ACCESS_HAS &&
655 (info->all_can_read() || info->all_can_write())) ||
656 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
657 (access_type == v8::ACCESS_SET && info->all_can_write());
658 return can_access;
659 }
660 }
661
662 return false;
663}
664
665
666static bool CheckAccess(JSObject* obj,
667 String* name,
668 LookupResult* result,
669 v8::AccessType access_type) {
670 ASSERT(result->IsProperty());
671
672 JSObject* holder = result->holder();
673 JSObject* current = obj;
674 while (true) {
675 if (current->IsAccessCheckNeeded() &&
676 !Top::MayNamedAccess(current, name, access_type)) {
677 // Access check callback denied the access, but some properties
678 // can have a special permissions which override callbacks descision
679 // (currently see v8::AccessControl).
680 break;
681 }
682
683 if (current == holder) {
684 return true;
685 }
686
687 current = JSObject::cast(current->GetPrototype());
688 }
689
690 // API callbacks can have per callback access exceptions.
691 switch (result->type()) {
692 case CALLBACKS: {
693 if (CheckAccessException(result, access_type)) {
694 return true;
695 }
696 break;
697 }
698 case INTERCEPTOR: {
699 // If the object has an interceptor, try real named properties.
700 // Overwrite the result to fetch the correct property later.
701 holder->LookupRealNamedProperty(name, result);
702 if (result->IsProperty()) {
703 if (CheckAccessException(result, access_type)) {
704 return true;
705 }
706 }
707 break;
708 }
709 default:
710 break;
711 }
712
713 Top::ReportFailedAccessCheck(current, access_type);
714 return false;
715}
716
717
718// TODO(1095): we should traverse hidden prototype hierachy as well.
719static bool CheckElementAccess(JSObject* obj,
720 uint32_t index,
721 v8::AccessType access_type) {
722 if (obj->IsAccessCheckNeeded() &&
723 !Top::MayIndexedAccess(obj, index, access_type)) {
724 return false;
725 }
726
727 return true;
728}
729
730
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000731// Enumerator used as indices into the array returned from GetOwnProperty
732enum PropertyDescriptorIndices {
733 IS_ACCESSOR_INDEX,
734 VALUE_INDEX,
735 GETTER_INDEX,
736 SETTER_INDEX,
737 WRITABLE_INDEX,
738 ENUMERABLE_INDEX,
739 CONFIGURABLE_INDEX,
740 DESCRIPTOR_SIZE
741};
742
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000743// Returns an array with the property description:
744// if args[1] is not a property on args[0]
745// returns undefined
746// if args[1] is a data property on args[0]
747// [false, value, Writeable, Enumerable, Configurable]
748// if args[1] is an accessor on args[0]
749// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000750static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000751 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000752 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000753 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000754 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
755 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000756 CONVERT_ARG_CHECKED(JSObject, obj, 0);
757 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000759 // This could be an element.
760 uint32_t index;
761 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000762 switch (obj->HasLocalElement(index)) {
763 case JSObject::UNDEFINED_ELEMENT:
764 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000765
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000766 case JSObject::STRING_CHARACTER_ELEMENT: {
767 // Special handling of string objects according to ECMAScript 5
768 // 15.5.5.2. Note that this might be a string object with elements
769 // other than the actual string value. This is covered by the
770 // subsequent cases.
771 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
772 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000773 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000774
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000775 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
776 elms->set(VALUE_INDEX, *substr);
777 elms->set(WRITABLE_INDEX, Heap::false_value());
778 elms->set(ENUMERABLE_INDEX, Heap::false_value());
779 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
780 return *desc;
781 }
782
783 case JSObject::INTERCEPTED_ELEMENT:
784 case JSObject::FAST_ELEMENT: {
785 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000786 elms->set(VALUE_INDEX, *GetElement(obj, index));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000787 elms->set(WRITABLE_INDEX, Heap::true_value());
788 elms->set(ENUMERABLE_INDEX, Heap::true_value());
789 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
790 return *desc;
791 }
792
793 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000794 Handle<JSObject> holder = obj;
795 if (obj->IsJSGlobalProxy()) {
796 Object* proto = obj->GetPrototype();
797 if (proto->IsNull()) return Heap::undefined_value();
798 ASSERT(proto->IsJSGlobalObject());
799 holder = Handle<JSObject>(JSObject::cast(proto));
800 }
801 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000802 int entry = dictionary->FindEntry(index);
803 ASSERT(entry != NumberDictionary::kNotFound);
804 PropertyDetails details = dictionary->DetailsAt(entry);
805 switch (details.type()) {
806 case CALLBACKS: {
807 // This is an accessor property with getter and/or setter.
808 FixedArray* callbacks =
809 FixedArray::cast(dictionary->ValueAt(entry));
810 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000811 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
812 elms->set(GETTER_INDEX, callbacks->get(0));
813 }
814 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
815 elms->set(SETTER_INDEX, callbacks->get(1));
816 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000817 break;
818 }
819 case NORMAL:
820 // This is a data property.
821 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000822 elms->set(VALUE_INDEX, *GetElement(obj, index));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000823 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
824 break;
825 default:
826 UNREACHABLE();
827 break;
828 }
829 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
830 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
831 return *desc;
832 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000833 }
834 }
835
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000836 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000837 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000838
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000839 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000840 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000841 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000842
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000843 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
844 return Heap::false_value();
845 }
846
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000847 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
848 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000849
850 bool is_js_accessor = (result.type() == CALLBACKS) &&
851 (result.GetCallbackObject()->IsFixedArray());
852
853 if (is_js_accessor) {
854 // __defineGetter__/__defineSetter__ callback.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000855 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856
857 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
858 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
859 elms->set(GETTER_INDEX, structure->get(0));
860 }
861 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
862 elms->set(SETTER_INDEX, structure->get(1));
863 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000864 } else {
865 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
866 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
867
868 PropertyAttributes attrs;
869 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000870 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000871 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
872 if (!maybe_value->ToObject(&value)) return maybe_value;
873 }
874 elms->set(VALUE_INDEX, value);
875 }
876
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000877 return *desc;
878}
879
880
lrn@chromium.org303ada72010-10-27 09:33:13 +0000881static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000882 ASSERT(args.length() == 1);
883 CONVERT_CHECKED(JSObject, obj, args[0]);
884 return obj->PreventExtensions();
885}
886
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000887
lrn@chromium.org303ada72010-10-27 09:33:13 +0000888static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000889 ASSERT(args.length() == 1);
890 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000891 if (obj->IsJSGlobalProxy()) {
892 Object* proto = obj->GetPrototype();
893 if (proto->IsNull()) return Heap::false_value();
894 ASSERT(proto->IsJSGlobalObject());
895 obj = JSObject::cast(proto);
896 }
897 return obj->map()->is_extensible() ? Heap::true_value()
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000898 : Heap::false_value();
899}
900
901
lrn@chromium.org303ada72010-10-27 09:33:13 +0000902static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000903 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000905 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
906 CONVERT_ARG_CHECKED(String, pattern, 1);
907 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000908 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
909 if (result.is_null()) return Failure::Exception();
910 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911}
912
913
lrn@chromium.org303ada72010-10-27 09:33:13 +0000914static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000915 HandleScope scope;
916 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000917 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000918 return *Factory::CreateApiFunction(data);
919}
920
921
lrn@chromium.org303ada72010-10-27 09:33:13 +0000922static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 ASSERT(args.length() == 1);
924 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000925 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 return Heap::ToBoolean(result);
927}
928
929
lrn@chromium.org303ada72010-10-27 09:33:13 +0000930static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 ASSERT(args.length() == 2);
932 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000934 int index = field->value();
935 int offset = index * kPointerSize + HeapObject::kHeaderSize;
936 InstanceType type = templ->map()->instance_type();
937 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
938 type == OBJECT_TEMPLATE_INFO_TYPE);
939 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000940 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000941 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
942 } else {
943 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
944 }
945 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000946}
947
948
lrn@chromium.org303ada72010-10-27 09:33:13 +0000949static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000950 ASSERT(args.length() == 1);
951 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000952 Map* old_map = object->map();
953 bool needs_access_checks = old_map->is_access_check_needed();
954 if (needs_access_checks) {
955 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000956 Object* new_map;
957 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
958 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
959 }
ager@chromium.org32912102009-01-16 10:38:43 +0000960
961 Map::cast(new_map)->set_is_access_check_needed(false);
962 object->set_map(Map::cast(new_map));
963 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000964 return needs_access_checks ? Heap::true_value() : Heap::false_value();
965}
966
967
lrn@chromium.org303ada72010-10-27 09:33:13 +0000968static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000969 ASSERT(args.length() == 1);
970 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000971 Map* old_map = object->map();
972 if (!old_map->is_access_check_needed()) {
973 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000974 Object* new_map;
975 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
976 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
977 }
ager@chromium.org32912102009-01-16 10:38:43 +0000978
979 Map::cast(new_map)->set_is_access_check_needed(true);
980 object->set_map(Map::cast(new_map));
981 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000982 return Heap::undefined_value();
983}
984
985
lrn@chromium.org303ada72010-10-27 09:33:13 +0000986static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987 HandleScope scope;
988 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
989 Handle<Object> args[2] = { type_handle, name };
990 Handle<Object> error =
991 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
992 return Top::Throw(*error);
993}
994
995
lrn@chromium.org303ada72010-10-27 09:33:13 +0000996static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 HandleScope scope;
998 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
999
ager@chromium.org3811b432009-10-28 14:53:37 +00001000 Handle<Context> context = args.at<Context>(0);
1001 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 bool is_eval = Smi::cast(args[2])->value() == 1;
1003
1004 // Compute the property attributes. According to ECMA-262, section
1005 // 13, page 71, the property must be read-only and
1006 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1007 // property as read-only, so we don't either.
1008 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1009
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 // Traverse the name/value pairs and set the properties.
1011 int length = pairs->length();
1012 for (int i = 0; i < length; i += 2) {
1013 HandleScope scope;
1014 Handle<String> name(String::cast(pairs->get(i)));
1015 Handle<Object> value(pairs->get(i + 1));
1016
1017 // We have to declare a global const property. To capture we only
1018 // assign to it when evaluating the assignment for "const x =
1019 // <expr>" the initial value is the hole.
1020 bool is_const_property = value->IsTheHole();
1021
1022 if (value->IsUndefined() || is_const_property) {
1023 // Lookup the property in the global object, and don't set the
1024 // value of the variable if the property is already there.
1025 LookupResult lookup;
1026 global->Lookup(*name, &lookup);
1027 if (lookup.IsProperty()) {
1028 // Determine if the property is local by comparing the holder
1029 // against the global object. The information will be used to
1030 // avoid throwing re-declaration errors when declaring
1031 // variables or constants that exist in the prototype chain.
1032 bool is_local = (*global == lookup.holder());
1033 // Get the property attributes and determine if the property is
1034 // read-only.
1035 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1036 bool is_read_only = (attributes & READ_ONLY) != 0;
1037 if (lookup.type() == INTERCEPTOR) {
1038 // If the interceptor says the property is there, we
1039 // just return undefined without overwriting the property.
1040 // Otherwise, we continue to setting the property.
1041 if (attributes != ABSENT) {
1042 // Check if the existing property conflicts with regards to const.
1043 if (is_local && (is_read_only || is_const_property)) {
1044 const char* type = (is_read_only) ? "const" : "var";
1045 return ThrowRedeclarationError(type, name);
1046 };
1047 // The property already exists without conflicting: Go to
1048 // the next declaration.
1049 continue;
1050 }
1051 // Fall-through and introduce the absent property by using
1052 // SetProperty.
1053 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001054 // For const properties, we treat a callback with this name
1055 // even in the prototype as a conflicting declaration.
1056 if (is_const_property && (lookup.type() == CALLBACKS)) {
1057 return ThrowRedeclarationError("const", name);
1058 }
1059 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060 if (is_local && (is_read_only || is_const_property)) {
1061 const char* type = (is_read_only) ? "const" : "var";
1062 return ThrowRedeclarationError(type, name);
1063 }
1064 // The property already exists without conflicting: Go to
1065 // the next declaration.
1066 continue;
1067 }
1068 }
1069 } else {
1070 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001071 Handle<SharedFunctionInfo> shared =
1072 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001074 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 value = function;
1076 }
1077
1078 LookupResult lookup;
1079 global->LocalLookup(*name, &lookup);
1080
1081 PropertyAttributes attributes = is_const_property
1082 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1083 : base;
1084
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001085 // There's a local property that we need to overwrite because
1086 // we're either declaring a function or there's an interceptor
1087 // that claims the property is absent.
1088 //
1089 // Check for conflicting re-declarations. We cannot have
1090 // conflicting types in case of intercepted properties because
1091 // they are absent.
1092 if (lookup.IsProperty() &&
1093 (lookup.type() != INTERCEPTOR) &&
1094 (lookup.IsReadOnly() || is_const_property)) {
1095 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
1096 return ThrowRedeclarationError(type, name);
1097 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001099 // Safari does not allow the invocation of callback setters for
1100 // function declarations. To mimic this behavior, we do not allow
1101 // the invocation of setters for function values. This makes a
1102 // difference for global functions with the same names as event
1103 // handlers such as "function onload() {}". Firefox does call the
1104 // onload setter in those case and Safari does not. We follow
1105 // Safari for compatibility.
1106 if (value->IsJSFunction()) {
1107 RETURN_IF_EMPTY_HANDLE(SetLocalPropertyIgnoreAttributes(global,
1108 name,
1109 value,
1110 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001112 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113 }
1114 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001115
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001116 ASSERT(!Top::has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001117 return Heap::undefined_value();
1118}
1119
1120
lrn@chromium.org303ada72010-10-27 09:33:13 +00001121static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001122 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001123 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001124
ager@chromium.org7c537e22008-10-16 08:43:32 +00001125 CONVERT_ARG_CHECKED(Context, context, 0);
1126 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001127 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001128 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001129 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001130 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131
1132 // Declarations are always done in the function context.
1133 context = Handle<Context>(context->fcontext());
1134
1135 int index;
1136 PropertyAttributes attributes;
1137 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001138 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001139 context->Lookup(name, flags, &index, &attributes);
1140
1141 if (attributes != ABSENT) {
1142 // The name was declared before; check for conflicting
1143 // re-declarations: This is similar to the code in parser.cc in
1144 // the AstBuildingParser::Declare function.
1145 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1146 // Functions are not read-only.
1147 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1148 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1149 return ThrowRedeclarationError(type, name);
1150 }
1151
1152 // Initialize it if necessary.
1153 if (*initial_value != NULL) {
1154 if (index >= 0) {
1155 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001156 // the function context or the arguments object.
1157 if (holder->IsContext()) {
1158 ASSERT(holder.is_identical_to(context));
1159 if (((attributes & READ_ONLY) == 0) ||
1160 context->get(index)->IsTheHole()) {
1161 context->set(index, *initial_value);
1162 }
1163 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001164 // The holder is an arguments object.
1165 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001166 Handle<Object> result = SetElement(arguments, index, initial_value);
1167 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 }
1169 } else {
1170 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001171 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001172 RETURN_IF_EMPTY_HANDLE(
1173 SetProperty(context_ext, name, initial_value, mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 }
1175 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001178 // The property is not in the function context. It needs to be
1179 // "declared" in the function context's extension context, or in the
1180 // global context.
1181 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001182 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001183 // The function context's extension context exists - use it.
1184 context_ext = Handle<JSObject>(context->extension());
1185 } else {
1186 // The function context's extension context does not exists - allocate
1187 // it.
1188 context_ext = Factory::NewJSObject(Top::context_extension_function());
1189 // And store it in the extension slot.
1190 context->set_extension(*context_ext);
1191 }
1192 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193
ager@chromium.org7c537e22008-10-16 08:43:32 +00001194 // Declare the property by setting it to the initial value if provided,
1195 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1196 // constant declarations).
1197 ASSERT(!context_ext->HasLocalProperty(*name));
1198 Handle<Object> value(Heap::undefined_value());
1199 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001200 // Declaring a const context slot is a conflicting declaration if
1201 // there is a callback with that name in a prototype. It is
1202 // allowed to introduce const variables in
1203 // JSContextExtensionObjects. They are treated specially in
1204 // SetProperty and no setters are invoked for those since they are
1205 // not real JSObjects.
1206 if (initial_value->IsTheHole() &&
1207 !context_ext->IsJSContextExtensionObject()) {
1208 LookupResult lookup;
1209 context_ext->Lookup(*name, &lookup);
1210 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
1211 return ThrowRedeclarationError("const", name);
1212 }
1213 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001214 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001215 }
1216
1217 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218}
1219
1220
lrn@chromium.org303ada72010-10-27 09:33:13 +00001221static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 NoHandleAllocation nha;
1223
1224 // Determine if we need to assign to the variable if it already
1225 // exists (based on the number of arguments).
1226 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1227 bool assign = args.length() == 2;
1228
1229 CONVERT_ARG_CHECKED(String, name, 0);
1230 GlobalObject* global = Top::context()->global();
1231
1232 // According to ECMA-262, section 12.2, page 62, the property must
1233 // not be deletable.
1234 PropertyAttributes attributes = DONT_DELETE;
1235
1236 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001237 // there, there is a property with this name in the prototype chain.
1238 // We follow Safari and Firefox behavior and only set the property
1239 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001240 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001241 // Note that objects can have hidden prototypes, so we need to traverse
1242 // the whole chain of hidden prototypes to do a 'local' lookup.
1243 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001245 while (true) {
1246 real_holder->LocalLookup(*name, &lookup);
1247 if (lookup.IsProperty()) {
1248 // Determine if this is a redeclaration of something read-only.
1249 if (lookup.IsReadOnly()) {
1250 // If we found readonly property on one of hidden prototypes,
1251 // just shadow it.
1252 if (real_holder != Top::context()->global()) break;
1253 return ThrowRedeclarationError("const", name);
1254 }
1255
1256 // Determine if this is a redeclaration of an intercepted read-only
1257 // property and figure out if the property exists at all.
1258 bool found = true;
1259 PropertyType type = lookup.type();
1260 if (type == INTERCEPTOR) {
1261 HandleScope handle_scope;
1262 Handle<JSObject> holder(real_holder);
1263 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1264 real_holder = *holder;
1265 if (intercepted == ABSENT) {
1266 // The interceptor claims the property isn't there. We need to
1267 // make sure to introduce it.
1268 found = false;
1269 } else if ((intercepted & READ_ONLY) != 0) {
1270 // The property is present, but read-only. Since we're trying to
1271 // overwrite it with a variable declaration we must throw a
1272 // re-declaration error. However if we found readonly property
1273 // on one of hidden prototypes, just shadow it.
1274 if (real_holder != Top::context()->global()) break;
1275 return ThrowRedeclarationError("const", name);
1276 }
1277 }
1278
1279 if (found && !assign) {
1280 // The global property is there and we're not assigning any value
1281 // to it. Just return.
1282 return Heap::undefined_value();
1283 }
1284
1285 // Assign the value (or undefined) to the property.
1286 Object* value = (assign) ? args[1] : Heap::undefined_value();
1287 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001288 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001289
1290 Object* proto = real_holder->GetPrototype();
1291 if (!proto->IsJSObject())
1292 break;
1293
1294 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1295 break;
1296
1297 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 }
1299
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001300 global = Top::context()->global();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001301 if (assign) return global->SetProperty(*name, args[1], attributes);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001302 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303}
1304
1305
lrn@chromium.org303ada72010-10-27 09:33:13 +00001306static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 // All constants are declared with an initial value. The name
1308 // of the constant is the first argument and the initial value
1309 // is the second.
1310 RUNTIME_ASSERT(args.length() == 2);
1311 CONVERT_ARG_CHECKED(String, name, 0);
1312 Handle<Object> value = args.at<Object>(1);
1313
1314 // Get the current global object from top.
1315 GlobalObject* global = Top::context()->global();
1316
1317 // According to ECMA-262, section 12.2, page 62, the property must
1318 // not be deletable. Since it's a const, it must be READ_ONLY too.
1319 PropertyAttributes attributes =
1320 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1321
1322 // Lookup the property locally in the global object. If it isn't
1323 // there, we add the property and take special precautions to always
1324 // add it as a local property even in case of callbacks in the
1325 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001326 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 LookupResult lookup;
1328 global->LocalLookup(*name, &lookup);
1329 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001330 return global->SetLocalPropertyIgnoreAttributes(*name,
1331 *value,
1332 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333 }
1334
1335 // Determine if this is a redeclaration of something not
1336 // read-only. In case the result is hidden behind an interceptor we
1337 // need to ask it for the property attributes.
1338 if (!lookup.IsReadOnly()) {
1339 if (lookup.type() != INTERCEPTOR) {
1340 return ThrowRedeclarationError("var", name);
1341 }
1342
1343 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1344
1345 // Throw re-declaration error if the intercepted property is present
1346 // but not read-only.
1347 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1348 return ThrowRedeclarationError("var", name);
1349 }
1350
1351 // Restore global object from context (in case of GC) and continue
1352 // with setting the value because the property is either absent or
1353 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001354 HandleScope handle_scope;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001355 Handle<GlobalObject> global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001357 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 // property through an interceptor and only do it if it's
1359 // uninitialized, e.g. the hole. Nirk...
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001360 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 return *value;
1362 }
1363
1364 // Set the value, but only we're assigning the initial value to a
1365 // constant. For now, we determine this by checking if the
1366 // current value is the hole.
1367 PropertyType type = lookup.type();
1368 if (type == FIELD) {
1369 FixedArray* properties = global->properties();
1370 int index = lookup.GetFieldIndex();
1371 if (properties->get(index)->IsTheHole()) {
1372 properties->set(index, *value);
1373 }
1374 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001375 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1376 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377 }
1378 } else {
1379 // Ignore re-initialization of constants that have already been
1380 // assigned a function value.
1381 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1382 }
1383
1384 // Use the set value as the result of the operation.
1385 return *value;
1386}
1387
1388
lrn@chromium.org303ada72010-10-27 09:33:13 +00001389static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 HandleScope scope;
1391 ASSERT(args.length() == 3);
1392
1393 Handle<Object> value(args[0]);
1394 ASSERT(!value->IsTheHole());
1395 CONVERT_ARG_CHECKED(Context, context, 1);
1396 Handle<String> name(String::cast(args[2]));
1397
1398 // Initializations are always done in the function context.
1399 context = Handle<Context>(context->fcontext());
1400
1401 int index;
1402 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001403 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001404 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405 context->Lookup(name, flags, &index, &attributes);
1406
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001407 // In most situations, the property introduced by the const
1408 // declaration should be present in the context extension object.
1409 // However, because declaration and initialization are separate, the
1410 // property might have been deleted (if it was introduced by eval)
1411 // before we reach the initialization point.
1412 //
1413 // Example:
1414 //
1415 // function f() { eval("delete x; const x;"); }
1416 //
1417 // In that case, the initialization behaves like a normal assignment
1418 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001420 // Property was found in a context.
1421 if (holder->IsContext()) {
1422 // The holder cannot be the function context. If it is, there
1423 // should have been a const redeclaration error when declaring
1424 // the const property.
1425 ASSERT(!holder.is_identical_to(context));
1426 if ((attributes & READ_ONLY) == 0) {
1427 Handle<Context>::cast(holder)->set(index, *value);
1428 }
1429 } else {
1430 // The holder is an arguments object.
1431 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001432 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1433 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 }
1435 return *value;
1436 }
1437
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001438 // The property could not be found, we introduce it in the global
1439 // context.
1440 if (attributes == ABSENT) {
1441 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001442 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, NONE));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001443 return *value;
1444 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001446 // The property was present in a context extension object.
1447 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001448
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001449 if (*context_ext == context->extension()) {
1450 // This is the property that was introduced by the const
1451 // declaration. Set it if it hasn't been set before. NOTE: We
1452 // cannot use GetProperty() to get the current value as it
1453 // 'unholes' the value.
1454 LookupResult lookup;
1455 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1456 ASSERT(lookup.IsProperty()); // the property was declared
1457 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1458
1459 PropertyType type = lookup.type();
1460 if (type == FIELD) {
1461 FixedArray* properties = context_ext->properties();
1462 int index = lookup.GetFieldIndex();
1463 if (properties->get(index)->IsTheHole()) {
1464 properties->set(index, *value);
1465 }
1466 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001467 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1468 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001469 }
1470 } else {
1471 // We should not reach here. Any real, named property should be
1472 // either a field or a dictionary slot.
1473 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001474 }
1475 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001476 // The property was found in a different context extension object.
1477 // Set it if it is not a read-only property.
1478 if ((attributes & READ_ONLY) == 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001479 RETURN_IF_EMPTY_HANDLE(
1480 SetProperty(context_ext, name, value, attributes));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001481 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001483
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484 return *value;
1485}
1486
1487
lrn@chromium.org303ada72010-10-27 09:33:13 +00001488static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001489 Arguments args) {
1490 HandleScope scope;
1491 ASSERT(args.length() == 2);
1492 CONVERT_ARG_CHECKED(JSObject, object, 0);
1493 CONVERT_SMI_CHECKED(properties, args[1]);
1494 if (object->HasFastProperties()) {
1495 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1496 }
1497 return *object;
1498}
1499
1500
lrn@chromium.org303ada72010-10-27 09:33:13 +00001501static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001503 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001504 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1505 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001506 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001507 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001508 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001509 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001510 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001511 RUNTIME_ASSERT(index >= 0);
1512 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001513 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001514 Handle<Object> result = RegExpImpl::Exec(regexp,
1515 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001516 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001517 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001518 if (result.is_null()) return Failure::Exception();
1519 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001520}
1521
1522
lrn@chromium.org303ada72010-10-27 09:33:13 +00001523static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001524 ASSERT(args.length() == 3);
1525 CONVERT_SMI_CHECKED(elements_count, args[0]);
1526 if (elements_count > JSArray::kMaxFastElementsLength) {
1527 return Top::ThrowIllegalOperation();
1528 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001529 Object* new_object;
1530 { MaybeObject* maybe_new_object =
1531 Heap::AllocateFixedArrayWithHoles(elements_count);
1532 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1533 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001534 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001535 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1536 NEW_SPACE,
1537 OLD_POINTER_SPACE);
1538 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1539 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001540 {
1541 AssertNoAllocation no_gc;
1542 HandleScope scope;
1543 reinterpret_cast<HeapObject*>(new_object)->
1544 set_map(Top::global_context()->regexp_result_map());
1545 }
1546 JSArray* array = JSArray::cast(new_object);
1547 array->set_properties(Heap::empty_fixed_array());
1548 array->set_elements(elements);
1549 array->set_length(Smi::FromInt(elements_count));
1550 // Write in-object properties after the length of the array.
1551 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1552 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1553 return array;
1554}
1555
1556
lrn@chromium.org303ada72010-10-27 09:33:13 +00001557static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001558 AssertNoAllocation no_alloc;
1559 ASSERT(args.length() == 5);
1560 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1561 CONVERT_CHECKED(String, source, args[1]);
1562
1563 Object* global = args[2];
1564 if (!global->IsTrue()) global = Heap::false_value();
1565
1566 Object* ignoreCase = args[3];
1567 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1568
1569 Object* multiline = args[4];
1570 if (!multiline->IsTrue()) multiline = Heap::false_value();
1571
1572 Map* map = regexp->map();
1573 Object* constructor = map->constructor();
1574 if (constructor->IsJSFunction() &&
1575 JSFunction::cast(constructor)->initial_map() == map) {
1576 // If we still have the original map, set in-object properties directly.
1577 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1578 // TODO(lrn): Consider skipping write barrier on booleans as well.
1579 // Both true and false should be in oldspace at all times.
1580 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1581 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1582 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1583 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1584 Smi::FromInt(0),
1585 SKIP_WRITE_BARRIER);
1586 return regexp;
1587 }
1588
lrn@chromium.org303ada72010-10-27 09:33:13 +00001589 // Map has changed, so use generic, but slower, method. Since these
1590 // properties were all added as DONT_DELETE they must be present and
1591 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001592 PropertyAttributes final =
1593 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1594 PropertyAttributes writable =
1595 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001596 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001597 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1598 source,
1599 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001600 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001601 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1602 global,
1603 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001604 ASSERT(!result->IsFailure());
1605 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001606 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1607 ignoreCase,
1608 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001609 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001610 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1611 multiline,
1612 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001613 ASSERT(!result->IsFailure());
1614 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001615 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1616 Smi::FromInt(0),
1617 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001618 ASSERT(!result->IsFailure());
1619 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001620 return regexp;
1621}
1622
1623
lrn@chromium.org303ada72010-10-27 09:33:13 +00001624static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001625 HandleScope scope;
1626 ASSERT(args.length() == 1);
1627 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1628 // This is necessary to enable fast checks for absence of elements
1629 // on Array.prototype and below.
1630 prototype->set_elements(Heap::empty_fixed_array());
1631 return Smi::FromInt(0);
1632}
1633
1634
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001635static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1636 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001637 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001638 Handle<String> key = Factory::LookupAsciiSymbol(name);
1639 Handle<Code> code(Builtins::builtin(builtin_name));
1640 Handle<JSFunction> optimized = Factory::NewFunction(key,
1641 JS_OBJECT_TYPE,
1642 JSObject::kHeaderSize,
1643 code,
1644 false);
1645 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001646 SetProperty(holder, key, optimized, NONE);
1647 return optimized;
1648}
1649
1650
lrn@chromium.org303ada72010-10-27 09:33:13 +00001651static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001652 HandleScope scope;
1653 ASSERT(args.length() == 1);
1654 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1655
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001656 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1657 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001658 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1659 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1660 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1661 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001662 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001663
1664 return *holder;
1665}
1666
1667
lrn@chromium.org303ada72010-10-27 09:33:13 +00001668static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001669 // Returns a real global receiver, not one of builtins object.
1670 Context* global_context = Top::context()->global()->global_context();
1671 return global_context->global()->global_receiver();
1672}
1673
1674
lrn@chromium.org303ada72010-10-27 09:33:13 +00001675static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001676 HandleScope scope;
1677 ASSERT(args.length() == 4);
1678 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1679 int index = Smi::cast(args[1])->value();
1680 Handle<String> pattern = args.at<String>(2);
1681 Handle<String> flags = args.at<String>(3);
1682
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001683 // Get the RegExp function from the context in the literals array.
1684 // This is the RegExp function from the context in which the
1685 // function was created. We do not use the RegExp function from the
1686 // current global context because this might be the RegExp function
1687 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001688 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001689 Handle<JSFunction>(
1690 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001691 // Compute the regular expression literal.
1692 bool has_pending_exception;
1693 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001694 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1695 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696 if (has_pending_exception) {
1697 ASSERT(Top::has_pending_exception());
1698 return Failure::Exception();
1699 }
1700 literals->set(index, *regexp);
1701 return *regexp;
1702}
1703
1704
lrn@chromium.org303ada72010-10-27 09:33:13 +00001705static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706 NoHandleAllocation ha;
1707 ASSERT(args.length() == 1);
1708
1709 CONVERT_CHECKED(JSFunction, f, args[0]);
1710 return f->shared()->name();
1711}
1712
1713
lrn@chromium.org303ada72010-10-27 09:33:13 +00001714static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001715 NoHandleAllocation ha;
1716 ASSERT(args.length() == 2);
1717
1718 CONVERT_CHECKED(JSFunction, f, args[0]);
1719 CONVERT_CHECKED(String, name, args[1]);
1720 f->shared()->set_name(name);
1721 return Heap::undefined_value();
1722}
1723
1724
lrn@chromium.org303ada72010-10-27 09:33:13 +00001725static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001726 NoHandleAllocation ha;
1727 ASSERT(args.length() == 1);
1728
1729 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 Object* obj;
1731 { MaybeObject* maybe_obj = f->RemovePrototype();
1732 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1733 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001734
1735 return Heap::undefined_value();
1736}
1737
1738
lrn@chromium.org303ada72010-10-27 09:33:13 +00001739static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001740 HandleScope scope;
1741 ASSERT(args.length() == 1);
1742
1743 CONVERT_CHECKED(JSFunction, fun, args[0]);
1744 Handle<Object> script = Handle<Object>(fun->shared()->script());
1745 if (!script->IsScript()) return Heap::undefined_value();
1746
1747 return *GetScriptWrapper(Handle<Script>::cast(script));
1748}
1749
1750
lrn@chromium.org303ada72010-10-27 09:33:13 +00001751static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001752 NoHandleAllocation ha;
1753 ASSERT(args.length() == 1);
1754
1755 CONVERT_CHECKED(JSFunction, f, args[0]);
1756 return f->shared()->GetSourceCode();
1757}
1758
1759
lrn@chromium.org303ada72010-10-27 09:33:13 +00001760static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001761 NoHandleAllocation ha;
1762 ASSERT(args.length() == 1);
1763
1764 CONVERT_CHECKED(JSFunction, fun, args[0]);
1765 int pos = fun->shared()->start_position();
1766 return Smi::FromInt(pos);
1767}
1768
1769
lrn@chromium.org303ada72010-10-27 09:33:13 +00001770static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001771 ASSERT(args.length() == 2);
1772
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001773 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001774 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1775
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001776 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1777
1778 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001779 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001780}
1781
1782
1783
lrn@chromium.org303ada72010-10-27 09:33:13 +00001784static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001785 NoHandleAllocation ha;
1786 ASSERT(args.length() == 2);
1787
1788 CONVERT_CHECKED(JSFunction, fun, args[0]);
1789 CONVERT_CHECKED(String, name, args[1]);
1790 fun->SetInstanceClassName(name);
1791 return Heap::undefined_value();
1792}
1793
1794
lrn@chromium.org303ada72010-10-27 09:33:13 +00001795static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796 NoHandleAllocation ha;
1797 ASSERT(args.length() == 2);
1798
1799 CONVERT_CHECKED(JSFunction, fun, args[0]);
1800 CONVERT_CHECKED(Smi, length, args[1]);
1801 fun->shared()->set_length(length->value());
1802 return length;
1803}
1804
1805
lrn@chromium.org303ada72010-10-27 09:33:13 +00001806static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001808 ASSERT(args.length() == 2);
1809
1810 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001811 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812 Object* obj;
1813 { MaybeObject* maybe_obj =
1814 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1815 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1816 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 return args[0]; // return TOS
1818}
1819
1820
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001822 NoHandleAllocation ha;
1823 ASSERT(args.length() == 1);
1824
1825 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001826 return f->shared()->IsApiFunction() ? Heap::true_value()
1827 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001828}
1829
lrn@chromium.org303ada72010-10-27 09:33:13 +00001830static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001831 NoHandleAllocation ha;
1832 ASSERT(args.length() == 1);
1833
1834 CONVERT_CHECKED(JSFunction, f, args[0]);
1835 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1836}
1837
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001838
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001840 HandleScope scope;
1841 ASSERT(args.length() == 2);
1842
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001843 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001844 Handle<Object> code = args.at<Object>(1);
1845
1846 Handle<Context> context(target->context());
1847
1848 if (!code->IsNull()) {
1849 RUNTIME_ASSERT(code->IsJSFunction());
1850 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001851 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001852
1853 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001854 return Failure::Exception();
1855 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001856 // Since we don't store the source for this we should never
1857 // optimize this.
1858 shared->code()->set_optimizable(false);
1859
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001860 // Set the code, scope info, formal parameter count,
1861 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001862 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001863 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001864 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001865 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001866 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001867 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001868 // Set the source code of the target function to undefined.
1869 // SetCode is only used for built-in constructors like String,
1870 // Array, and Object, and some web code
1871 // doesn't like seeing source code for constructors.
1872 target->shared()->set_script(Heap::undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001873 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001874 // Clear the optimization hints related to the compiled code as these are no
1875 // longer valid when the code is overwritten.
1876 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001877 context = Handle<Context>(fun->context());
1878
1879 // Make sure we get a fresh copy of the literal vector to avoid
1880 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001881 int number_of_literals = fun->NumberOfLiterals();
1882 Handle<FixedArray> literals =
1883 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001885 // Insert the object, regexp and array functions in the literals
1886 // array prefix. These are the functions that will be used when
1887 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001888 literals->set(JSFunction::kLiteralGlobalContextIndex,
1889 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001891 // It's okay to skip the write barrier here because the literals
1892 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001893 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001894 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001895 }
1896
1897 target->set_context(*context);
1898 return *target;
1899}
1900
1901
lrn@chromium.org303ada72010-10-27 09:33:13 +00001902static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001903 HandleScope scope;
1904 ASSERT(args.length() == 2);
1905 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1906 CONVERT_SMI_CHECKED(num, args[1]);
1907 RUNTIME_ASSERT(num >= 0);
1908 SetExpectedNofProperties(function, num);
1909 return Heap::undefined_value();
1910}
1911
1912
lrn@chromium.org303ada72010-10-27 09:33:13 +00001913MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001914 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001915 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001916 if (code <= 0xffff) {
1917 return Heap::LookupSingleCharacterStringFromCode(code);
1918 }
1919 }
1920 return Heap::empty_string();
1921}
1922
1923
lrn@chromium.org303ada72010-10-27 09:33:13 +00001924static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 NoHandleAllocation ha;
1926 ASSERT(args.length() == 2);
1927
1928 CONVERT_CHECKED(String, subject, args[0]);
1929 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001930 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001931
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001932 uint32_t i = 0;
1933 if (index->IsSmi()) {
1934 int value = Smi::cast(index)->value();
1935 if (value < 0) return Heap::nan_value();
1936 i = value;
1937 } else {
1938 ASSERT(index->IsHeapNumber());
1939 double value = HeapNumber::cast(index)->value();
1940 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001941 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001942
1943 // Flatten the string. If someone wants to get a char at an index
1944 // in a cons string, it is likely that more indices will be
1945 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001946 Object* flat;
1947 { MaybeObject* maybe_flat = subject->TryFlatten();
1948 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1949 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001950 subject = String::cast(flat);
1951
1952 if (i >= static_cast<uint32_t>(subject->length())) {
1953 return Heap::nan_value();
1954 }
1955
1956 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001957}
1958
1959
lrn@chromium.org303ada72010-10-27 09:33:13 +00001960static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001961 NoHandleAllocation ha;
1962 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001963 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001964}
1965
lrn@chromium.org25156de2010-04-06 13:10:27 +00001966
1967class FixedArrayBuilder {
1968 public:
1969 explicit FixedArrayBuilder(int initial_capacity)
1970 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1971 length_(0) {
1972 // Require a non-zero initial size. Ensures that doubling the size to
1973 // extend the array will work.
1974 ASSERT(initial_capacity > 0);
1975 }
1976
1977 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1978 : array_(backing_store),
1979 length_(0) {
1980 // Require a non-zero initial size. Ensures that doubling the size to
1981 // extend the array will work.
1982 ASSERT(backing_store->length() > 0);
1983 }
1984
1985 bool HasCapacity(int elements) {
1986 int length = array_->length();
1987 int required_length = length_ + elements;
1988 return (length >= required_length);
1989 }
1990
1991 void EnsureCapacity(int elements) {
1992 int length = array_->length();
1993 int required_length = length_ + elements;
1994 if (length < required_length) {
1995 int new_length = length;
1996 do {
1997 new_length *= 2;
1998 } while (new_length < required_length);
1999 Handle<FixedArray> extended_array =
2000 Factory::NewFixedArrayWithHoles(new_length);
2001 array_->CopyTo(0, *extended_array, 0, length_);
2002 array_ = extended_array;
2003 }
2004 }
2005
2006 void Add(Object* value) {
2007 ASSERT(length_ < capacity());
2008 array_->set(length_, value);
2009 length_++;
2010 }
2011
2012 void Add(Smi* value) {
2013 ASSERT(length_ < capacity());
2014 array_->set(length_, value);
2015 length_++;
2016 }
2017
2018 Handle<FixedArray> array() {
2019 return array_;
2020 }
2021
2022 int length() {
2023 return length_;
2024 }
2025
2026 int capacity() {
2027 return array_->length();
2028 }
2029
2030 Handle<JSArray> ToJSArray() {
2031 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
2032 result_array->set_length(Smi::FromInt(length_));
2033 return result_array;
2034 }
2035
2036 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2037 target_array->set_elements(*array_);
2038 target_array->set_length(Smi::FromInt(length_));
2039 return target_array;
2040 }
2041
2042 private:
2043 Handle<FixedArray> array_;
2044 int length_;
2045};
2046
2047
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002048// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002049const int kStringBuilderConcatHelperLengthBits = 11;
2050const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002051
2052template <typename schar>
2053static inline void StringBuilderConcatHelper(String*,
2054 schar*,
2055 FixedArray*,
2056 int);
2057
lrn@chromium.org25156de2010-04-06 13:10:27 +00002058typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2059 StringBuilderSubstringLength;
2060typedef BitField<int,
2061 kStringBuilderConcatHelperLengthBits,
2062 kStringBuilderConcatHelperPositionBits>
2063 StringBuilderSubstringPosition;
2064
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002065
2066class ReplacementStringBuilder {
2067 public:
2068 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00002069 : array_builder_(estimated_part_count),
2070 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002071 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002072 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002073 // Require a non-zero initial size. Ensures that doubling the size to
2074 // extend the array will work.
2075 ASSERT(estimated_part_count > 0);
2076 }
2077
lrn@chromium.org25156de2010-04-06 13:10:27 +00002078 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2079 int from,
2080 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002081 ASSERT(from >= 0);
2082 int length = to - from;
2083 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002084 if (StringBuilderSubstringLength::is_valid(length) &&
2085 StringBuilderSubstringPosition::is_valid(from)) {
2086 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2087 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002088 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002089 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002090 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002091 builder->Add(Smi::FromInt(-length));
2092 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002093 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002094 }
2095
2096
2097 void EnsureCapacity(int elements) {
2098 array_builder_.EnsureCapacity(elements);
2099 }
2100
2101
2102 void AddSubjectSlice(int from, int to) {
2103 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002104 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002105 }
2106
2107
2108 void AddString(Handle<String> string) {
2109 int length = string->length();
2110 ASSERT(length > 0);
2111 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002112 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002113 is_ascii_ = false;
2114 }
2115 IncrementCharacterCount(length);
2116 }
2117
2118
2119 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002120 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002121 return Factory::empty_string();
2122 }
2123
2124 Handle<String> joined_string;
2125 if (is_ascii_) {
2126 joined_string = NewRawAsciiString(character_count_);
2127 AssertNoAllocation no_alloc;
2128 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2129 char* char_buffer = seq->GetChars();
2130 StringBuilderConcatHelper(*subject_,
2131 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002132 *array_builder_.array(),
2133 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002134 } else {
2135 // Non-ASCII.
2136 joined_string = NewRawTwoByteString(character_count_);
2137 AssertNoAllocation no_alloc;
2138 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2139 uc16* char_buffer = seq->GetChars();
2140 StringBuilderConcatHelper(*subject_,
2141 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002142 *array_builder_.array(),
2143 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002144 }
2145 return joined_string;
2146 }
2147
2148
2149 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002150 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002151 V8::FatalProcessOutOfMemory("String.replace result too large.");
2152 }
2153 character_count_ += by;
2154 }
2155
lrn@chromium.org25156de2010-04-06 13:10:27 +00002156 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002157 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002158 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002159
lrn@chromium.org25156de2010-04-06 13:10:27 +00002160 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002161 Handle<String> NewRawAsciiString(int size) {
2162 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2163 }
2164
2165
2166 Handle<String> NewRawTwoByteString(int size) {
2167 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2168 }
2169
2170
2171 void AddElement(Object* element) {
2172 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002173 ASSERT(array_builder_.capacity() > array_builder_.length());
2174 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002175 }
2176
lrn@chromium.org25156de2010-04-06 13:10:27 +00002177 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002178 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002179 int character_count_;
2180 bool is_ascii_;
2181};
2182
2183
2184class CompiledReplacement {
2185 public:
2186 CompiledReplacement()
2187 : parts_(1), replacement_substrings_(0) {}
2188
2189 void Compile(Handle<String> replacement,
2190 int capture_count,
2191 int subject_length);
2192
2193 void Apply(ReplacementStringBuilder* builder,
2194 int match_from,
2195 int match_to,
2196 Handle<JSArray> last_match_info);
2197
2198 // Number of distinct parts of the replacement pattern.
2199 int parts() {
2200 return parts_.length();
2201 }
2202 private:
2203 enum PartType {
2204 SUBJECT_PREFIX = 1,
2205 SUBJECT_SUFFIX,
2206 SUBJECT_CAPTURE,
2207 REPLACEMENT_SUBSTRING,
2208 REPLACEMENT_STRING,
2209
2210 NUMBER_OF_PART_TYPES
2211 };
2212
2213 struct ReplacementPart {
2214 static inline ReplacementPart SubjectMatch() {
2215 return ReplacementPart(SUBJECT_CAPTURE, 0);
2216 }
2217 static inline ReplacementPart SubjectCapture(int capture_index) {
2218 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2219 }
2220 static inline ReplacementPart SubjectPrefix() {
2221 return ReplacementPart(SUBJECT_PREFIX, 0);
2222 }
2223 static inline ReplacementPart SubjectSuffix(int subject_length) {
2224 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2225 }
2226 static inline ReplacementPart ReplacementString() {
2227 return ReplacementPart(REPLACEMENT_STRING, 0);
2228 }
2229 static inline ReplacementPart ReplacementSubString(int from, int to) {
2230 ASSERT(from >= 0);
2231 ASSERT(to > from);
2232 return ReplacementPart(-from, to);
2233 }
2234
2235 // If tag <= 0 then it is the negation of a start index of a substring of
2236 // the replacement pattern, otherwise it's a value from PartType.
2237 ReplacementPart(int tag, int data)
2238 : tag(tag), data(data) {
2239 // Must be non-positive or a PartType value.
2240 ASSERT(tag < NUMBER_OF_PART_TYPES);
2241 }
2242 // Either a value of PartType or a non-positive number that is
2243 // the negation of an index into the replacement string.
2244 int tag;
2245 // The data value's interpretation depends on the value of tag:
2246 // tag == SUBJECT_PREFIX ||
2247 // tag == SUBJECT_SUFFIX: data is unused.
2248 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2249 // tag == REPLACEMENT_SUBSTRING ||
2250 // tag == REPLACEMENT_STRING: data is index into array of substrings
2251 // of the replacement string.
2252 // tag <= 0: Temporary representation of the substring of the replacement
2253 // string ranging over -tag .. data.
2254 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2255 // substring objects.
2256 int data;
2257 };
2258
2259 template<typename Char>
2260 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2261 Vector<Char> characters,
2262 int capture_count,
2263 int subject_length) {
2264 int length = characters.length();
2265 int last = 0;
2266 for (int i = 0; i < length; i++) {
2267 Char c = characters[i];
2268 if (c == '$') {
2269 int next_index = i + 1;
2270 if (next_index == length) { // No next character!
2271 break;
2272 }
2273 Char c2 = characters[next_index];
2274 switch (c2) {
2275 case '$':
2276 if (i > last) {
2277 // There is a substring before. Include the first "$".
2278 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2279 last = next_index + 1; // Continue after the second "$".
2280 } else {
2281 // Let the next substring start with the second "$".
2282 last = next_index;
2283 }
2284 i = next_index;
2285 break;
2286 case '`':
2287 if (i > last) {
2288 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2289 }
2290 parts->Add(ReplacementPart::SubjectPrefix());
2291 i = next_index;
2292 last = i + 1;
2293 break;
2294 case '\'':
2295 if (i > last) {
2296 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2297 }
2298 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2299 i = next_index;
2300 last = i + 1;
2301 break;
2302 case '&':
2303 if (i > last) {
2304 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2305 }
2306 parts->Add(ReplacementPart::SubjectMatch());
2307 i = next_index;
2308 last = i + 1;
2309 break;
2310 case '0':
2311 case '1':
2312 case '2':
2313 case '3':
2314 case '4':
2315 case '5':
2316 case '6':
2317 case '7':
2318 case '8':
2319 case '9': {
2320 int capture_ref = c2 - '0';
2321 if (capture_ref > capture_count) {
2322 i = next_index;
2323 continue;
2324 }
2325 int second_digit_index = next_index + 1;
2326 if (second_digit_index < length) {
2327 // Peek ahead to see if we have two digits.
2328 Char c3 = characters[second_digit_index];
2329 if ('0' <= c3 && c3 <= '9') { // Double digits.
2330 int double_digit_ref = capture_ref * 10 + c3 - '0';
2331 if (double_digit_ref <= capture_count) {
2332 next_index = second_digit_index;
2333 capture_ref = double_digit_ref;
2334 }
2335 }
2336 }
2337 if (capture_ref > 0) {
2338 if (i > last) {
2339 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2340 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002341 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002342 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2343 last = next_index + 1;
2344 }
2345 i = next_index;
2346 break;
2347 }
2348 default:
2349 i = next_index;
2350 break;
2351 }
2352 }
2353 }
2354 if (length > last) {
2355 if (last == 0) {
2356 parts->Add(ReplacementPart::ReplacementString());
2357 } else {
2358 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2359 }
2360 }
2361 }
2362
2363 ZoneList<ReplacementPart> parts_;
2364 ZoneList<Handle<String> > replacement_substrings_;
2365};
2366
2367
2368void CompiledReplacement::Compile(Handle<String> replacement,
2369 int capture_count,
2370 int subject_length) {
2371 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002372 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002373 AssertNoAllocation no_alloc;
2374 ParseReplacementPattern(&parts_,
2375 replacement->ToAsciiVector(),
2376 capture_count,
2377 subject_length);
2378 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002379 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002380 AssertNoAllocation no_alloc;
2381
2382 ParseReplacementPattern(&parts_,
2383 replacement->ToUC16Vector(),
2384 capture_count,
2385 subject_length);
2386 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002387 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388 int substring_index = 0;
2389 for (int i = 0, n = parts_.length(); i < n; i++) {
2390 int tag = parts_[i].tag;
2391 if (tag <= 0) { // A replacement string slice.
2392 int from = -tag;
2393 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002394 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002395 parts_[i].tag = REPLACEMENT_SUBSTRING;
2396 parts_[i].data = substring_index;
2397 substring_index++;
2398 } else if (tag == REPLACEMENT_STRING) {
2399 replacement_substrings_.Add(replacement);
2400 parts_[i].data = substring_index;
2401 substring_index++;
2402 }
2403 }
2404}
2405
2406
2407void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2408 int match_from,
2409 int match_to,
2410 Handle<JSArray> last_match_info) {
2411 for (int i = 0, n = parts_.length(); i < n; i++) {
2412 ReplacementPart part = parts_[i];
2413 switch (part.tag) {
2414 case SUBJECT_PREFIX:
2415 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2416 break;
2417 case SUBJECT_SUFFIX: {
2418 int subject_length = part.data;
2419 if (match_to < subject_length) {
2420 builder->AddSubjectSlice(match_to, subject_length);
2421 }
2422 break;
2423 }
2424 case SUBJECT_CAPTURE: {
2425 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002426 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2428 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2429 if (from >= 0 && to > from) {
2430 builder->AddSubjectSlice(from, to);
2431 }
2432 break;
2433 }
2434 case REPLACEMENT_SUBSTRING:
2435 case REPLACEMENT_STRING:
2436 builder->AddString(replacement_substrings_[part.data]);
2437 break;
2438 default:
2439 UNREACHABLE();
2440 }
2441 }
2442}
2443
2444
2445
lrn@chromium.org303ada72010-10-27 09:33:13 +00002446MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2447 String* subject,
2448 JSRegExp* regexp,
2449 String* replacement,
2450 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002451 ASSERT(subject->IsFlat());
2452 ASSERT(replacement->IsFlat());
2453
2454 HandleScope handles;
2455
2456 int length = subject->length();
2457 Handle<String> subject_handle(subject);
2458 Handle<JSRegExp> regexp_handle(regexp);
2459 Handle<String> replacement_handle(replacement);
2460 Handle<JSArray> last_match_info_handle(last_match_info);
2461 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2462 subject_handle,
2463 0,
2464 last_match_info_handle);
2465 if (match.is_null()) {
2466 return Failure::Exception();
2467 }
2468 if (match->IsNull()) {
2469 return *subject_handle;
2470 }
2471
2472 int capture_count = regexp_handle->CaptureCount();
2473
2474 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002475 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002476 CompiledReplacement compiled_replacement;
2477 compiled_replacement.Compile(replacement_handle,
2478 capture_count,
2479 length);
2480
2481 bool is_global = regexp_handle->GetFlags().is_global();
2482
2483 // Guessing the number of parts that the final result string is built
2484 // from. Global regexps can match any number of times, so we guess
2485 // conservatively.
2486 int expected_parts =
2487 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2488 ReplacementStringBuilder builder(subject_handle, expected_parts);
2489
2490 // Index of end of last match.
2491 int prev = 0;
2492
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002493 // Number of parts added by compiled replacement plus preceeding
2494 // string and possibly suffix after last match. It is possible for
2495 // all components to use two elements when encoded as two smis.
2496 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 bool matched = true;
2498 do {
2499 ASSERT(last_match_info_handle->HasFastElements());
2500 // Increase the capacity of the builder before entering local handle-scope,
2501 // so its internal buffer can safely allocate a new handle if it grows.
2502 builder.EnsureCapacity(parts_added_per_loop);
2503
2504 HandleScope loop_scope;
2505 int start, end;
2506 {
2507 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002508 FixedArray* match_info_array =
2509 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002510
2511 ASSERT_EQ(capture_count * 2 + 2,
2512 RegExpImpl::GetLastCaptureCount(match_info_array));
2513 start = RegExpImpl::GetCapture(match_info_array, 0);
2514 end = RegExpImpl::GetCapture(match_info_array, 1);
2515 }
2516
2517 if (prev < start) {
2518 builder.AddSubjectSlice(prev, start);
2519 }
2520 compiled_replacement.Apply(&builder,
2521 start,
2522 end,
2523 last_match_info_handle);
2524 prev = end;
2525
2526 // Only continue checking for global regexps.
2527 if (!is_global) break;
2528
2529 // Continue from where the match ended, unless it was an empty match.
2530 int next = end;
2531 if (start == end) {
2532 next = end + 1;
2533 if (next > length) break;
2534 }
2535
2536 match = RegExpImpl::Exec(regexp_handle,
2537 subject_handle,
2538 next,
2539 last_match_info_handle);
2540 if (match.is_null()) {
2541 return Failure::Exception();
2542 }
2543 matched = !match->IsNull();
2544 } while (matched);
2545
2546 if (prev < length) {
2547 builder.AddSubjectSlice(prev, length);
2548 }
2549
2550 return *(builder.ToString());
2551}
2552
2553
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002554template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002555MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2556 String* subject,
2557 JSRegExp* regexp,
2558 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002559 ASSERT(subject->IsFlat());
2560
2561 HandleScope handles;
2562
2563 Handle<String> subject_handle(subject);
2564 Handle<JSRegExp> regexp_handle(regexp);
2565 Handle<JSArray> last_match_info_handle(last_match_info);
2566 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2567 subject_handle,
2568 0,
2569 last_match_info_handle);
2570 if (match.is_null()) return Failure::Exception();
2571 if (match->IsNull()) return *subject_handle;
2572
2573 ASSERT(last_match_info_handle->HasFastElements());
2574
2575 HandleScope loop_scope;
2576 int start, end;
2577 {
2578 AssertNoAllocation match_info_array_is_not_in_a_handle;
2579 FixedArray* match_info_array =
2580 FixedArray::cast(last_match_info_handle->elements());
2581
2582 start = RegExpImpl::GetCapture(match_info_array, 0);
2583 end = RegExpImpl::GetCapture(match_info_array, 1);
2584 }
2585
2586 int length = subject->length();
2587 int new_length = length - (end - start);
2588 if (new_length == 0) {
2589 return Heap::empty_string();
2590 }
2591 Handle<ResultSeqString> answer;
2592 if (ResultSeqString::kHasAsciiEncoding) {
2593 answer =
2594 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2595 } else {
2596 answer =
2597 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2598 }
2599
2600 // If the regexp isn't global, only match once.
2601 if (!regexp_handle->GetFlags().is_global()) {
2602 if (start > 0) {
2603 String::WriteToFlat(*subject_handle,
2604 answer->GetChars(),
2605 0,
2606 start);
2607 }
2608 if (end < length) {
2609 String::WriteToFlat(*subject_handle,
2610 answer->GetChars() + start,
2611 end,
2612 length);
2613 }
2614 return *answer;
2615 }
2616
2617 int prev = 0; // Index of end of last match.
2618 int next = 0; // Start of next search (prev unless last match was empty).
2619 int position = 0;
2620
2621 do {
2622 if (prev < start) {
2623 // Add substring subject[prev;start] to answer string.
2624 String::WriteToFlat(*subject_handle,
2625 answer->GetChars() + position,
2626 prev,
2627 start);
2628 position += start - prev;
2629 }
2630 prev = end;
2631 next = end;
2632 // Continue from where the match ended, unless it was an empty match.
2633 if (start == end) {
2634 next++;
2635 if (next > length) break;
2636 }
2637 match = RegExpImpl::Exec(regexp_handle,
2638 subject_handle,
2639 next,
2640 last_match_info_handle);
2641 if (match.is_null()) return Failure::Exception();
2642 if (match->IsNull()) break;
2643
2644 ASSERT(last_match_info_handle->HasFastElements());
2645 HandleScope loop_scope;
2646 {
2647 AssertNoAllocation match_info_array_is_not_in_a_handle;
2648 FixedArray* match_info_array =
2649 FixedArray::cast(last_match_info_handle->elements());
2650 start = RegExpImpl::GetCapture(match_info_array, 0);
2651 end = RegExpImpl::GetCapture(match_info_array, 1);
2652 }
2653 } while (true);
2654
2655 if (prev < length) {
2656 // Add substring subject[prev;length] to answer string.
2657 String::WriteToFlat(*subject_handle,
2658 answer->GetChars() + position,
2659 prev,
2660 length);
2661 position += length - prev;
2662 }
2663
2664 if (position == 0) {
2665 return Heap::empty_string();
2666 }
2667
2668 // Shorten string and fill
2669 int string_size = ResultSeqString::SizeFor(position);
2670 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2671 int delta = allocated_string_size - string_size;
2672
2673 answer->set_length(position);
2674 if (delta == 0) return *answer;
2675
2676 Address end_of_string = answer->address() + string_size;
2677 Heap::CreateFillerObjectAt(end_of_string, delta);
2678
2679 return *answer;
2680}
2681
2682
lrn@chromium.org303ada72010-10-27 09:33:13 +00002683static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002684 ASSERT(args.length() == 4);
2685
2686 CONVERT_CHECKED(String, subject, args[0]);
2687 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002688 Object* flat_subject;
2689 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2690 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2691 return maybe_flat_subject;
2692 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002693 }
2694 subject = String::cast(flat_subject);
2695 }
2696
2697 CONVERT_CHECKED(String, replacement, args[2]);
2698 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002699 Object* flat_replacement;
2700 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2701 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2702 return maybe_flat_replacement;
2703 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704 }
2705 replacement = String::cast(flat_replacement);
2706 }
2707
2708 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2709 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2710
2711 ASSERT(last_match_info->HasFastElements());
2712
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002713 if (replacement->length() == 0) {
2714 if (subject->HasOnlyAsciiChars()) {
2715 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2716 subject, regexp, last_match_info);
2717 } else {
2718 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2719 subject, regexp, last_match_info);
2720 }
2721 }
2722
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002723 return StringReplaceRegExpWithString(subject,
2724 regexp,
2725 replacement,
2726 last_match_info);
2727}
2728
2729
ager@chromium.org7c537e22008-10-16 08:43:32 +00002730// Perform string match of pattern on subject, starting at start index.
2731// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002732// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002733int Runtime::StringMatch(Handle<String> sub,
2734 Handle<String> pat,
2735 int start_index) {
2736 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002737 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002738
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002739 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002740 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002741
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002742 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002743 if (start_index + pattern_length > subject_length) return -1;
2744
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002745 if (!sub->IsFlat()) FlattenString(sub);
2746 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002747
ager@chromium.org7c537e22008-10-16 08:43:32 +00002748 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002749 // Extract flattened substrings of cons strings before determining asciiness.
2750 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002751 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002752 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002753 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002754
ager@chromium.org7c537e22008-10-16 08:43:32 +00002755 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002756 if (seq_pat->IsAsciiRepresentation()) {
2757 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2758 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002759 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002760 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002761 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002762 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002763 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2764 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002765 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002766 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002767 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002768}
2769
2770
lrn@chromium.org303ada72010-10-27 09:33:13 +00002771static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002772 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002773 ASSERT(args.length() == 3);
2774
ager@chromium.org7c537e22008-10-16 08:43:32 +00002775 CONVERT_ARG_CHECKED(String, sub, 0);
2776 CONVERT_ARG_CHECKED(String, pat, 1);
2777
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002778 Object* index = args[2];
2779 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002780 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002781
ager@chromium.org870a0b62008-11-04 11:43:05 +00002782 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002783 int position = Runtime::StringMatch(sub, pat, start_index);
2784 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002785}
2786
2787
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002788template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002789static int StringMatchBackwards(Vector<const schar> subject,
2790 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002791 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002792 int pattern_length = pattern.length();
2793 ASSERT(pattern_length >= 1);
2794 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002795
2796 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002797 for (int i = 0; i < pattern_length; i++) {
2798 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002799 if (c > String::kMaxAsciiCharCode) {
2800 return -1;
2801 }
2802 }
2803 }
2804
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002805 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002806 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002807 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002808 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002809 while (j < pattern_length) {
2810 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002811 break;
2812 }
2813 j++;
2814 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002815 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002816 return i;
2817 }
2818 }
2819 return -1;
2820}
2821
lrn@chromium.org303ada72010-10-27 09:33:13 +00002822static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002823 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002824 ASSERT(args.length() == 3);
2825
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002826 CONVERT_ARG_CHECKED(String, sub, 0);
2827 CONVERT_ARG_CHECKED(String, pat, 1);
2828
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002829 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002830 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002831 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002832
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002833 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002834 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002835
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002836 if (start_index + pat_length > sub_length) {
2837 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002838 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002839
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002840 if (pat_length == 0) {
2841 return Smi::FromInt(start_index);
2842 }
2843
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002844 if (!sub->IsFlat()) FlattenString(sub);
2845 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002846
2847 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2848
2849 int position = -1;
2850
2851 if (pat->IsAsciiRepresentation()) {
2852 Vector<const char> pat_vector = pat->ToAsciiVector();
2853 if (sub->IsAsciiRepresentation()) {
2854 position = StringMatchBackwards(sub->ToAsciiVector(),
2855 pat_vector,
2856 start_index);
2857 } else {
2858 position = StringMatchBackwards(sub->ToUC16Vector(),
2859 pat_vector,
2860 start_index);
2861 }
2862 } else {
2863 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2864 if (sub->IsAsciiRepresentation()) {
2865 position = StringMatchBackwards(sub->ToAsciiVector(),
2866 pat_vector,
2867 start_index);
2868 } else {
2869 position = StringMatchBackwards(sub->ToUC16Vector(),
2870 pat_vector,
2871 start_index);
2872 }
2873 }
2874
2875 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002876}
2877
2878
lrn@chromium.org303ada72010-10-27 09:33:13 +00002879static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002880 NoHandleAllocation ha;
2881 ASSERT(args.length() == 2);
2882
2883 CONVERT_CHECKED(String, str1, args[0]);
2884 CONVERT_CHECKED(String, str2, args[1]);
2885
2886 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002887 int str1_length = str1->length();
2888 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002889
2890 // Decide trivial cases without flattening.
2891 if (str1_length == 0) {
2892 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2893 return Smi::FromInt(-str2_length);
2894 } else {
2895 if (str2_length == 0) return Smi::FromInt(str1_length);
2896 }
2897
2898 int end = str1_length < str2_length ? str1_length : str2_length;
2899
2900 // No need to flatten if we are going to find the answer on the first
2901 // character. At this point we know there is at least one character
2902 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002903 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002904 if (d != 0) return Smi::FromInt(d);
2905
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002906 str1->TryFlatten();
2907 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002908
2909 static StringInputBuffer buf1;
2910 static StringInputBuffer buf2;
2911
2912 buf1.Reset(str1);
2913 buf2.Reset(str2);
2914
2915 for (int i = 0; i < end; i++) {
2916 uint16_t char1 = buf1.GetNext();
2917 uint16_t char2 = buf2.GetNext();
2918 if (char1 != char2) return Smi::FromInt(char1 - char2);
2919 }
2920
2921 return Smi::FromInt(str1_length - str2_length);
2922}
2923
2924
lrn@chromium.org303ada72010-10-27 09:33:13 +00002925static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002926 NoHandleAllocation ha;
2927 ASSERT(args.length() == 3);
2928
2929 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002930 Object* from = args[1];
2931 Object* to = args[2];
2932 int start, end;
2933 // We have a fast integer-only case here to avoid a conversion to double in
2934 // the common case where from and to are Smis.
2935 if (from->IsSmi() && to->IsSmi()) {
2936 start = Smi::cast(from)->value();
2937 end = Smi::cast(to)->value();
2938 } else {
2939 CONVERT_DOUBLE_CHECKED(from_number, from);
2940 CONVERT_DOUBLE_CHECKED(to_number, to);
2941 start = FastD2I(from_number);
2942 end = FastD2I(to_number);
2943 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002944 RUNTIME_ASSERT(end >= start);
2945 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002946 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002947 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002948 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002949}
2950
2951
lrn@chromium.org303ada72010-10-27 09:33:13 +00002952static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002953 ASSERT_EQ(3, args.length());
2954
2955 CONVERT_ARG_CHECKED(String, subject, 0);
2956 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2957 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2958 HandleScope handles;
2959
2960 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2961
2962 if (match.is_null()) {
2963 return Failure::Exception();
2964 }
2965 if (match->IsNull()) {
2966 return Heap::null_value();
2967 }
2968 int length = subject->length();
2969
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002970 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002971 ZoneList<int> offsets(8);
2972 do {
2973 int start;
2974 int end;
2975 {
2976 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002977 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002978 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2979 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2980 }
2981 offsets.Add(start);
2982 offsets.Add(end);
2983 int index = start < end ? end : end + 1;
2984 if (index > length) break;
2985 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2986 if (match.is_null()) {
2987 return Failure::Exception();
2988 }
2989 } while (!match->IsNull());
2990 int matches = offsets.length() / 2;
2991 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2992 for (int i = 0; i < matches ; i++) {
2993 int from = offsets.at(i * 2);
2994 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002995 Handle<String> match = Factory::NewSubString(subject, from, to);
2996 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002997 }
2998 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2999 result->set_length(Smi::FromInt(matches));
3000 return *result;
3001}
3002
3003
lrn@chromium.org25156de2010-04-06 13:10:27 +00003004// Two smis before and after the match, for very long strings.
3005const int kMaxBuilderEntriesPerRegExpMatch = 5;
3006
3007
3008static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3009 Handle<JSArray> last_match_info,
3010 int match_start,
3011 int match_end) {
3012 // Fill last_match_info with a single capture.
3013 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3014 AssertNoAllocation no_gc;
3015 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3016 RegExpImpl::SetLastCaptureCount(elements, 2);
3017 RegExpImpl::SetLastInput(elements, *subject);
3018 RegExpImpl::SetLastSubject(elements, *subject);
3019 RegExpImpl::SetCapture(elements, 0, match_start);
3020 RegExpImpl::SetCapture(elements, 1, match_end);
3021}
3022
3023
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003024template <typename SubjectChar, typename PatternChar>
3025static bool SearchStringMultiple(Vector<const SubjectChar> subject,
3026 Vector<const PatternChar> pattern,
3027 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003028 FixedArrayBuilder* builder,
3029 int* match_pos) {
3030 int pos = *match_pos;
3031 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003032 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003033 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003034 StringSearch<PatternChar, SubjectChar> search(pattern);
3035 while (pos <= max_search_start) {
3036 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3037 *match_pos = pos;
3038 return false;
3039 }
3040 // Position of end of previous match.
3041 int match_end = pos + pattern_length;
3042 int new_pos = search.Search(subject, match_end);
3043 if (new_pos >= 0) {
3044 // A match.
3045 if (new_pos > match_end) {
3046 ReplacementStringBuilder::AddSubjectSlice(builder,
3047 match_end,
3048 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003049 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003050 pos = new_pos;
3051 builder->Add(pattern_string);
3052 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003053 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003054 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003055 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003056
lrn@chromium.org25156de2010-04-06 13:10:27 +00003057 if (pos < max_search_start) {
3058 ReplacementStringBuilder::AddSubjectSlice(builder,
3059 pos + pattern_length,
3060 subject_length);
3061 }
3062 *match_pos = pos;
3063 return true;
3064}
3065
3066
3067static bool SearchStringMultiple(Handle<String> subject,
3068 Handle<String> pattern,
3069 Handle<JSArray> last_match_info,
3070 FixedArrayBuilder* builder) {
3071 ASSERT(subject->IsFlat());
3072 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003073
3074 // Treating as if a previous match was before first character.
3075 int match_pos = -pattern->length();
3076
3077 for (;;) { // Break when search complete.
3078 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3079 AssertNoAllocation no_gc;
3080 if (subject->IsAsciiRepresentation()) {
3081 Vector<const char> subject_vector = subject->ToAsciiVector();
3082 if (pattern->IsAsciiRepresentation()) {
3083 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003084 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003085 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003086 builder,
3087 &match_pos)) break;
3088 } else {
3089 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003090 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003091 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003092 builder,
3093 &match_pos)) break;
3094 }
3095 } else {
3096 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3097 if (pattern->IsAsciiRepresentation()) {
3098 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003099 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003100 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003101 builder,
3102 &match_pos)) break;
3103 } else {
3104 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003105 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003106 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003107 builder,
3108 &match_pos)) break;
3109 }
3110 }
3111 }
3112
3113 if (match_pos >= 0) {
3114 SetLastMatchInfoNoCaptures(subject,
3115 last_match_info,
3116 match_pos,
3117 match_pos + pattern->length());
3118 return true;
3119 }
3120 return false; // No matches at all.
3121}
3122
3123
3124static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3125 Handle<String> subject,
3126 Handle<JSRegExp> regexp,
3127 Handle<JSArray> last_match_array,
3128 FixedArrayBuilder* builder) {
3129 ASSERT(subject->IsFlat());
3130 int match_start = -1;
3131 int match_end = 0;
3132 int pos = 0;
3133 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3134 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3135
3136 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003137 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003138 int subject_length = subject->length();
3139
3140 for (;;) { // Break on failure, return on exception.
3141 RegExpImpl::IrregexpResult result =
3142 RegExpImpl::IrregexpExecOnce(regexp,
3143 subject,
3144 pos,
3145 register_vector);
3146 if (result == RegExpImpl::RE_SUCCESS) {
3147 match_start = register_vector[0];
3148 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3149 if (match_end < match_start) {
3150 ReplacementStringBuilder::AddSubjectSlice(builder,
3151 match_end,
3152 match_start);
3153 }
3154 match_end = register_vector[1];
3155 HandleScope loop_scope;
3156 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3157 if (match_start != match_end) {
3158 pos = match_end;
3159 } else {
3160 pos = match_end + 1;
3161 if (pos > subject_length) break;
3162 }
3163 } else if (result == RegExpImpl::RE_FAILURE) {
3164 break;
3165 } else {
3166 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3167 return result;
3168 }
3169 }
3170
3171 if (match_start >= 0) {
3172 if (match_end < subject_length) {
3173 ReplacementStringBuilder::AddSubjectSlice(builder,
3174 match_end,
3175 subject_length);
3176 }
3177 SetLastMatchInfoNoCaptures(subject,
3178 last_match_array,
3179 match_start,
3180 match_end);
3181 return RegExpImpl::RE_SUCCESS;
3182 } else {
3183 return RegExpImpl::RE_FAILURE; // No matches at all.
3184 }
3185}
3186
3187
3188static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3189 Handle<String> subject,
3190 Handle<JSRegExp> regexp,
3191 Handle<JSArray> last_match_array,
3192 FixedArrayBuilder* builder) {
3193
3194 ASSERT(subject->IsFlat());
3195 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3196 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3197
3198 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003199 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003200
3201 RegExpImpl::IrregexpResult result =
3202 RegExpImpl::IrregexpExecOnce(regexp,
3203 subject,
3204 0,
3205 register_vector);
3206
3207 int capture_count = regexp->CaptureCount();
3208 int subject_length = subject->length();
3209
3210 // Position to search from.
3211 int pos = 0;
3212 // End of previous match. Differs from pos if match was empty.
3213 int match_end = 0;
3214 if (result == RegExpImpl::RE_SUCCESS) {
3215 // Need to keep a copy of the previous match for creating last_match_info
3216 // at the end, so we have two vectors that we swap between.
3217 OffsetsVector registers2(required_registers);
3218 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3219
3220 do {
3221 int match_start = register_vector[0];
3222 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3223 if (match_end < match_start) {
3224 ReplacementStringBuilder::AddSubjectSlice(builder,
3225 match_end,
3226 match_start);
3227 }
3228 match_end = register_vector[1];
3229
3230 {
3231 // Avoid accumulating new handles inside loop.
3232 HandleScope temp_scope;
3233 // Arguments array to replace function is match, captures, index and
3234 // subject, i.e., 3 + capture count in total.
3235 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003236 Handle<String> match = Factory::NewSubString(subject,
3237 match_start,
3238 match_end);
3239 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003240 for (int i = 1; i <= capture_count; i++) {
3241 int start = register_vector[i * 2];
3242 if (start >= 0) {
3243 int end = register_vector[i * 2 + 1];
3244 ASSERT(start <= end);
3245 Handle<String> substring = Factory::NewSubString(subject,
3246 start,
3247 end);
3248 elements->set(i, *substring);
3249 } else {
3250 ASSERT(register_vector[i * 2 + 1] < 0);
3251 elements->set(i, Heap::undefined_value());
3252 }
3253 }
3254 elements->set(capture_count + 1, Smi::FromInt(match_start));
3255 elements->set(capture_count + 2, *subject);
3256 builder->Add(*Factory::NewJSArrayWithElements(elements));
3257 }
3258 // Swap register vectors, so the last successful match is in
3259 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003260 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003261 prev_register_vector = register_vector;
3262 register_vector = tmp;
3263
3264 if (match_end > match_start) {
3265 pos = match_end;
3266 } else {
3267 pos = match_end + 1;
3268 if (pos > subject_length) {
3269 break;
3270 }
3271 }
3272
3273 result = RegExpImpl::IrregexpExecOnce(regexp,
3274 subject,
3275 pos,
3276 register_vector);
3277 } while (result == RegExpImpl::RE_SUCCESS);
3278
3279 if (result != RegExpImpl::RE_EXCEPTION) {
3280 // Finished matching, with at least one match.
3281 if (match_end < subject_length) {
3282 ReplacementStringBuilder::AddSubjectSlice(builder,
3283 match_end,
3284 subject_length);
3285 }
3286
3287 int last_match_capture_count = (capture_count + 1) * 2;
3288 int last_match_array_size =
3289 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3290 last_match_array->EnsureSize(last_match_array_size);
3291 AssertNoAllocation no_gc;
3292 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3293 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3294 RegExpImpl::SetLastSubject(elements, *subject);
3295 RegExpImpl::SetLastInput(elements, *subject);
3296 for (int i = 0; i < last_match_capture_count; i++) {
3297 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3298 }
3299 return RegExpImpl::RE_SUCCESS;
3300 }
3301 }
3302 // No matches at all, return failure or exception result directly.
3303 return result;
3304}
3305
3306
lrn@chromium.org303ada72010-10-27 09:33:13 +00003307static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003308 ASSERT(args.length() == 4);
3309 HandleScope handles;
3310
3311 CONVERT_ARG_CHECKED(String, subject, 1);
3312 if (!subject->IsFlat()) { FlattenString(subject); }
3313 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3314 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3315 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3316
3317 ASSERT(last_match_info->HasFastElements());
3318 ASSERT(regexp->GetFlags().is_global());
3319 Handle<FixedArray> result_elements;
3320 if (result_array->HasFastElements()) {
3321 result_elements =
3322 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3323 } else {
3324 result_elements = Factory::NewFixedArrayWithHoles(16);
3325 }
3326 FixedArrayBuilder builder(result_elements);
3327
3328 if (regexp->TypeTag() == JSRegExp::ATOM) {
3329 Handle<String> pattern(
3330 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003331 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003332 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3333 return *builder.ToJSArray(result_array);
3334 }
3335 return Heap::null_value();
3336 }
3337
3338 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3339
3340 RegExpImpl::IrregexpResult result;
3341 if (regexp->CaptureCount() == 0) {
3342 result = SearchRegExpNoCaptureMultiple(subject,
3343 regexp,
3344 last_match_info,
3345 &builder);
3346 } else {
3347 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3348 }
3349 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3350 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3351 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3352 return Failure::Exception();
3353}
3354
3355
lrn@chromium.org303ada72010-10-27 09:33:13 +00003356static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003357 NoHandleAllocation ha;
3358 ASSERT(args.length() == 2);
3359
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003360 // Fast case where the result is a one character string.
3361 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3362 int value = Smi::cast(args[0])->value();
3363 int radix = Smi::cast(args[1])->value();
3364 if (value >= 0 && value < radix) {
3365 RUNTIME_ASSERT(radix <= 36);
3366 // Character array used for conversion.
3367 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3368 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3369 }
3370 }
3371
3372 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003373 CONVERT_DOUBLE_CHECKED(value, args[0]);
3374 if (isnan(value)) {
3375 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3376 }
3377 if (isinf(value)) {
3378 if (value < 0) {
3379 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3380 }
3381 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3382 }
3383 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3384 int radix = FastD2I(radix_number);
3385 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3386 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003387 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003388 DeleteArray(str);
3389 return result;
3390}
3391
3392
lrn@chromium.org303ada72010-10-27 09:33:13 +00003393static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003394 NoHandleAllocation ha;
3395 ASSERT(args.length() == 2);
3396
3397 CONVERT_DOUBLE_CHECKED(value, args[0]);
3398 if (isnan(value)) {
3399 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3400 }
3401 if (isinf(value)) {
3402 if (value < 0) {
3403 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3404 }
3405 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3406 }
3407 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3408 int f = FastD2I(f_number);
3409 RUNTIME_ASSERT(f >= 0);
3410 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003411 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003412 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003413 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003414}
3415
3416
lrn@chromium.org303ada72010-10-27 09:33:13 +00003417static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003418 NoHandleAllocation ha;
3419 ASSERT(args.length() == 2);
3420
3421 CONVERT_DOUBLE_CHECKED(value, args[0]);
3422 if (isnan(value)) {
3423 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3424 }
3425 if (isinf(value)) {
3426 if (value < 0) {
3427 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3428 }
3429 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3430 }
3431 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3432 int f = FastD2I(f_number);
3433 RUNTIME_ASSERT(f >= -1 && f <= 20);
3434 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003435 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003436 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003437 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003438}
3439
3440
lrn@chromium.org303ada72010-10-27 09:33:13 +00003441static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003442 NoHandleAllocation ha;
3443 ASSERT(args.length() == 2);
3444
3445 CONVERT_DOUBLE_CHECKED(value, args[0]);
3446 if (isnan(value)) {
3447 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3448 }
3449 if (isinf(value)) {
3450 if (value < 0) {
3451 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3452 }
3453 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3454 }
3455 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3456 int f = FastD2I(f_number);
3457 RUNTIME_ASSERT(f >= 1 && f <= 21);
3458 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003459 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003461 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003462}
3463
3464
3465// Returns a single character string where first character equals
3466// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003467static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003468 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003469 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003470 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003471 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003473 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003474}
3475
3476
lrn@chromium.org303ada72010-10-27 09:33:13 +00003477MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3478 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003479 // Handle [] indexing on Strings
3480 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003481 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3482 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003483 }
3484
3485 // Handle [] indexing on String objects
3486 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003487 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3488 Handle<Object> result =
3489 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3490 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003491 }
3492
3493 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003494 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003495 return prototype->GetElement(index);
3496 }
3497
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003498 return GetElement(object, index);
3499}
3500
3501
lrn@chromium.org303ada72010-10-27 09:33:13 +00003502MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003503 return object->GetElement(index);
3504}
3505
3506
lrn@chromium.org303ada72010-10-27 09:33:13 +00003507MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3508 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003509 HandleScope scope;
3510
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003511 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003512 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513 Handle<Object> error =
3514 Factory::NewTypeError("non_object_property_load",
3515 HandleVector(args, 2));
3516 return Top::Throw(*error);
3517 }
3518
3519 // Check if the given key is an array index.
3520 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003521 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522 return GetElementOrCharAt(object, index);
3523 }
3524
3525 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003526 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003527 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003528 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003529 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003530 bool has_pending_exception = false;
3531 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003532 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003533 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003534 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003535 }
3536
ager@chromium.org32912102009-01-16 10:38:43 +00003537 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003538 // the element if so.
3539 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003540 return GetElementOrCharAt(object, index);
3541 } else {
3542 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003543 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003544 }
3545}
3546
3547
lrn@chromium.org303ada72010-10-27 09:33:13 +00003548static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003549 NoHandleAllocation ha;
3550 ASSERT(args.length() == 2);
3551
3552 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003553 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554
3555 return Runtime::GetObjectProperty(object, key);
3556}
3557
3558
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003559// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003560static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003561 NoHandleAllocation ha;
3562 ASSERT(args.length() == 2);
3563
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003564 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003565 // itself.
3566 //
3567 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003568 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003569 // global proxy object never has properties. This is the case
3570 // because the global proxy object forwards everything to its hidden
3571 // prototype including local lookups.
3572 //
3573 // Additionally, we need to make sure that we do not cache results
3574 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003575 if (args[0]->IsJSObject() &&
3576 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003577 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003578 args[1]->IsString()) {
3579 JSObject* receiver = JSObject::cast(args[0]);
3580 String* key = String::cast(args[1]);
3581 if (receiver->HasFastProperties()) {
3582 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003583 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003584 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3585 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003586 Object* value = receiver->FastPropertyAt(offset);
3587 return value->IsTheHole() ? Heap::undefined_value() : value;
3588 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003589 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003590 LookupResult result;
3591 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003592 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003593 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003594 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003595 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003596 }
3597 } else {
3598 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003599 StringDictionary* dictionary = receiver->property_dictionary();
3600 int entry = dictionary->FindEntry(key);
3601 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003602 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003603 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003604 if (!receiver->IsGlobalObject()) return value;
3605 value = JSGlobalPropertyCell::cast(value)->value();
3606 if (!value->IsTheHole()) return value;
3607 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003608 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003609 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003610 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3611 // Fast case for string indexing using [] with a smi index.
3612 HandleScope scope;
3613 Handle<String> str = args.at<String>(0);
3614 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003615 if (index >= 0 && index < str->length()) {
3616 Handle<Object> result = GetCharAt(str, index);
3617 return *result;
3618 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003619 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003620
3621 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003622 return Runtime::GetObjectProperty(args.at<Object>(0),
3623 args.at<Object>(1));
3624}
3625
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003626// Implements part of 8.12.9 DefineOwnProperty.
3627// There are 3 cases that lead here:
3628// Step 4b - define a new accessor property.
3629// Steps 9c & 12 - replace an existing data property with an accessor property.
3630// Step 12 - update an existing accessor property with an accessor or generic
3631// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003632static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003633 ASSERT(args.length() == 5);
3634 HandleScope scope;
3635 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3636 CONVERT_CHECKED(String, name, args[1]);
3637 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003638 Object* fun = args[3];
3639 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003640 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3641 int unchecked = flag_attr->value();
3642 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3643 RUNTIME_ASSERT(!obj->IsNull());
3644 LookupResult result;
3645 obj->LocalLookupRealNamedProperty(name, &result);
3646
3647 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3648 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3649 // delete it to avoid running into trouble in DefineAccessor, which
3650 // handles this incorrectly if the property is readonly (does nothing)
3651 if (result.IsProperty() &&
3652 (result.type() == FIELD || result.type() == NORMAL
3653 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003654 Object* ok;
3655 { MaybeObject* maybe_ok =
3656 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3657 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3658 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003659 }
3660 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3661}
3662
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003663// Implements part of 8.12.9 DefineOwnProperty.
3664// There are 3 cases that lead here:
3665// Step 4a - define a new data property.
3666// Steps 9b & 12 - replace an existing accessor property with a data property.
3667// Step 12 - update an existing data property with a data or generic
3668// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003669static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003670 ASSERT(args.length() == 4);
3671 HandleScope scope;
3672 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3673 CONVERT_ARG_CHECKED(String, name, 1);
3674 Handle<Object> obj_value = args.at<Object>(2);
3675
3676 CONVERT_CHECKED(Smi, flag, args[3]);
3677 int unchecked = flag->value();
3678 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3679
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003680 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3681
3682 // Check if this is an element.
3683 uint32_t index;
3684 bool is_element = name->AsArrayIndex(&index);
3685
3686 // Special case for elements if any of the flags are true.
3687 // If elements are in fast case we always implicitly assume that:
3688 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3689 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3690 is_element) {
3691 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003692 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003693 // We do not need to do access checks here since these has already
3694 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003695 Handle<Object> proto(js_object->GetPrototype());
3696 // If proxy is detached, ignore the assignment. Alternatively,
3697 // we could throw an exception.
3698 if (proto->IsNull()) return *obj_value;
3699 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003700 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003701 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003702 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003703 // Make sure that we never go back to fast case.
3704 dictionary->set_requires_slow_elements();
3705 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003706 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003707 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003708 }
3709
ager@chromium.org5c838252010-02-19 08:53:10 +00003710 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003711 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003712
ager@chromium.org5c838252010-02-19 08:53:10 +00003713 // Take special care when attributes are different and there is already
3714 // a property. For simplicity we normalize the property which enables us
3715 // to not worry about changing the instance_descriptor and creating a new
3716 // map. The current version of SetObjectProperty does not handle attributes
3717 // correctly in the case where a property is a field and is reset with
3718 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003719 if (result.IsProperty() &&
3720 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003721 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003722 if (js_object->IsJSGlobalProxy()) {
3723 // Since the result is a property, the prototype will exist so
3724 // we don't have to check for null.
3725 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003726 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003727 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003728 // Use IgnoreAttributes version since a readonly property may be
3729 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003730 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3731 *obj_value,
3732 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003733 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003734
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003735 return Runtime::ForceSetObjectProperty(js_object, name, obj_value, attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003736}
3737
3738
lrn@chromium.org303ada72010-10-27 09:33:13 +00003739MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3740 Handle<Object> key,
3741 Handle<Object> value,
3742 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003743 HandleScope scope;
3744
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003745 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003746 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003747 Handle<Object> error =
3748 Factory::NewTypeError("non_object_property_store",
3749 HandleVector(args, 2));
3750 return Top::Throw(*error);
3751 }
3752
3753 // If the object isn't a JavaScript object, we ignore the store.
3754 if (!object->IsJSObject()) return *value;
3755
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003756 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3757
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003758 // Check if the given key is an array index.
3759 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003760 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003761 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3762 // of a string using [] notation. We need to support this too in
3763 // JavaScript.
3764 // In the case of a String object we just need to redirect the assignment to
3765 // the underlying string if the index is in range. Since the underlying
3766 // string does nothing with the assignment then we can ignore such
3767 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003768 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003769 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003770 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003772 Handle<Object> result = SetElement(js_object, index, value);
3773 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774 return *value;
3775 }
3776
3777 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003778 Handle<Object> result;
3779 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003780 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003782 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003783 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003784 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003785 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003786 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003787 return *value;
3788 }
3789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003790 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003791 bool has_pending_exception = false;
3792 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3793 if (has_pending_exception) return Failure::Exception();
3794 Handle<String> name = Handle<String>::cast(converted);
3795
3796 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003797 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003799 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003800 }
3801}
3802
3803
lrn@chromium.org303ada72010-10-27 09:33:13 +00003804MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3805 Handle<Object> key,
3806 Handle<Object> value,
3807 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003808 HandleScope scope;
3809
3810 // Check if the given key is an array index.
3811 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003812 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003813 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3814 // of a string using [] notation. We need to support this too in
3815 // JavaScript.
3816 // In the case of a String object we just need to redirect the assignment to
3817 // the underlying string if the index is in range. Since the underlying
3818 // string does nothing with the assignment then we can ignore such
3819 // assignments.
3820 if (js_object->IsStringObjectWithCharacterAt(index)) {
3821 return *value;
3822 }
3823
3824 return js_object->SetElement(index, *value);
3825 }
3826
3827 if (key->IsString()) {
3828 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003829 return js_object->SetElement(index, *value);
3830 } else {
3831 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003832 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003833 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3834 *value,
3835 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003836 }
3837 }
3838
3839 // Call-back into JavaScript to convert the key to a string.
3840 bool has_pending_exception = false;
3841 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3842 if (has_pending_exception) return Failure::Exception();
3843 Handle<String> name = Handle<String>::cast(converted);
3844
3845 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003846 return js_object->SetElement(index, *value);
3847 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003848 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003849 }
3850}
3851
3852
lrn@chromium.org303ada72010-10-27 09:33:13 +00003853MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3854 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003855 HandleScope scope;
3856
3857 // Check if the given key is an array index.
3858 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003859 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003860 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3861 // characters of a string using [] notation. In the case of a
3862 // String object we just need to redirect the deletion to the
3863 // underlying string if the index is in range. Since the
3864 // underlying string does nothing with the deletion, we can ignore
3865 // such deletions.
3866 if (js_object->IsStringObjectWithCharacterAt(index)) {
3867 return Heap::true_value();
3868 }
3869
3870 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3871 }
3872
3873 Handle<String> key_string;
3874 if (key->IsString()) {
3875 key_string = Handle<String>::cast(key);
3876 } else {
3877 // Call-back into JavaScript to convert the key to a string.
3878 bool has_pending_exception = false;
3879 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3880 if (has_pending_exception) return Failure::Exception();
3881 key_string = Handle<String>::cast(converted);
3882 }
3883
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003884 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003885 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3886}
3887
3888
lrn@chromium.org303ada72010-10-27 09:33:13 +00003889static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003890 NoHandleAllocation ha;
3891 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3892
3893 Handle<Object> object = args.at<Object>(0);
3894 Handle<Object> key = args.at<Object>(1);
3895 Handle<Object> value = args.at<Object>(2);
3896
3897 // Compute attributes.
3898 PropertyAttributes attributes = NONE;
3899 if (args.length() == 4) {
3900 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003901 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003902 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003903 RUNTIME_ASSERT(
3904 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3905 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003906 }
3907 return Runtime::SetObjectProperty(object, key, value, attributes);
3908}
3909
3910
3911// Set a local property, even if it is READ_ONLY. If the property does not
3912// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003913static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003914 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003915 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916 CONVERT_CHECKED(JSObject, object, args[0]);
3917 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003918 // Compute attributes.
3919 PropertyAttributes attributes = NONE;
3920 if (args.length() == 4) {
3921 CONVERT_CHECKED(Smi, value_obj, args[3]);
3922 int unchecked_value = value_obj->value();
3923 // Only attribute bits should be set.
3924 RUNTIME_ASSERT(
3925 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3926 attributes = static_cast<PropertyAttributes>(unchecked_value);
3927 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003929 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003930 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003931}
3932
3933
lrn@chromium.org303ada72010-10-27 09:33:13 +00003934static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003935 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003936 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003937
3938 CONVERT_CHECKED(JSObject, object, args[0]);
3939 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003940 CONVERT_SMI_CHECKED(strict, args[2]);
3941 return object->DeleteProperty(key, strict == kStrictMode
3942 ? JSObject::STRICT_DELETION
3943 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944}
3945
3946
ager@chromium.org9085a012009-05-11 19:22:57 +00003947static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3948 Handle<String> key) {
3949 if (object->HasLocalProperty(*key)) return Heap::true_value();
3950 // Handle hidden prototypes. If there's a hidden prototype above this thing
3951 // then we have to check it for properties, because they are supposed to
3952 // look like they are on this object.
3953 Handle<Object> proto(object->GetPrototype());
3954 if (proto->IsJSObject() &&
3955 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3956 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3957 }
3958 return Heap::false_value();
3959}
3960
3961
lrn@chromium.org303ada72010-10-27 09:33:13 +00003962static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003963 NoHandleAllocation ha;
3964 ASSERT(args.length() == 2);
3965 CONVERT_CHECKED(String, key, args[1]);
3966
ager@chromium.org9085a012009-05-11 19:22:57 +00003967 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003969 if (obj->IsJSObject()) {
3970 JSObject* object = JSObject::cast(obj);
3971 // Fast case - no interceptors.
3972 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3973 // Slow case. Either it's not there or we have an interceptor. We should
3974 // have handles for this kind of deal.
3975 HandleScope scope;
3976 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3977 Handle<String>(key));
3978 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 // Well, there is one exception: Handle [] on strings.
3980 uint32_t index;
3981 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003982 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003983 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 return Heap::true_value();
3985 }
3986 }
3987 return Heap::false_value();
3988}
3989
3990
lrn@chromium.org303ada72010-10-27 09:33:13 +00003991static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003992 NoHandleAllocation na;
3993 ASSERT(args.length() == 2);
3994
3995 // Only JS objects can have properties.
3996 if (args[0]->IsJSObject()) {
3997 JSObject* object = JSObject::cast(args[0]);
3998 CONVERT_CHECKED(String, key, args[1]);
3999 if (object->HasProperty(key)) return Heap::true_value();
4000 }
4001 return Heap::false_value();
4002}
4003
4004
lrn@chromium.org303ada72010-10-27 09:33:13 +00004005static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004006 NoHandleAllocation na;
4007 ASSERT(args.length() == 2);
4008
4009 // Only JS objects can have elements.
4010 if (args[0]->IsJSObject()) {
4011 JSObject* object = JSObject::cast(args[0]);
4012 CONVERT_CHECKED(Smi, index_obj, args[1]);
4013 uint32_t index = index_obj->value();
4014 if (object->HasElement(index)) return Heap::true_value();
4015 }
4016 return Heap::false_value();
4017}
4018
4019
lrn@chromium.org303ada72010-10-27 09:33:13 +00004020static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 NoHandleAllocation ha;
4022 ASSERT(args.length() == 2);
4023
4024 CONVERT_CHECKED(JSObject, object, args[0]);
4025 CONVERT_CHECKED(String, key, args[1]);
4026
4027 uint32_t index;
4028 if (key->AsArrayIndex(&index)) {
4029 return Heap::ToBoolean(object->HasElement(index));
4030 }
4031
ager@chromium.org870a0b62008-11-04 11:43:05 +00004032 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
4033 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004034}
4035
4036
lrn@chromium.org303ada72010-10-27 09:33:13 +00004037static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 HandleScope scope;
4039 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004040 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004041 return *GetKeysFor(object);
4042}
4043
4044
4045// Returns either a FixedArray as Runtime_GetPropertyNames,
4046// or, if the given object has an enum cache that contains
4047// all enumerable properties of the object and its prototypes
4048// have none, the map of the object. This is used to speed up
4049// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004050static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051 ASSERT(args.length() == 1);
4052
4053 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4054
4055 if (raw_object->IsSimpleEnum()) return raw_object->map();
4056
4057 HandleScope scope;
4058 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004059 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4060 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061
4062 // Test again, since cache may have been built by preceding call.
4063 if (object->IsSimpleEnum()) return object->map();
4064
4065 return *content;
4066}
4067
4068
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004069// Find the length of the prototype chain that is to to handled as one. If a
4070// prototype object is hidden it is to be viewed as part of the the object it
4071// is prototype for.
4072static int LocalPrototypeChainLength(JSObject* obj) {
4073 int count = 1;
4074 Object* proto = obj->GetPrototype();
4075 while (proto->IsJSObject() &&
4076 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4077 count++;
4078 proto = JSObject::cast(proto)->GetPrototype();
4079 }
4080 return count;
4081}
4082
4083
4084// Return the names of the local named properties.
4085// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004086static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004087 HandleScope scope;
4088 ASSERT(args.length() == 1);
4089 if (!args[0]->IsJSObject()) {
4090 return Heap::undefined_value();
4091 }
4092 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4093
4094 // Skip the global proxy as it has no properties and always delegates to the
4095 // real global object.
4096 if (obj->IsJSGlobalProxy()) {
4097 // Only collect names if access is permitted.
4098 if (obj->IsAccessCheckNeeded() &&
4099 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
4100 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4101 return *Factory::NewJSArray(0);
4102 }
4103 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4104 }
4105
4106 // Find the number of objects making up this.
4107 int length = LocalPrototypeChainLength(*obj);
4108
4109 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004110 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004111 int total_property_count = 0;
4112 Handle<JSObject> jsproto = obj;
4113 for (int i = 0; i < length; i++) {
4114 // Only collect names if access is permitted.
4115 if (jsproto->IsAccessCheckNeeded() &&
4116 !Top::MayNamedAccess(*jsproto,
4117 Heap::undefined_value(),
4118 v8::ACCESS_KEYS)) {
4119 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4120 return *Factory::NewJSArray(0);
4121 }
4122 int n;
4123 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4124 local_property_count[i] = n;
4125 total_property_count += n;
4126 if (i < length - 1) {
4127 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4128 }
4129 }
4130
4131 // Allocate an array with storage for all the property names.
4132 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4133
4134 // Get the property names.
4135 jsproto = obj;
4136 int proto_with_hidden_properties = 0;
4137 for (int i = 0; i < length; i++) {
4138 jsproto->GetLocalPropertyNames(*names,
4139 i == 0 ? 0 : local_property_count[i - 1]);
4140 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4141 proto_with_hidden_properties++;
4142 }
4143 if (i < length - 1) {
4144 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4145 }
4146 }
4147
4148 // Filter out name of hidden propeties object.
4149 if (proto_with_hidden_properties > 0) {
4150 Handle<FixedArray> old_names = names;
4151 names = Factory::NewFixedArray(
4152 names->length() - proto_with_hidden_properties);
4153 int dest_pos = 0;
4154 for (int i = 0; i < total_property_count; i++) {
4155 Object* name = old_names->get(i);
4156 if (name == Heap::hidden_symbol()) {
4157 continue;
4158 }
4159 names->set(dest_pos++, name);
4160 }
4161 }
4162
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004163 return *Factory::NewJSArrayWithElements(names);
4164}
4165
4166
4167// Return the names of the local indexed properties.
4168// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004169static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004170 HandleScope scope;
4171 ASSERT(args.length() == 1);
4172 if (!args[0]->IsJSObject()) {
4173 return Heap::undefined_value();
4174 }
4175 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4176
4177 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4178 Handle<FixedArray> names = Factory::NewFixedArray(n);
4179 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4180 return *Factory::NewJSArrayWithElements(names);
4181}
4182
4183
4184// Return information on whether an object has a named or indexed interceptor.
4185// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004186static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004187 HandleScope scope;
4188 ASSERT(args.length() == 1);
4189 if (!args[0]->IsJSObject()) {
4190 return Smi::FromInt(0);
4191 }
4192 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4193
4194 int result = 0;
4195 if (obj->HasNamedInterceptor()) result |= 2;
4196 if (obj->HasIndexedInterceptor()) result |= 1;
4197
4198 return Smi::FromInt(result);
4199}
4200
4201
4202// Return property names from named interceptor.
4203// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004204static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004205 HandleScope scope;
4206 ASSERT(args.length() == 1);
4207 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4208
4209 if (obj->HasNamedInterceptor()) {
4210 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4211 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4212 }
4213 return Heap::undefined_value();
4214}
4215
4216
4217// Return element names from indexed interceptor.
4218// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004219static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004220 HandleScope scope;
4221 ASSERT(args.length() == 1);
4222 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4223
4224 if (obj->HasIndexedInterceptor()) {
4225 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4226 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4227 }
4228 return Heap::undefined_value();
4229}
4230
4231
lrn@chromium.org303ada72010-10-27 09:33:13 +00004232static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004233 ASSERT_EQ(args.length(), 1);
4234 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4235 HandleScope scope;
4236 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004237
4238 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004239 // Do access checks before going to the global object.
4240 if (object->IsAccessCheckNeeded() &&
4241 !Top::MayNamedAccess(*object, Heap::undefined_value(),
4242 v8::ACCESS_KEYS)) {
4243 Top::ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4244 return *Factory::NewJSArray(0);
4245 }
4246
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004247 Handle<Object> proto(object->GetPrototype());
4248 // If proxy is detached we simply return an empty array.
4249 if (proto->IsNull()) return *Factory::NewJSArray(0);
4250 object = Handle<JSObject>::cast(proto);
4251 }
4252
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004253 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4254 LOCAL_ONLY);
4255 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4256 // property array and since the result is mutable we have to create
4257 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004258 int length = contents->length();
4259 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4260 for (int i = 0; i < length; i++) {
4261 Object* entry = contents->get(i);
4262 if (entry->IsString()) {
4263 copy->set(i, entry);
4264 } else {
4265 ASSERT(entry->IsNumber());
4266 HandleScope scope;
4267 Handle<Object> entry_handle(entry);
4268 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4269 copy->set(i, *entry_str);
4270 }
4271 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004272 return *Factory::NewJSArrayWithElements(copy);
4273}
4274
4275
lrn@chromium.org303ada72010-10-27 09:33:13 +00004276static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004277 NoHandleAllocation ha;
4278 ASSERT(args.length() == 1);
4279
4280 // Compute the frame holding the arguments.
4281 JavaScriptFrameIterator it;
4282 it.AdvanceToArgumentsFrame();
4283 JavaScriptFrame* frame = it.frame();
4284
4285 // Get the actual number of provided arguments.
4286 const uint32_t n = frame->GetProvidedParametersCount();
4287
4288 // Try to convert the key to an index. If successful and within
4289 // index return the the argument from the frame.
4290 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004291 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004292 return frame->GetParameter(index);
4293 }
4294
4295 // Convert the key to a string.
4296 HandleScope scope;
4297 bool exception = false;
4298 Handle<Object> converted =
4299 Execution::ToString(args.at<Object>(0), &exception);
4300 if (exception) return Failure::Exception();
4301 Handle<String> key = Handle<String>::cast(converted);
4302
4303 // Try to convert the string key into an array index.
4304 if (key->AsArrayIndex(&index)) {
4305 if (index < n) {
4306 return frame->GetParameter(index);
4307 } else {
4308 return Top::initial_object_prototype()->GetElement(index);
4309 }
4310 }
4311
4312 // Handle special arguments properties.
4313 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4314 if (key->Equals(Heap::callee_symbol())) return frame->function();
4315
4316 // Lookup in the initial Object.prototype object.
4317 return Top::initial_object_prototype()->GetProperty(*key);
4318}
4319
4320
lrn@chromium.org303ada72010-10-27 09:33:13 +00004321static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004322 HandleScope scope;
4323
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004324 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004325 Handle<Object> object = args.at<Object>(0);
4326 if (object->IsJSObject()) {
4327 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004328 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004329 MaybeObject* ok = js_object->TransformToFastProperties(0);
4330 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004331 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004332 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004333 return *object;
4334}
4335
4336
lrn@chromium.org303ada72010-10-27 09:33:13 +00004337static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004338 HandleScope scope;
4339
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004340 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004341 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004342 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004343 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004344 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004345 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004346 return *object;
4347}
4348
4349
lrn@chromium.org303ada72010-10-27 09:33:13 +00004350static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004351 NoHandleAllocation ha;
4352 ASSERT(args.length() == 1);
4353
4354 return args[0]->ToBoolean();
4355}
4356
4357
4358// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4359// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004360static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004361 NoHandleAllocation ha;
4362
4363 Object* obj = args[0];
4364 if (obj->IsNumber()) return Heap::number_symbol();
4365 HeapObject* heap_obj = HeapObject::cast(obj);
4366
4367 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004368 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004369
4370 InstanceType instance_type = heap_obj->map()->instance_type();
4371 if (instance_type < FIRST_NONSTRING_TYPE) {
4372 return Heap::string_symbol();
4373 }
4374
4375 switch (instance_type) {
4376 case ODDBALL_TYPE:
4377 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4378 return Heap::boolean_symbol();
4379 }
4380 if (heap_obj->IsNull()) {
4381 return Heap::object_symbol();
4382 }
4383 ASSERT(heap_obj->IsUndefined());
4384 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004385 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004386 return Heap::function_symbol();
4387 default:
4388 // For any kind of object not handled above, the spec rule for
4389 // host objects gives that it is okay to return "object"
4390 return Heap::object_symbol();
4391 }
4392}
4393
4394
lrn@chromium.org25156de2010-04-06 13:10:27 +00004395static bool AreDigits(const char*s, int from, int to) {
4396 for (int i = from; i < to; i++) {
4397 if (s[i] < '0' || s[i] > '9') return false;
4398 }
4399
4400 return true;
4401}
4402
4403
4404static int ParseDecimalInteger(const char*s, int from, int to) {
4405 ASSERT(to - from < 10); // Overflow is not possible.
4406 ASSERT(from < to);
4407 int d = s[from] - '0';
4408
4409 for (int i = from + 1; i < to; i++) {
4410 d = 10 * d + (s[i] - '0');
4411 }
4412
4413 return d;
4414}
4415
4416
lrn@chromium.org303ada72010-10-27 09:33:13 +00004417static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004418 NoHandleAllocation ha;
4419 ASSERT(args.length() == 1);
4420 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004421 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004422
4423 // Fast case: short integer or some sorts of junk values.
4424 int len = subject->length();
4425 if (subject->IsSeqAsciiString()) {
4426 if (len == 0) return Smi::FromInt(0);
4427
4428 char const* data = SeqAsciiString::cast(subject)->GetChars();
4429 bool minus = (data[0] == '-');
4430 int start_pos = (minus ? 1 : 0);
4431
4432 if (start_pos == len) {
4433 return Heap::nan_value();
4434 } else if (data[start_pos] > '9') {
4435 // Fast check for a junk value. A valid string may start from a
4436 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4437 // the 'I' character ('Infinity'). All of that have codes not greater than
4438 // '9' except 'I'.
4439 if (data[start_pos] != 'I') {
4440 return Heap::nan_value();
4441 }
4442 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4443 // The maximal/minimal smi has 10 digits. If the string has less digits we
4444 // know it will fit into the smi-data type.
4445 int d = ParseDecimalInteger(data, start_pos, len);
4446 if (minus) {
4447 if (d == 0) return Heap::minus_zero_value();
4448 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004449 } else if (!subject->HasHashCode() &&
4450 len <= String::kMaxArrayIndexSize &&
4451 (len == 1 || data[0] != '0')) {
4452 // String hash is not calculated yet but all the data are present.
4453 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004454 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004455#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004456 subject->Hash(); // Force hash calculation.
4457 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4458 static_cast<int>(hash));
4459#endif
4460 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004461 }
4462 return Smi::FromInt(d);
4463 }
4464 }
4465
4466 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4468}
4469
4470
lrn@chromium.org303ada72010-10-27 09:33:13 +00004471static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472 NoHandleAllocation ha;
4473 ASSERT(args.length() == 1);
4474
4475 CONVERT_CHECKED(JSArray, codes, args[0]);
4476 int length = Smi::cast(codes->length())->value();
4477
4478 // Check if the string can be ASCII.
4479 int i;
4480 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004481 Object* element;
4482 { MaybeObject* maybe_element = codes->GetElement(i);
4483 // We probably can't get an exception here, but just in order to enforce
4484 // the checking of inputs in the runtime calls we check here.
4485 if (!maybe_element->ToObject(&element)) return maybe_element;
4486 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004487 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4488 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4489 break;
4490 }
4491
lrn@chromium.org303ada72010-10-27 09:33:13 +00004492 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004494 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004495 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004496 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 }
4498
lrn@chromium.org303ada72010-10-27 09:33:13 +00004499 Object* object = NULL;
4500 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004501 String* result = String::cast(object);
4502 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004503 Object* element;
4504 { MaybeObject* maybe_element = codes->GetElement(i);
4505 if (!maybe_element->ToObject(&element)) return maybe_element;
4506 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004508 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004509 }
4510 return result;
4511}
4512
4513
4514// kNotEscaped is generated by the following:
4515//
4516// #!/bin/perl
4517// for (my $i = 0; $i < 256; $i++) {
4518// print "\n" if $i % 16 == 0;
4519// my $c = chr($i);
4520// my $escaped = 1;
4521// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4522// print $escaped ? "0, " : "1, ";
4523// }
4524
4525
4526static bool IsNotEscaped(uint16_t character) {
4527 // Only for 8 bit characters, the rest are always escaped (in a different way)
4528 ASSERT(character < 256);
4529 static const char kNotEscaped[256] = {
4530 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4531 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4532 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4533 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4534 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4535 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4536 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4537 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4538 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4539 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4540 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4541 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4542 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4543 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4544 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4545 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4546 };
4547 return kNotEscaped[character] != 0;
4548}
4549
4550
lrn@chromium.org303ada72010-10-27 09:33:13 +00004551static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552 const char hex_chars[] = "0123456789ABCDEF";
4553 NoHandleAllocation ha;
4554 ASSERT(args.length() == 1);
4555 CONVERT_CHECKED(String, source, args[0]);
4556
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004557 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004558
4559 int escaped_length = 0;
4560 int length = source->length();
4561 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004562 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004563 buffer->Reset(source);
4564 while (buffer->has_more()) {
4565 uint16_t character = buffer->GetNext();
4566 if (character >= 256) {
4567 escaped_length += 6;
4568 } else if (IsNotEscaped(character)) {
4569 escaped_length++;
4570 } else {
4571 escaped_length += 3;
4572 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004573 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004574 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004575 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004576 Top::context()->mark_out_of_memory();
4577 return Failure::OutOfMemoryException();
4578 }
4579 }
4580 }
4581 // No length change implies no change. Return original string if no change.
4582 if (escaped_length == length) {
4583 return source;
4584 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004585 Object* o;
4586 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4587 if (!maybe_o->ToObject(&o)) return maybe_o;
4588 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 String* destination = String::cast(o);
4590 int dest_position = 0;
4591
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004592 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 buffer->Rewind();
4594 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004595 uint16_t chr = buffer->GetNext();
4596 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004597 destination->Set(dest_position, '%');
4598 destination->Set(dest_position+1, 'u');
4599 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4600 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4601 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4602 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004604 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004605 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004606 dest_position++;
4607 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004608 destination->Set(dest_position, '%');
4609 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4610 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004611 dest_position += 3;
4612 }
4613 }
4614 return destination;
4615}
4616
4617
4618static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4619 static const signed char kHexValue['g'] = {
4620 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4621 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4622 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4623 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4624 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4625 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4626 -1, 10, 11, 12, 13, 14, 15 };
4627
4628 if (character1 > 'f') return -1;
4629 int hi = kHexValue[character1];
4630 if (hi == -1) return -1;
4631 if (character2 > 'f') return -1;
4632 int lo = kHexValue[character2];
4633 if (lo == -1) return -1;
4634 return (hi << 4) + lo;
4635}
4636
4637
ager@chromium.org870a0b62008-11-04 11:43:05 +00004638static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004639 int i,
4640 int length,
4641 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004642 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004643 int32_t hi = 0;
4644 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004645 if (character == '%' &&
4646 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004647 source->Get(i + 1) == 'u' &&
4648 (hi = TwoDigitHex(source->Get(i + 2),
4649 source->Get(i + 3))) != -1 &&
4650 (lo = TwoDigitHex(source->Get(i + 4),
4651 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004652 *step = 6;
4653 return (hi << 8) + lo;
4654 } else if (character == '%' &&
4655 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004656 (lo = TwoDigitHex(source->Get(i + 1),
4657 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004658 *step = 3;
4659 return lo;
4660 } else {
4661 *step = 1;
4662 return character;
4663 }
4664}
4665
4666
lrn@chromium.org303ada72010-10-27 09:33:13 +00004667static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004668 NoHandleAllocation ha;
4669 ASSERT(args.length() == 1);
4670 CONVERT_CHECKED(String, source, args[0]);
4671
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004672 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004673
4674 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004675 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004676
4677 int unescaped_length = 0;
4678 for (int i = 0; i < length; unescaped_length++) {
4679 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004680 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004682 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683 i += step;
4684 }
4685
4686 // No length change implies no change. Return original string if no change.
4687 if (unescaped_length == length)
4688 return source;
4689
lrn@chromium.org303ada72010-10-27 09:33:13 +00004690 Object* o;
4691 { MaybeObject* maybe_o = ascii ?
4692 Heap::AllocateRawAsciiString(unescaped_length) :
4693 Heap::AllocateRawTwoByteString(unescaped_length);
4694 if (!maybe_o->ToObject(&o)) return maybe_o;
4695 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004696 String* destination = String::cast(o);
4697
4698 int dest_position = 0;
4699 for (int i = 0; i < length; dest_position++) {
4700 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004701 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702 i += step;
4703 }
4704 return destination;
4705}
4706
4707
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004708static const unsigned int kQuoteTableLength = 128u;
4709
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004710static const int kJsonQuotesCharactersPerEntry = 8;
4711static const char* const JsonQuotes =
4712 "\\u0000 \\u0001 \\u0002 \\u0003 "
4713 "\\u0004 \\u0005 \\u0006 \\u0007 "
4714 "\\b \\t \\n \\u000b "
4715 "\\f \\r \\u000e \\u000f "
4716 "\\u0010 \\u0011 \\u0012 \\u0013 "
4717 "\\u0014 \\u0015 \\u0016 \\u0017 "
4718 "\\u0018 \\u0019 \\u001a \\u001b "
4719 "\\u001c \\u001d \\u001e \\u001f "
4720 " ! \\\" # "
4721 "$ % & ' "
4722 "( ) * + "
4723 ", - . / "
4724 "0 1 2 3 "
4725 "4 5 6 7 "
4726 "8 9 : ; "
4727 "< = > ? "
4728 "@ A B C "
4729 "D E F G "
4730 "H I J K "
4731 "L M N O "
4732 "P Q R S "
4733 "T U V W "
4734 "X Y Z [ "
4735 "\\\\ ] ^ _ "
4736 "` a b c "
4737 "d e f g "
4738 "h i j k "
4739 "l m n o "
4740 "p q r s "
4741 "t u v w "
4742 "x y z { "
4743 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004744
4745
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004746// For a string that is less than 32k characters it should always be
4747// possible to allocate it in new space.
4748static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4749
4750
4751// Doing JSON quoting cannot make the string more than this many times larger.
4752static const int kJsonQuoteWorstCaseBlowup = 6;
4753
4754
4755// Covers the entire ASCII range (all other characters are unchanged by JSON
4756// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004757static const byte JsonQuoteLengths[kQuoteTableLength] = {
4758 6, 6, 6, 6, 6, 6, 6, 6,
4759 2, 2, 2, 6, 2, 2, 6, 6,
4760 6, 6, 6, 6, 6, 6, 6, 6,
4761 6, 6, 6, 6, 6, 6, 6, 6,
4762 1, 1, 2, 1, 1, 1, 1, 1,
4763 1, 1, 1, 1, 1, 1, 1, 1,
4764 1, 1, 1, 1, 1, 1, 1, 1,
4765 1, 1, 1, 1, 1, 1, 1, 1,
4766 1, 1, 1, 1, 1, 1, 1, 1,
4767 1, 1, 1, 1, 1, 1, 1, 1,
4768 1, 1, 1, 1, 1, 1, 1, 1,
4769 1, 1, 1, 1, 2, 1, 1, 1,
4770 1, 1, 1, 1, 1, 1, 1, 1,
4771 1, 1, 1, 1, 1, 1, 1, 1,
4772 1, 1, 1, 1, 1, 1, 1, 1,
4773 1, 1, 1, 1, 1, 1, 1, 1,
4774};
4775
4776
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004777template <typename StringType>
4778MaybeObject* AllocateRawString(int length);
4779
4780
4781template <>
4782MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4783 return Heap::AllocateRawTwoByteString(length);
4784}
4785
4786
4787template <>
4788MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4789 return Heap::AllocateRawAsciiString(length);
4790}
4791
4792
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004793template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004794static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004795 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004796 const Char* read_cursor = characters.start();
4797 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004798 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004799 int quoted_length = kSpaceForQuotes;
4800 while (read_cursor < end) {
4801 Char c = *(read_cursor++);
4802 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4803 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004804 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004805 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004806 }
4807 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004808 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4809 Object* new_object;
4810 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004811 return new_alloc;
4812 }
4813 StringType* new_string = StringType::cast(new_object);
4814
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004815 Char* write_cursor = reinterpret_cast<Char*>(
4816 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004817 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004818 *(write_cursor++) = '"';
4819
4820 read_cursor = characters.start();
4821 while (read_cursor < end) {
4822 Char c = *(read_cursor++);
4823 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4824 *(write_cursor++) = c;
4825 } else {
4826 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4827 const char* replacement = JsonQuotes +
4828 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4829 for (int i = 0; i < len; i++) {
4830 *write_cursor++ = *replacement++;
4831 }
4832 }
4833 }
4834 *(write_cursor++) = '"';
4835 return new_string;
4836}
4837
4838
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004839template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004840static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4841 int length = characters.length();
4842 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004843 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004844 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4845 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004846 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004847 }
4848
4849 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4850 Object* new_object;
4851 if (!new_alloc->ToObject(&new_object)) {
4852 return new_alloc;
4853 }
4854 if (!Heap::new_space()->Contains(new_object)) {
4855 // Even if our string is small enough to fit in new space we still have to
4856 // handle it being allocated in old space as may happen in the third
4857 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4858 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004859 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004860 }
4861 StringType* new_string = StringType::cast(new_object);
4862 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004863
4864 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4865 Char* write_cursor = reinterpret_cast<Char*>(
4866 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004867 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004868 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004869
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004870 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004871 const Char* end = read_cursor + length;
4872 while (read_cursor < end) {
4873 Char c = *(read_cursor++);
4874 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4875 *(write_cursor++) = c;
4876 } else {
4877 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4878 const char* replacement = JsonQuotes +
4879 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4880 write_cursor[0] = replacement[0];
4881 if (len > 1) {
4882 write_cursor[1] = replacement[1];
4883 if (len > 2) {
4884 ASSERT(len == 6);
4885 write_cursor[2] = replacement[2];
4886 write_cursor[3] = replacement[3];
4887 write_cursor[4] = replacement[4];
4888 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004889 }
4890 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004891 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004892 }
4893 }
4894 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004895
4896 int final_length = static_cast<int>(
4897 write_cursor - reinterpret_cast<Char*>(
4898 new_string->address() + SeqAsciiString::kHeaderSize));
4899 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4900 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004901 return new_string;
4902}
4903
4904
4905static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4906 NoHandleAllocation ha;
4907 CONVERT_CHECKED(String, str, args[0]);
4908 if (!str->IsFlat()) {
4909 MaybeObject* try_flatten = str->TryFlatten();
4910 Object* flat;
4911 if (!try_flatten->ToObject(&flat)) {
4912 return try_flatten;
4913 }
4914 str = String::cast(flat);
4915 ASSERT(str->IsFlat());
4916 }
4917 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004918 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004919 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004920 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004921 }
4922}
4923
4924
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004925static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4926 NoHandleAllocation ha;
4927 CONVERT_CHECKED(String, str, args[0]);
4928 if (!str->IsFlat()) {
4929 MaybeObject* try_flatten = str->TryFlatten();
4930 Object* flat;
4931 if (!try_flatten->ToObject(&flat)) {
4932 return try_flatten;
4933 }
4934 str = String::cast(flat);
4935 ASSERT(str->IsFlat());
4936 }
4937 if (str->IsTwoByteRepresentation()) {
4938 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
4939 } else {
4940 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
4941 }
4942}
4943
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004944
lrn@chromium.org303ada72010-10-27 09:33:13 +00004945static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004946 NoHandleAllocation ha;
4947
4948 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004949 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004950
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004951 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004952
lrn@chromium.org25156de2010-04-06 13:10:27 +00004953 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4954 double value = StringToInt(s, radix);
4955 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004956}
4957
4958
lrn@chromium.org303ada72010-10-27 09:33:13 +00004959static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004960 NoHandleAllocation ha;
4961 CONVERT_CHECKED(String, str, args[0]);
4962
4963 // ECMA-262 section 15.1.2.3, empty string is NaN
4964 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4965
4966 // Create a number object from the value.
4967 return Heap::NumberFromDouble(value);
4968}
4969
4970
4971static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4972static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4973
4974
4975template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004976MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4977 String* s,
4978 int length,
4979 int input_string_length,
4980 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004981 // We try this twice, once with the assumption that the result is no longer
4982 // than the input and, if that assumption breaks, again with the exact
4983 // length. This may not be pretty, but it is nicer than what was here before
4984 // and I hereby claim my vaffel-is.
4985 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004986 // Allocate the resulting string.
4987 //
4988 // NOTE: This assumes that the upper/lower case of an ascii
4989 // character is also ascii. This is currently the case, but it
4990 // might break in the future if we implement more context and locale
4991 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004992 Object* o;
4993 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4994 ? Heap::AllocateRawAsciiString(length)
4995 : Heap::AllocateRawTwoByteString(length);
4996 if (!maybe_o->ToObject(&o)) return maybe_o;
4997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004998 String* result = String::cast(o);
4999 bool has_changed_character = false;
5000
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001 // Convert all characters to upper case, assuming that they will fit
5002 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005003 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005004 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005005 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005006 // We can assume that the string is not empty
5007 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005008 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005009 bool has_next = buffer->has_more();
5010 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011 int char_length = mapping->get(current, next, chars);
5012 if (char_length == 0) {
5013 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005014 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005015 i++;
5016 } else if (char_length == 1) {
5017 // Common case: converting the letter resulted in one character.
5018 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005019 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005020 has_changed_character = true;
5021 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005022 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005023 // We've assumed that the result would be as long as the
5024 // input but here is a character that converts to several
5025 // characters. No matter, we calculate the exact length
5026 // of the result and try the whole thing again.
5027 //
5028 // Note that this leaves room for optimization. We could just
5029 // memcpy what we already have to the result string. Also,
5030 // the result string is the last object allocated we could
5031 // "realloc" it and probably, in the vast majority of cases,
5032 // extend the existing string to be able to hold the full
5033 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005034 int next_length = 0;
5035 if (has_next) {
5036 next_length = mapping->get(next, 0, chars);
5037 if (next_length == 0) next_length = 1;
5038 }
5039 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005040 while (buffer->has_more()) {
5041 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005042 // NOTE: we use 0 as the next character here because, while
5043 // the next character may affect what a character converts to,
5044 // it does not in any case affect the length of what it convert
5045 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005046 int char_length = mapping->get(current, 0, chars);
5047 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005048 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005049 if (current_length > Smi::kMaxValue) {
5050 Top::context()->mark_out_of_memory();
5051 return Failure::OutOfMemoryException();
5052 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005053 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005054 // Try again with the real length.
5055 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005056 } else {
5057 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005058 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005059 i++;
5060 }
5061 has_changed_character = true;
5062 }
5063 current = next;
5064 }
5065 if (has_changed_character) {
5066 return result;
5067 } else {
5068 // If we didn't actually change anything in doing the conversion
5069 // we simple return the result and let the converted string
5070 // become garbage; there is no reason to keep two identical strings
5071 // alive.
5072 return s;
5073 }
5074}
5075
5076
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005077namespace {
5078
lrn@chromium.org303ada72010-10-27 09:33:13 +00005079static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5080
5081
5082// Given a word and two range boundaries returns a word with high bit
5083// set in every byte iff the corresponding input byte was strictly in
5084// the range (m, n). All the other bits in the result are cleared.
5085// This function is only useful when it can be inlined and the
5086// boundaries are statically known.
5087// Requires: all bytes in the input word and the boundaries must be
5088// ascii (less than 0x7F).
5089static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5090 // Every byte in an ascii string is less than or equal to 0x7F.
5091 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5092 // Use strict inequalities since in edge cases the function could be
5093 // further simplified.
5094 ASSERT(0 < m && m < n && n < 0x7F);
5095 // Has high bit set in every w byte less than n.
5096 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5097 // Has high bit set in every w byte greater than m.
5098 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5099 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5100}
5101
5102
5103enum AsciiCaseConversion {
5104 ASCII_TO_LOWER,
5105 ASCII_TO_UPPER
5106};
5107
5108
5109template <AsciiCaseConversion dir>
5110struct FastAsciiConverter {
5111 static bool Convert(char* dst, char* src, int length) {
5112#ifdef DEBUG
5113 char* saved_dst = dst;
5114 char* saved_src = src;
5115#endif
5116 // We rely on the distance between upper and lower case letters
5117 // being a known power of 2.
5118 ASSERT('a' - 'A' == (1 << 5));
5119 // Boundaries for the range of input characters than require conversion.
5120 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5121 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5122 bool changed = false;
5123 char* const limit = src + length;
5124#ifdef V8_HOST_CAN_READ_UNALIGNED
5125 // Process the prefix of the input that requires no conversion one
5126 // (machine) word at a time.
5127 while (src <= limit - sizeof(uintptr_t)) {
5128 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5129 if (AsciiRangeMask(w, lo, hi) != 0) {
5130 changed = true;
5131 break;
5132 }
5133 *reinterpret_cast<uintptr_t*>(dst) = w;
5134 src += sizeof(uintptr_t);
5135 dst += sizeof(uintptr_t);
5136 }
5137 // Process the remainder of the input performing conversion when
5138 // required one word at a time.
5139 while (src <= limit - sizeof(uintptr_t)) {
5140 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5141 uintptr_t m = AsciiRangeMask(w, lo, hi);
5142 // The mask has high (7th) bit set in every byte that needs
5143 // conversion and we know that the distance between cases is
5144 // 1 << 5.
5145 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5146 src += sizeof(uintptr_t);
5147 dst += sizeof(uintptr_t);
5148 }
5149#endif
5150 // Process the last few bytes of the input (or the whole input if
5151 // unaligned access is not supported).
5152 while (src < limit) {
5153 char c = *src;
5154 if (lo < c && c < hi) {
5155 c ^= (1 << 5);
5156 changed = true;
5157 }
5158 *dst = c;
5159 ++src;
5160 ++dst;
5161 }
5162#ifdef DEBUG
5163 CheckConvert(saved_dst, saved_src, length, changed);
5164#endif
5165 return changed;
5166 }
5167
5168#ifdef DEBUG
5169 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5170 bool expected_changed = false;
5171 for (int i = 0; i < length; i++) {
5172 if (dst[i] == src[i]) continue;
5173 expected_changed = true;
5174 if (dir == ASCII_TO_LOWER) {
5175 ASSERT('A' <= src[i] && src[i] <= 'Z');
5176 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5177 } else {
5178 ASSERT(dir == ASCII_TO_UPPER);
5179 ASSERT('a' <= src[i] && src[i] <= 'z');
5180 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5181 }
5182 }
5183 ASSERT(expected_changed == changed);
5184 }
5185#endif
5186};
5187
5188
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005189struct ToLowerTraits {
5190 typedef unibrow::ToLowercase UnibrowConverter;
5191
lrn@chromium.org303ada72010-10-27 09:33:13 +00005192 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005193};
5194
5195
5196struct ToUpperTraits {
5197 typedef unibrow::ToUppercase UnibrowConverter;
5198
lrn@chromium.org303ada72010-10-27 09:33:13 +00005199 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005200};
5201
5202} // namespace
5203
5204
5205template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005206MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005207 Arguments args,
5208 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005209 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005210 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005211 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005212
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005213 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005214 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005215 if (length == 0) return s;
5216
5217 // Simpler handling of ascii strings.
5218 //
5219 // NOTE: This assumes that the upper/lower case of an ascii
5220 // character is also ascii. This is currently the case, but it
5221 // might break in the future if we implement more context and locale
5222 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005223 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005224 Object* o;
5225 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5226 if (!maybe_o->ToObject(&o)) return maybe_o;
5227 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005228 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005229 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005230 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005231 return has_changed_character ? result : s;
5232 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005233
lrn@chromium.org303ada72010-10-27 09:33:13 +00005234 Object* answer;
5235 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5236 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5237 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005238 if (answer->IsSmi()) {
5239 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005240 { MaybeObject* maybe_answer =
5241 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5242 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5243 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005244 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005245 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005246}
5247
5248
lrn@chromium.org303ada72010-10-27 09:33:13 +00005249static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005250 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251}
5252
5253
lrn@chromium.org303ada72010-10-27 09:33:13 +00005254static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005255 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005256}
5257
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005258
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005259static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5260 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5261}
5262
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005263
lrn@chromium.org303ada72010-10-27 09:33:13 +00005264static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005265 NoHandleAllocation ha;
5266 ASSERT(args.length() == 3);
5267
5268 CONVERT_CHECKED(String, s, args[0]);
5269 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5270 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5271
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005272 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005273 int length = s->length();
5274
5275 int left = 0;
5276 if (trimLeft) {
5277 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5278 left++;
5279 }
5280 }
5281
5282 int right = length;
5283 if (trimRight) {
5284 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5285 right--;
5286 }
5287 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005288 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005289}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005290
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005291
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005292template <typename SubjectChar, typename PatternChar>
5293void FindStringIndices(Vector<const SubjectChar> subject,
5294 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005295 ZoneList<int>* indices,
5296 unsigned int limit) {
5297 ASSERT(limit > 0);
5298 // Collect indices of pattern in subject, and the end-of-string index.
5299 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005300 StringSearch<PatternChar, SubjectChar> search(pattern);
5301 int pattern_length = pattern.length();
5302 int index = 0;
5303 while (limit > 0) {
5304 index = search.Search(subject, index);
5305 if (index < 0) return;
5306 indices->Add(index);
5307 index += pattern_length;
5308 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005309 }
5310}
5311
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005312
lrn@chromium.org303ada72010-10-27 09:33:13 +00005313static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005314 ASSERT(args.length() == 3);
5315 HandleScope handle_scope;
5316 CONVERT_ARG_CHECKED(String, subject, 0);
5317 CONVERT_ARG_CHECKED(String, pattern, 1);
5318 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5319
5320 int subject_length = subject->length();
5321 int pattern_length = pattern->length();
5322 RUNTIME_ASSERT(pattern_length > 0);
5323
5324 // The limit can be very large (0xffffffffu), but since the pattern
5325 // isn't empty, we can never create more parts than ~half the length
5326 // of the subject.
5327
5328 if (!subject->IsFlat()) FlattenString(subject);
5329
5330 static const int kMaxInitialListCapacity = 16;
5331
5332 ZoneScope scope(DELETE_ON_EXIT);
5333
5334 // Find (up to limit) indices of separator and end-of-string in subject
5335 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5336 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005337 if (!pattern->IsFlat()) FlattenString(pattern);
5338
5339 // No allocation block.
5340 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005341 AssertNoAllocation nogc;
5342 if (subject->IsAsciiRepresentation()) {
5343 Vector<const char> subject_vector = subject->ToAsciiVector();
5344 if (pattern->IsAsciiRepresentation()) {
5345 FindStringIndices(subject_vector,
5346 pattern->ToAsciiVector(),
5347 &indices,
5348 limit);
5349 } else {
5350 FindStringIndices(subject_vector,
5351 pattern->ToUC16Vector(),
5352 &indices,
5353 limit);
5354 }
5355 } else {
5356 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5357 if (pattern->IsAsciiRepresentation()) {
5358 FindStringIndices(subject_vector,
5359 pattern->ToAsciiVector(),
5360 &indices,
5361 limit);
5362 } else {
5363 FindStringIndices(subject_vector,
5364 pattern->ToUC16Vector(),
5365 &indices,
5366 limit);
5367 }
5368 }
5369 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005370
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005371 if (static_cast<uint32_t>(indices.length()) < limit) {
5372 indices.Add(subject_length);
5373 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005374
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005375 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005376
5377 // Create JSArray of substrings separated by separator.
5378 int part_count = indices.length();
5379
5380 Handle<JSArray> result = Factory::NewJSArray(part_count);
5381 result->set_length(Smi::FromInt(part_count));
5382
5383 ASSERT(result->HasFastElements());
5384
5385 if (part_count == 1 && indices.at(0) == subject_length) {
5386 FixedArray::cast(result->elements())->set(0, *subject);
5387 return *result;
5388 }
5389
5390 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5391 int part_start = 0;
5392 for (int i = 0; i < part_count; i++) {
5393 HandleScope local_loop_handle;
5394 int part_end = indices.at(i);
5395 Handle<String> substring =
5396 Factory::NewSubString(subject, part_start, part_end);
5397 elements->set(i, *substring);
5398 part_start = part_end + pattern_length;
5399 }
5400
5401 return *result;
5402}
5403
5404
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005405// Copies ascii characters to the given fixed array looking up
5406// one-char strings in the cache. Gives up on the first char that is
5407// not in the cache and fills the remainder with smi zeros. Returns
5408// the length of the successfully copied prefix.
5409static int CopyCachedAsciiCharsToArray(const char* chars,
5410 FixedArray* elements,
5411 int length) {
5412 AssertNoAllocation nogc;
5413 FixedArray* ascii_cache = Heap::single_character_string_cache();
5414 Object* undefined = Heap::undefined_value();
5415 int i;
5416 for (i = 0; i < length; ++i) {
5417 Object* value = ascii_cache->get(chars[i]);
5418 if (value == undefined) break;
5419 ASSERT(!Heap::InNewSpace(value));
5420 elements->set(i, value, SKIP_WRITE_BARRIER);
5421 }
5422 if (i < length) {
5423 ASSERT(Smi::FromInt(0) == 0);
5424 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5425 }
5426#ifdef DEBUG
5427 for (int j = 0; j < length; ++j) {
5428 Object* element = elements->get(j);
5429 ASSERT(element == Smi::FromInt(0) ||
5430 (element->IsString() && String::cast(element)->LooksValid()));
5431 }
5432#endif
5433 return i;
5434}
5435
5436
5437// Converts a String to JSArray.
5438// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005439static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005440 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005441 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005442 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005443 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005444
5445 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005446 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005447
5448 Handle<FixedArray> elements;
5449 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005450 Object* obj;
5451 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5452 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5453 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005454 elements = Handle<FixedArray>(FixedArray::cast(obj));
5455
5456 Vector<const char> chars = s->ToAsciiVector();
5457 // Note, this will initialize all elements (not only the prefix)
5458 // to prevent GC from seeing partially initialized array.
5459 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5460 *elements,
5461 length);
5462
5463 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005464 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5465 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005466 }
5467 } else {
5468 elements = Factory::NewFixedArray(length);
5469 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005470 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5471 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005472 }
5473 }
5474
5475#ifdef DEBUG
5476 for (int i = 0; i < length; ++i) {
5477 ASSERT(String::cast(elements->get(i))->length() == 1);
5478 }
5479#endif
5480
5481 return *Factory::NewJSArrayWithElements(elements);
5482}
5483
5484
lrn@chromium.org303ada72010-10-27 09:33:13 +00005485static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005486 NoHandleAllocation ha;
5487 ASSERT(args.length() == 1);
5488 CONVERT_CHECKED(String, value, args[0]);
5489 return value->ToObject();
5490}
5491
5492
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005493bool Runtime::IsUpperCaseChar(uint16_t ch) {
5494 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5495 int char_length = to_upper_mapping.get(ch, 0, chars);
5496 return char_length == 0;
5497}
5498
5499
lrn@chromium.org303ada72010-10-27 09:33:13 +00005500static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501 NoHandleAllocation ha;
5502 ASSERT(args.length() == 1);
5503
5504 Object* number = args[0];
5505 RUNTIME_ASSERT(number->IsNumber());
5506
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005507 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005508}
5509
5510
lrn@chromium.org303ada72010-10-27 09:33:13 +00005511static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005512 NoHandleAllocation ha;
5513 ASSERT(args.length() == 1);
5514
5515 Object* number = args[0];
5516 RUNTIME_ASSERT(number->IsNumber());
5517
5518 return Heap::NumberToString(number, false);
5519}
5520
5521
lrn@chromium.org303ada72010-10-27 09:33:13 +00005522static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005523 NoHandleAllocation ha;
5524 ASSERT(args.length() == 1);
5525
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005526 CONVERT_DOUBLE_CHECKED(number, args[0]);
5527
5528 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5529 if (number > 0 && number <= Smi::kMaxValue) {
5530 return Smi::FromInt(static_cast<int>(number));
5531 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005532 return Heap::NumberFromDouble(DoubleToInteger(number));
5533}
5534
5535
lrn@chromium.org303ada72010-10-27 09:33:13 +00005536static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005537 NoHandleAllocation ha;
5538 ASSERT(args.length() == 1);
5539
5540 CONVERT_DOUBLE_CHECKED(number, args[0]);
5541
5542 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5543 if (number > 0 && number <= Smi::kMaxValue) {
5544 return Smi::FromInt(static_cast<int>(number));
5545 }
5546
5547 double double_value = DoubleToInteger(number);
5548 // Map both -0 and +0 to +0.
5549 if (double_value == 0) double_value = 0;
5550
5551 return Heap::NumberFromDouble(double_value);
5552}
5553
5554
lrn@chromium.org303ada72010-10-27 09:33:13 +00005555static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005556 NoHandleAllocation ha;
5557 ASSERT(args.length() == 1);
5558
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005559 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005560 return Heap::NumberFromUint32(number);
5561}
5562
5563
lrn@chromium.org303ada72010-10-27 09:33:13 +00005564static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005565 NoHandleAllocation ha;
5566 ASSERT(args.length() == 1);
5567
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005568 CONVERT_DOUBLE_CHECKED(number, args[0]);
5569
5570 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5571 if (number > 0 && number <= Smi::kMaxValue) {
5572 return Smi::FromInt(static_cast<int>(number));
5573 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005574 return Heap::NumberFromInt32(DoubleToInt32(number));
5575}
5576
5577
ager@chromium.org870a0b62008-11-04 11:43:05 +00005578// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5579// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005580static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005581 NoHandleAllocation ha;
5582 ASSERT(args.length() == 1);
5583
5584 Object* obj = args[0];
5585 if (obj->IsSmi()) {
5586 return obj;
5587 }
5588 if (obj->IsHeapNumber()) {
5589 double value = HeapNumber::cast(obj)->value();
5590 int int_value = FastD2I(value);
5591 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5592 return Smi::FromInt(int_value);
5593 }
5594 }
5595 return Heap::nan_value();
5596}
5597
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005598
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005599static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5600 NoHandleAllocation ha;
5601 ASSERT(args.length() == 0);
5602 return Heap::AllocateHeapNumber(0);
5603}
5604
5605
lrn@chromium.org303ada72010-10-27 09:33:13 +00005606static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 NoHandleAllocation ha;
5608 ASSERT(args.length() == 2);
5609
5610 CONVERT_DOUBLE_CHECKED(x, args[0]);
5611 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005612 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005613}
5614
5615
lrn@chromium.org303ada72010-10-27 09:33:13 +00005616static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005617 NoHandleAllocation ha;
5618 ASSERT(args.length() == 2);
5619
5620 CONVERT_DOUBLE_CHECKED(x, args[0]);
5621 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005622 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005623}
5624
5625
lrn@chromium.org303ada72010-10-27 09:33:13 +00005626static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005627 NoHandleAllocation ha;
5628 ASSERT(args.length() == 2);
5629
5630 CONVERT_DOUBLE_CHECKED(x, args[0]);
5631 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005632 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005633}
5634
5635
lrn@chromium.org303ada72010-10-27 09:33:13 +00005636static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005637 NoHandleAllocation ha;
5638 ASSERT(args.length() == 1);
5639
5640 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005641 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642}
5643
5644
lrn@chromium.org303ada72010-10-27 09:33:13 +00005645static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005646 NoHandleAllocation ha;
5647 ASSERT(args.length() == 0);
5648
5649 return Heap::NumberFromDouble(9876543210.0);
5650}
5651
5652
lrn@chromium.org303ada72010-10-27 09:33:13 +00005653static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005654 NoHandleAllocation ha;
5655 ASSERT(args.length() == 2);
5656
5657 CONVERT_DOUBLE_CHECKED(x, args[0]);
5658 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005659 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005660}
5661
5662
lrn@chromium.org303ada72010-10-27 09:33:13 +00005663static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664 NoHandleAllocation ha;
5665 ASSERT(args.length() == 2);
5666
5667 CONVERT_DOUBLE_CHECKED(x, args[0]);
5668 CONVERT_DOUBLE_CHECKED(y, args[1]);
5669
ager@chromium.org3811b432009-10-28 14:53:37 +00005670 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005671 // NumberFromDouble may return a Smi instead of a Number object
5672 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005673}
5674
5675
lrn@chromium.org303ada72010-10-27 09:33:13 +00005676static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005677 NoHandleAllocation ha;
5678 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005679 CONVERT_CHECKED(String, str1, args[0]);
5680 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005681 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005682 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005683}
5684
5685
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005686template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005687static inline void StringBuilderConcatHelper(String* special,
5688 sinkchar* sink,
5689 FixedArray* fixed_array,
5690 int array_length) {
5691 int position = 0;
5692 for (int i = 0; i < array_length; i++) {
5693 Object* element = fixed_array->get(i);
5694 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005695 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005696 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005697 int pos;
5698 int len;
5699 if (encoded_slice > 0) {
5700 // Position and length encoded in one smi.
5701 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5702 len = StringBuilderSubstringLength::decode(encoded_slice);
5703 } else {
5704 // Position and length encoded in two smis.
5705 Object* obj = fixed_array->get(++i);
5706 ASSERT(obj->IsSmi());
5707 pos = Smi::cast(obj)->value();
5708 len = -encoded_slice;
5709 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005710 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005711 sink + position,
5712 pos,
5713 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005714 position += len;
5715 } else {
5716 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005717 int element_length = string->length();
5718 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005719 position += element_length;
5720 }
5721 }
5722}
5723
5724
lrn@chromium.org303ada72010-10-27 09:33:13 +00005725static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005726 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005727 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005728 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005729 if (!args[1]->IsSmi()) {
5730 Top::context()->mark_out_of_memory();
5731 return Failure::OutOfMemoryException();
5732 }
5733 int array_length = Smi::cast(args[1])->value();
5734 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005735
5736 // This assumption is used by the slice encoding in one or two smis.
5737 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5738
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005739 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005740 if (!array->HasFastElements()) {
5741 return Top::Throw(Heap::illegal_argument_symbol());
5742 }
5743 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005744 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005745 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005746 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005747
5748 if (array_length == 0) {
5749 return Heap::empty_string();
5750 } else if (array_length == 1) {
5751 Object* first = fixed_array->get(0);
5752 if (first->IsString()) return first;
5753 }
5754
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005755 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005756 int position = 0;
5757 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005758 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005759 Object* elt = fixed_array->get(i);
5760 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005761 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005762 int smi_value = Smi::cast(elt)->value();
5763 int pos;
5764 int len;
5765 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005766 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005767 pos = StringBuilderSubstringPosition::decode(smi_value);
5768 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005769 } else {
5770 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005771 len = -smi_value;
5772 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005773 i++;
5774 if (i >= array_length) {
5775 return Top::Throw(Heap::illegal_argument_symbol());
5776 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005777 Object* next_smi = fixed_array->get(i);
5778 if (!next_smi->IsSmi()) {
5779 return Top::Throw(Heap::illegal_argument_symbol());
5780 }
5781 pos = Smi::cast(next_smi)->value();
5782 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005783 return Top::Throw(Heap::illegal_argument_symbol());
5784 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005785 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005786 ASSERT(pos >= 0);
5787 ASSERT(len >= 0);
5788 if (pos > special_length || len > special_length - pos) {
5789 return Top::Throw(Heap::illegal_argument_symbol());
5790 }
5791 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005792 } else if (elt->IsString()) {
5793 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005794 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005795 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005796 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005797 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005798 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005799 } else {
5800 return Top::Throw(Heap::illegal_argument_symbol());
5801 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005802 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005803 Top::context()->mark_out_of_memory();
5804 return Failure::OutOfMemoryException();
5805 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005806 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005807 }
5808
5809 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005810 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005811
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005812 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005813 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5814 if (!maybe_object->ToObject(&object)) return maybe_object;
5815 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005816 SeqAsciiString* answer = SeqAsciiString::cast(object);
5817 StringBuilderConcatHelper(special,
5818 answer->GetChars(),
5819 fixed_array,
5820 array_length);
5821 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005822 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005823 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5824 if (!maybe_object->ToObject(&object)) return maybe_object;
5825 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005826 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5827 StringBuilderConcatHelper(special,
5828 answer->GetChars(),
5829 fixed_array,
5830 array_length);
5831 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005832 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005833}
5834
5835
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005836static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
5837 NoHandleAllocation ha;
5838 ASSERT(args.length() == 3);
5839 CONVERT_CHECKED(JSArray, array, args[0]);
5840 if (!args[1]->IsSmi()) {
5841 Top::context()->mark_out_of_memory();
5842 return Failure::OutOfMemoryException();
5843 }
5844 int array_length = Smi::cast(args[1])->value();
5845 CONVERT_CHECKED(String, separator, args[2]);
5846
5847 if (!array->HasFastElements()) {
5848 return Top::Throw(Heap::illegal_argument_symbol());
5849 }
5850 FixedArray* fixed_array = FixedArray::cast(array->elements());
5851 if (fixed_array->length() < array_length) {
5852 array_length = fixed_array->length();
5853 }
5854
5855 if (array_length == 0) {
5856 return Heap::empty_string();
5857 } else if (array_length == 1) {
5858 Object* first = fixed_array->get(0);
5859 if (first->IsString()) return first;
5860 }
5861
5862 int separator_length = separator->length();
5863 int max_nof_separators =
5864 (String::kMaxLength + separator_length - 1) / separator_length;
5865 if (max_nof_separators < (array_length - 1)) {
5866 Top::context()->mark_out_of_memory();
5867 return Failure::OutOfMemoryException();
5868 }
5869 int length = (array_length - 1) * separator_length;
5870 for (int i = 0; i < array_length; i++) {
5871 Object* element_obj = fixed_array->get(i);
5872 if (!element_obj->IsString()) {
5873 // TODO(1161): handle this case.
5874 return Top::Throw(Heap::illegal_argument_symbol());
5875 }
5876 String* element = String::cast(element_obj);
5877 int increment = element->length();
5878 if (increment > String::kMaxLength - length) {
5879 Top::context()->mark_out_of_memory();
5880 return Failure::OutOfMemoryException();
5881 }
5882 length += increment;
5883 }
5884
5885 Object* object;
5886 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5887 if (!maybe_object->ToObject(&object)) return maybe_object;
5888 }
5889 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5890
5891 uc16* sink = answer->GetChars();
5892#ifdef DEBUG
5893 uc16* end = sink + length;
5894#endif
5895
5896 String* first = String::cast(fixed_array->get(0));
5897 int first_length = first->length();
5898 String::WriteToFlat(first, sink, 0, first_length);
5899 sink += first_length;
5900
5901 for (int i = 1; i < array_length; i++) {
5902 ASSERT(sink + separator_length <= end);
5903 String::WriteToFlat(separator, sink, 0, separator_length);
5904 sink += separator_length;
5905
5906 String* element = String::cast(fixed_array->get(i));
5907 int element_length = element->length();
5908 ASSERT(sink + element_length <= end);
5909 String::WriteToFlat(element, sink, 0, element_length);
5910 sink += element_length;
5911 }
5912 ASSERT(sink == end);
5913
5914 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
5915 return answer;
5916}
5917
5918
lrn@chromium.org303ada72010-10-27 09:33:13 +00005919static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920 NoHandleAllocation ha;
5921 ASSERT(args.length() == 2);
5922
5923 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5924 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5925 return Heap::NumberFromInt32(x | y);
5926}
5927
5928
lrn@chromium.org303ada72010-10-27 09:33:13 +00005929static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005930 NoHandleAllocation ha;
5931 ASSERT(args.length() == 2);
5932
5933 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5934 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5935 return Heap::NumberFromInt32(x & y);
5936}
5937
5938
lrn@chromium.org303ada72010-10-27 09:33:13 +00005939static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940 NoHandleAllocation ha;
5941 ASSERT(args.length() == 2);
5942
5943 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5944 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5945 return Heap::NumberFromInt32(x ^ y);
5946}
5947
5948
lrn@chromium.org303ada72010-10-27 09:33:13 +00005949static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005950 NoHandleAllocation ha;
5951 ASSERT(args.length() == 1);
5952
5953 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5954 return Heap::NumberFromInt32(~x);
5955}
5956
5957
lrn@chromium.org303ada72010-10-27 09:33:13 +00005958static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959 NoHandleAllocation ha;
5960 ASSERT(args.length() == 2);
5961
5962 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5963 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5964 return Heap::NumberFromInt32(x << (y & 0x1f));
5965}
5966
5967
lrn@chromium.org303ada72010-10-27 09:33:13 +00005968static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 NoHandleAllocation ha;
5970 ASSERT(args.length() == 2);
5971
5972 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5973 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5974 return Heap::NumberFromUint32(x >> (y & 0x1f));
5975}
5976
5977
lrn@chromium.org303ada72010-10-27 09:33:13 +00005978static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 NoHandleAllocation ha;
5980 ASSERT(args.length() == 2);
5981
5982 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5983 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5984 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5985}
5986
5987
lrn@chromium.org303ada72010-10-27 09:33:13 +00005988static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 NoHandleAllocation ha;
5990 ASSERT(args.length() == 2);
5991
5992 CONVERT_DOUBLE_CHECKED(x, args[0]);
5993 CONVERT_DOUBLE_CHECKED(y, args[1]);
5994 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5995 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5996 if (x == y) return Smi::FromInt(EQUAL);
5997 Object* result;
5998 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5999 result = Smi::FromInt(EQUAL);
6000 } else {
6001 result = Smi::FromInt(NOT_EQUAL);
6002 }
6003 return result;
6004}
6005
6006
lrn@chromium.org303ada72010-10-27 09:33:13 +00006007static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 NoHandleAllocation ha;
6009 ASSERT(args.length() == 2);
6010
6011 CONVERT_CHECKED(String, x, args[0]);
6012 CONVERT_CHECKED(String, y, args[1]);
6013
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006014 bool not_equal = !x->Equals(y);
6015 // This is slightly convoluted because the value that signifies
6016 // equality is 0 and inequality is 1 so we have to negate the result
6017 // from String::Equals.
6018 ASSERT(not_equal == 0 || not_equal == 1);
6019 STATIC_CHECK(EQUAL == 0);
6020 STATIC_CHECK(NOT_EQUAL == 1);
6021 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022}
6023
6024
lrn@chromium.org303ada72010-10-27 09:33:13 +00006025static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 NoHandleAllocation ha;
6027 ASSERT(args.length() == 3);
6028
6029 CONVERT_DOUBLE_CHECKED(x, args[0]);
6030 CONVERT_DOUBLE_CHECKED(y, args[1]);
6031 if (isnan(x) || isnan(y)) return args[2];
6032 if (x == y) return Smi::FromInt(EQUAL);
6033 if (isless(x, y)) return Smi::FromInt(LESS);
6034 return Smi::FromInt(GREATER);
6035}
6036
6037
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006038// Compare two Smis as if they were converted to strings and then
6039// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006040static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006041 NoHandleAllocation ha;
6042 ASSERT(args.length() == 2);
6043
6044 // Arrays for the individual characters of the two Smis. Smis are
6045 // 31 bit integers and 10 decimal digits are therefore enough.
6046 static int x_elms[10];
6047 static int y_elms[10];
6048
6049 // Extract the integer values from the Smis.
6050 CONVERT_CHECKED(Smi, x, args[0]);
6051 CONVERT_CHECKED(Smi, y, args[1]);
6052 int x_value = x->value();
6053 int y_value = y->value();
6054
6055 // If the integers are equal so are the string representations.
6056 if (x_value == y_value) return Smi::FromInt(EQUAL);
6057
6058 // If one of the integers are zero the normal integer order is the
6059 // same as the lexicographic order of the string representations.
6060 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6061
ager@chromium.org32912102009-01-16 10:38:43 +00006062 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006063 // smallest because the char code of '-' is less than the char code
6064 // of any digit. Otherwise, we make both values positive.
6065 if (x_value < 0 || y_value < 0) {
6066 if (y_value >= 0) return Smi::FromInt(LESS);
6067 if (x_value >= 0) return Smi::FromInt(GREATER);
6068 x_value = -x_value;
6069 y_value = -y_value;
6070 }
6071
6072 // Convert the integers to arrays of their decimal digits.
6073 int x_index = 0;
6074 int y_index = 0;
6075 while (x_value > 0) {
6076 x_elms[x_index++] = x_value % 10;
6077 x_value /= 10;
6078 }
6079 while (y_value > 0) {
6080 y_elms[y_index++] = y_value % 10;
6081 y_value /= 10;
6082 }
6083
6084 // Loop through the arrays of decimal digits finding the first place
6085 // where they differ.
6086 while (--x_index >= 0 && --y_index >= 0) {
6087 int diff = x_elms[x_index] - y_elms[y_index];
6088 if (diff != 0) return Smi::FromInt(diff);
6089 }
6090
6091 // If one array is a suffix of the other array, the longest array is
6092 // the representation of the largest of the Smis in the
6093 // lexicographic ordering.
6094 return Smi::FromInt(x_index - y_index);
6095}
6096
6097
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006098static Object* StringInputBufferCompare(String* x, String* y) {
6099 static StringInputBuffer bufx;
6100 static StringInputBuffer bufy;
6101 bufx.Reset(x);
6102 bufy.Reset(y);
6103 while (bufx.has_more() && bufy.has_more()) {
6104 int d = bufx.GetNext() - bufy.GetNext();
6105 if (d < 0) return Smi::FromInt(LESS);
6106 else if (d > 0) return Smi::FromInt(GREATER);
6107 }
6108
6109 // x is (non-trivial) prefix of y:
6110 if (bufy.has_more()) return Smi::FromInt(LESS);
6111 // y is prefix of x:
6112 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6113}
6114
6115
6116static Object* FlatStringCompare(String* x, String* y) {
6117 ASSERT(x->IsFlat());
6118 ASSERT(y->IsFlat());
6119 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6120 int prefix_length = x->length();
6121 if (y->length() < prefix_length) {
6122 prefix_length = y->length();
6123 equal_prefix_result = Smi::FromInt(GREATER);
6124 } else if (y->length() > prefix_length) {
6125 equal_prefix_result = Smi::FromInt(LESS);
6126 }
6127 int r;
6128 if (x->IsAsciiRepresentation()) {
6129 Vector<const char> x_chars = x->ToAsciiVector();
6130 if (y->IsAsciiRepresentation()) {
6131 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006132 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006133 } else {
6134 Vector<const uc16> y_chars = y->ToUC16Vector();
6135 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6136 }
6137 } else {
6138 Vector<const uc16> x_chars = x->ToUC16Vector();
6139 if (y->IsAsciiRepresentation()) {
6140 Vector<const char> y_chars = y->ToAsciiVector();
6141 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6142 } else {
6143 Vector<const uc16> y_chars = y->ToUC16Vector();
6144 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6145 }
6146 }
6147 Object* result;
6148 if (r == 0) {
6149 result = equal_prefix_result;
6150 } else {
6151 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6152 }
6153 ASSERT(result == StringInputBufferCompare(x, y));
6154 return result;
6155}
6156
6157
lrn@chromium.org303ada72010-10-27 09:33:13 +00006158static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006159 NoHandleAllocation ha;
6160 ASSERT(args.length() == 2);
6161
6162 CONVERT_CHECKED(String, x, args[0]);
6163 CONVERT_CHECKED(String, y, args[1]);
6164
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006165 Counters::string_compare_runtime.Increment();
6166
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006167 // A few fast case tests before we flatten.
6168 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006169 if (y->length() == 0) {
6170 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006171 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006172 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006173 return Smi::FromInt(LESS);
6174 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006175
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006176 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006177 if (d < 0) return Smi::FromInt(LESS);
6178 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006179
lrn@chromium.org303ada72010-10-27 09:33:13 +00006180 Object* obj;
6181 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
6182 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6183 }
6184 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
6185 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6186 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006187
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006188 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
6189 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006190}
6191
6192
lrn@chromium.org303ada72010-10-27 09:33:13 +00006193static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006194 NoHandleAllocation ha;
6195 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006196 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197
6198 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006199 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006200}
6201
6202
lrn@chromium.org303ada72010-10-27 09:33:13 +00006203static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006204 NoHandleAllocation ha;
6205 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006206 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006207
6208 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006209 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006210}
6211
6212
lrn@chromium.org303ada72010-10-27 09:33:13 +00006213static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006214 NoHandleAllocation ha;
6215 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006216 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006217
6218 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006219 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220}
6221
6222
lrn@chromium.org303ada72010-10-27 09:33:13 +00006223static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006224 NoHandleAllocation ha;
6225 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006226 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006227
6228 CONVERT_DOUBLE_CHECKED(x, args[0]);
6229 CONVERT_DOUBLE_CHECKED(y, args[1]);
6230 double result;
6231 if (isinf(x) && isinf(y)) {
6232 // Make sure that the result in case of two infinite arguments
6233 // is a multiple of Pi / 4. The sign of the result is determined
6234 // by the first argument (x) and the sign of the second argument
6235 // determines the multiplier: one or three.
6236 static double kPiDividedBy4 = 0.78539816339744830962;
6237 int multiplier = (x < 0) ? -1 : 1;
6238 if (y < 0) multiplier *= 3;
6239 result = multiplier * kPiDividedBy4;
6240 } else {
6241 result = atan2(x, y);
6242 }
6243 return Heap::AllocateHeapNumber(result);
6244}
6245
6246
lrn@chromium.org303ada72010-10-27 09:33:13 +00006247static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006248 NoHandleAllocation ha;
6249 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006250 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006251
6252 CONVERT_DOUBLE_CHECKED(x, args[0]);
6253 return Heap::NumberFromDouble(ceiling(x));
6254}
6255
6256
lrn@chromium.org303ada72010-10-27 09:33:13 +00006257static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006258 NoHandleAllocation ha;
6259 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006260 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006261
6262 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006263 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006264}
6265
6266
lrn@chromium.org303ada72010-10-27 09:33:13 +00006267static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268 NoHandleAllocation ha;
6269 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006270 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006271
6272 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006273 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006274}
6275
6276
lrn@chromium.org303ada72010-10-27 09:33:13 +00006277static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006278 NoHandleAllocation ha;
6279 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006280 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006281
6282 CONVERT_DOUBLE_CHECKED(x, args[0]);
6283 return Heap::NumberFromDouble(floor(x));
6284}
6285
6286
lrn@chromium.org303ada72010-10-27 09:33:13 +00006287static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006288 NoHandleAllocation ha;
6289 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006290 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006291
6292 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006293 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006294}
6295
6296
lrn@chromium.org303ada72010-10-27 09:33:13 +00006297static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006298 NoHandleAllocation ha;
6299 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006300 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006301
6302 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006303
6304 // If the second argument is a smi, it is much faster to call the
6305 // custom powi() function than the generic pow().
6306 if (args[1]->IsSmi()) {
6307 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006308 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006309 }
6310
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006311 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006312 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006313}
6314
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006315// Fast version of Math.pow if we know that y is not an integer and
6316// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006317static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006318 NoHandleAllocation ha;
6319 ASSERT(args.length() == 2);
6320 CONVERT_DOUBLE_CHECKED(x, args[0]);
6321 CONVERT_DOUBLE_CHECKED(y, args[1]);
6322 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006323 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006324 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006325 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006326 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006327 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006328 }
6329}
6330
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006331
lrn@chromium.org303ada72010-10-27 09:33:13 +00006332static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006333 NoHandleAllocation ha;
6334 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006335 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006336
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006337 if (!args[0]->IsHeapNumber()) {
6338 // Must be smi. Return the argument unchanged for all the other types
6339 // to make fuzz-natives test happy.
6340 return args[0];
6341 }
6342
6343 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6344
6345 double value = number->value();
6346 int exponent = number->get_exponent();
6347 int sign = number->get_sign();
6348
6349 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6350 // should be rounded to 2^30, which is not smi.
6351 if (!sign && exponent <= kSmiValueSize - 3) {
6352 return Smi::FromInt(static_cast<int>(value + 0.5));
6353 }
6354
6355 // If the magnitude is big enough, there's no place for fraction part. If we
6356 // try to add 0.5 to this number, 1.0 will be added instead.
6357 if (exponent >= 52) {
6358 return number;
6359 }
6360
6361 if (sign && value >= -0.5) return Heap::minus_zero_value();
6362
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006363 // Do not call NumberFromDouble() to avoid extra checks.
6364 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006365}
6366
6367
lrn@chromium.org303ada72010-10-27 09:33:13 +00006368static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006369 NoHandleAllocation ha;
6370 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006371 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006372
6373 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006374 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006375}
6376
6377
lrn@chromium.org303ada72010-10-27 09:33:13 +00006378static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006379 NoHandleAllocation ha;
6380 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006381 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006382
6383 CONVERT_DOUBLE_CHECKED(x, args[0]);
6384 return Heap::AllocateHeapNumber(sqrt(x));
6385}
6386
6387
lrn@chromium.org303ada72010-10-27 09:33:13 +00006388static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006389 NoHandleAllocation ha;
6390 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006391 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006392
6393 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006394 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006395}
6396
6397
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006398static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006399 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6400 181, 212, 243, 273, 304, 334};
6401 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6402 182, 213, 244, 274, 305, 335};
6403
6404 year += month / 12;
6405 month %= 12;
6406 if (month < 0) {
6407 year--;
6408 month += 12;
6409 }
6410
6411 ASSERT(month >= 0);
6412 ASSERT(month < 12);
6413
6414 // year_delta is an arbitrary number such that:
6415 // a) year_delta = -1 (mod 400)
6416 // b) year + year_delta > 0 for years in the range defined by
6417 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6418 // Jan 1 1970. This is required so that we don't run into integer
6419 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006420 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006421 // operations.
6422 static const int year_delta = 399999;
6423 static const int base_day = 365 * (1970 + year_delta) +
6424 (1970 + year_delta) / 4 -
6425 (1970 + year_delta) / 100 +
6426 (1970 + year_delta) / 400;
6427
6428 int year1 = year + year_delta;
6429 int day_from_year = 365 * year1 +
6430 year1 / 4 -
6431 year1 / 100 +
6432 year1 / 400 -
6433 base_day;
6434
6435 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006436 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006437 }
6438
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006439 return day_from_year + day_from_month_leap[month] + day - 1;
6440}
6441
6442
lrn@chromium.org303ada72010-10-27 09:33:13 +00006443static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006444 NoHandleAllocation ha;
6445 ASSERT(args.length() == 3);
6446
6447 CONVERT_SMI_CHECKED(year, args[0]);
6448 CONVERT_SMI_CHECKED(month, args[1]);
6449 CONVERT_SMI_CHECKED(date, args[2]);
6450
6451 return Smi::FromInt(MakeDay(year, month, date));
6452}
6453
6454
6455static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6456static const int kDaysIn4Years = 4 * 365 + 1;
6457static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6458static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6459static const int kDays1970to2000 = 30 * 365 + 7;
6460static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6461 kDays1970to2000;
6462static const int kYearsOffset = 400000;
6463
6464static const char kDayInYear[] = {
6465 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6466 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6467 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6468 22, 23, 24, 25, 26, 27, 28,
6469 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6470 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6471 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6472 22, 23, 24, 25, 26, 27, 28, 29, 30,
6473 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6474 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6475 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6476 22, 23, 24, 25, 26, 27, 28, 29, 30,
6477 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6478 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6479 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6480 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6481 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6482 22, 23, 24, 25, 26, 27, 28, 29, 30,
6483 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6484 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6485 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6486 22, 23, 24, 25, 26, 27, 28, 29, 30,
6487 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6488 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6489
6490 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6491 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6492 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6493 22, 23, 24, 25, 26, 27, 28,
6494 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6495 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6496 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6497 22, 23, 24, 25, 26, 27, 28, 29, 30,
6498 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6499 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6500 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6501 22, 23, 24, 25, 26, 27, 28, 29, 30,
6502 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6503 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6504 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6505 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6506 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6507 22, 23, 24, 25, 26, 27, 28, 29, 30,
6508 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6509 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6510 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6511 22, 23, 24, 25, 26, 27, 28, 29, 30,
6512 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6513 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6514
6515 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6516 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6517 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6518 22, 23, 24, 25, 26, 27, 28, 29,
6519 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6520 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6521 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6522 22, 23, 24, 25, 26, 27, 28, 29, 30,
6523 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6524 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6525 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6526 22, 23, 24, 25, 26, 27, 28, 29, 30,
6527 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6528 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6529 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6530 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6531 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6532 22, 23, 24, 25, 26, 27, 28, 29, 30,
6533 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6534 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6535 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6536 22, 23, 24, 25, 26, 27, 28, 29, 30,
6537 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6538 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6539
6540 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6541 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6542 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6543 22, 23, 24, 25, 26, 27, 28,
6544 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6545 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6546 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6547 22, 23, 24, 25, 26, 27, 28, 29, 30,
6548 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6549 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6550 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6551 22, 23, 24, 25, 26, 27, 28, 29, 30,
6552 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6553 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6554 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6555 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6556 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6557 22, 23, 24, 25, 26, 27, 28, 29, 30,
6558 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6559 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6560 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6561 22, 23, 24, 25, 26, 27, 28, 29, 30,
6562 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6563 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6564
6565static const char kMonthInYear[] = {
6566 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6567 0, 0, 0, 0, 0, 0,
6568 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6569 1, 1, 1,
6570 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6571 2, 2, 2, 2, 2, 2,
6572 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6573 3, 3, 3, 3, 3,
6574 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6575 4, 4, 4, 4, 4, 4,
6576 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6577 5, 5, 5, 5, 5,
6578 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6579 6, 6, 6, 6, 6, 6,
6580 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6581 7, 7, 7, 7, 7, 7,
6582 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6583 8, 8, 8, 8, 8,
6584 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6585 9, 9, 9, 9, 9, 9,
6586 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6587 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6588 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6589 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6590
6591 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6592 0, 0, 0, 0, 0, 0,
6593 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6594 1, 1, 1,
6595 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6596 2, 2, 2, 2, 2, 2,
6597 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6598 3, 3, 3, 3, 3,
6599 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6600 4, 4, 4, 4, 4, 4,
6601 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6602 5, 5, 5, 5, 5,
6603 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6604 6, 6, 6, 6, 6, 6,
6605 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6606 7, 7, 7, 7, 7, 7,
6607 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6608 8, 8, 8, 8, 8,
6609 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6610 9, 9, 9, 9, 9, 9,
6611 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6612 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6613 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6614 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6615
6616 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6617 0, 0, 0, 0, 0, 0,
6618 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6619 1, 1, 1, 1,
6620 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6621 2, 2, 2, 2, 2, 2,
6622 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6623 3, 3, 3, 3, 3,
6624 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6625 4, 4, 4, 4, 4, 4,
6626 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6627 5, 5, 5, 5, 5,
6628 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6629 6, 6, 6, 6, 6, 6,
6630 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6631 7, 7, 7, 7, 7, 7,
6632 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6633 8, 8, 8, 8, 8,
6634 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6635 9, 9, 9, 9, 9, 9,
6636 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6637 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6638 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6639 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6640
6641 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6642 0, 0, 0, 0, 0, 0,
6643 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6644 1, 1, 1,
6645 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6646 2, 2, 2, 2, 2, 2,
6647 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6648 3, 3, 3, 3, 3,
6649 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6650 4, 4, 4, 4, 4, 4,
6651 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6652 5, 5, 5, 5, 5,
6653 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6654 6, 6, 6, 6, 6, 6,
6655 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6656 7, 7, 7, 7, 7, 7,
6657 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6658 8, 8, 8, 8, 8,
6659 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6660 9, 9, 9, 9, 9, 9,
6661 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6662 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6663 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6664 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6665
6666
6667// This function works for dates from 1970 to 2099.
6668static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006669 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006670#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006671 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006672#endif
6673
6674 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6675 date %= kDaysIn4Years;
6676
6677 month = kMonthInYear[date];
6678 day = kDayInYear[date];
6679
6680 ASSERT(MakeDay(year, month, day) == save_date);
6681}
6682
6683
6684static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006685 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006686#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006687 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006688#endif
6689
6690 date += kDaysOffset;
6691 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6692 date %= kDaysIn400Years;
6693
6694 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6695
6696 date--;
6697 int yd1 = date / kDaysIn100Years;
6698 date %= kDaysIn100Years;
6699 year += 100 * yd1;
6700
6701 date++;
6702 int yd2 = date / kDaysIn4Years;
6703 date %= kDaysIn4Years;
6704 year += 4 * yd2;
6705
6706 date--;
6707 int yd3 = date / 365;
6708 date %= 365;
6709 year += yd3;
6710
6711 bool is_leap = (!yd1 || yd2) && !yd3;
6712
6713 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006714 ASSERT(is_leap || (date >= 0));
6715 ASSERT((date < 365) || (is_leap && (date < 366)));
6716 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6717 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6718 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006719
6720 if (is_leap) {
6721 day = kDayInYear[2*365 + 1 + date];
6722 month = kMonthInYear[2*365 + 1 + date];
6723 } else {
6724 day = kDayInYear[date];
6725 month = kMonthInYear[date];
6726 }
6727
6728 ASSERT(MakeDay(year, month, day) == save_date);
6729}
6730
6731
6732static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006733 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006734 if (date >= 0 && date < 32 * kDaysIn4Years) {
6735 DateYMDFromTimeAfter1970(date, year, month, day);
6736 } else {
6737 DateYMDFromTimeSlow(date, year, month, day);
6738 }
6739}
6740
6741
lrn@chromium.org303ada72010-10-27 09:33:13 +00006742static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006743 NoHandleAllocation ha;
6744 ASSERT(args.length() == 2);
6745
6746 CONVERT_DOUBLE_CHECKED(t, args[0]);
6747 CONVERT_CHECKED(JSArray, res_array, args[1]);
6748
6749 int year, month, day;
6750 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6751
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006752 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6753 FixedArray* elms = FixedArray::cast(res_array->elements());
6754 RUNTIME_ASSERT(elms->length() == 3);
6755
6756 elms->set(0, Smi::FromInt(year));
6757 elms->set(1, Smi::FromInt(month));
6758 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006759
6760 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006761}
6762
6763
lrn@chromium.org303ada72010-10-27 09:33:13 +00006764static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006765 NoHandleAllocation ha;
6766 ASSERT(args.length() == 3);
6767
6768 JSFunction* callee = JSFunction::cast(args[0]);
6769 Object** parameters = reinterpret_cast<Object**>(args[1]);
6770 const int length = Smi::cast(args[2])->value();
6771
lrn@chromium.org303ada72010-10-27 09:33:13 +00006772 Object* result;
6773 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6774 if (!maybe_result->ToObject(&result)) return maybe_result;
6775 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006776 // Allocate the elements if needed.
6777 if (length > 0) {
6778 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006779 Object* obj;
6780 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6781 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6782 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006783
6784 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006785 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6786 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006787 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006788
6789 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006790 for (int i = 0; i < length; i++) {
6791 array->set(i, *--parameters, mode);
6792 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006793 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006794 }
6795 return result;
6796}
6797
6798
lrn@chromium.org303ada72010-10-27 09:33:13 +00006799static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006801 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006802 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006803 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006804 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006806 // Allocate global closures in old space and allocate local closures
6807 // in new space. Additionally pretenure closures that are assigned
6808 // directly to properties.
6809 pretenure = pretenure || (context->global_context() == *context);
6810 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006812 Factory::NewFunctionFromSharedFunctionInfo(shared,
6813 context,
6814 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815 return *result;
6816}
6817
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006818
lrn@chromium.org303ada72010-10-27 09:33:13 +00006819static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006820 HandleScope scope;
6821 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006822 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006823 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006824
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006825 // Second argument is either null or an array of bound arguments.
6826 FixedArray* bound_args = NULL;
6827 int bound_argc = 0;
6828 if (!args[1]->IsNull()) {
6829 CONVERT_ARG_CHECKED(JSArray, params, 1);
6830 RUNTIME_ASSERT(params->HasFastElements());
6831 bound_args = FixedArray::cast(params->elements());
6832 bound_argc = Smi::cast(params->length())->value();
6833 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006834
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006835 // Find frame containing arguments passed to the caller.
6836 JavaScriptFrameIterator it;
6837 JavaScriptFrame* frame = it.frame();
6838 ASSERT(!frame->is_optimized());
6839 it.AdvanceToArgumentsFrame();
6840 frame = it.frame();
6841 int argc = frame->GetProvidedParametersCount();
6842
6843 // Prepend bound arguments to caller's arguments.
6844 int total_argc = bound_argc + argc;
6845 SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
6846 for (int i = 0; i < bound_argc; i++) {
6847 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006848 param_data[i] = val.location();
6849 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006850 for (int i = 0; i < argc; i++) {
6851 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
6852 param_data[bound_argc + i] = val.location();
6853 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006854
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006855 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006856 Handle<Object> result =
6857 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006858 if (exception) {
6859 return Failure::Exception();
6860 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006861
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006862 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006863 return *result;
6864}
6865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006866
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006867static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006868 Handle<Object> prototype = Factory::null_value();
6869 if (function->has_instance_prototype()) {
6870 prototype = Handle<Object>(function->instance_prototype());
6871 }
6872 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006873 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006874 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006875 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006876 function->shared()->set_construct_stub(
6877 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006878 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006879 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006880}
6881
6882
lrn@chromium.org303ada72010-10-27 09:33:13 +00006883static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006884 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006885 ASSERT(args.length() == 1);
6886
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006887 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006888
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006889 // If the constructor isn't a proper function we throw a type error.
6890 if (!constructor->IsJSFunction()) {
6891 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6892 Handle<Object> type_error =
6893 Factory::NewTypeError("not_constructor", arguments);
6894 return Top::Throw(*type_error);
6895 }
6896
6897 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006898
6899 // If function should not have prototype, construction is not allowed. In this
6900 // case generated code bailouts here, since function has no initial_map.
6901 if (!function->should_have_prototype()) {
6902 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6903 Handle<Object> type_error =
6904 Factory::NewTypeError("not_constructor", arguments);
6905 return Top::Throw(*type_error);
6906 }
6907
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006908#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006909 // Handle stepping into constructors if step into is active.
6910 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006911 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006912 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006913#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006914
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006915 if (function->has_initial_map()) {
6916 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006917 // The 'Function' function ignores the receiver object when
6918 // called using 'new' and creates a new JSFunction object that
6919 // is returned. The receiver object is only used for error
6920 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006921 // JSFunction. Factory::NewJSObject() should not be used to
6922 // allocate JSFunctions since it does not properly initialize
6923 // the shared part of the function. Since the receiver is
6924 // ignored anyway, we use the global object as the receiver
6925 // instead of a new JSFunction object. This way, errors are
6926 // reported the same way whether or not 'Function' is called
6927 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006928 return Top::context()->global();
6929 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006930 }
6931
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006932 // The function should be compiled for the optimization hints to be
6933 // available. We cannot use EnsureCompiled because that forces a
6934 // compilation through the shared function info which makes it
6935 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006936 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006937 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006938
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006939 if (!function->has_initial_map() &&
6940 shared->IsInobjectSlackTrackingInProgress()) {
6941 // The tracking is already in progress for another function. We can only
6942 // track one initial_map at a time, so we force the completion before the
6943 // function is called as a constructor for the first time.
6944 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006945 }
6946
6947 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006948 Handle<JSObject> result = Factory::NewJSObject(function);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006949 RETURN_IF_EMPTY_HANDLE(result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006950 // Delay setting the stub if inobject slack tracking is in progress.
6951 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6952 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006953 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006954
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006955 Counters::constructed_objects.Increment();
6956 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006957
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006958 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006959}
6960
6961
lrn@chromium.org303ada72010-10-27 09:33:13 +00006962static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006963 HandleScope scope;
6964 ASSERT(args.length() == 1);
6965
6966 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6967 function->shared()->CompleteInobjectSlackTracking();
6968 TrySettingInlineConstructStub(function);
6969
6970 return Heap::undefined_value();
6971}
6972
6973
lrn@chromium.org303ada72010-10-27 09:33:13 +00006974static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006975 HandleScope scope;
6976 ASSERT(args.length() == 1);
6977
6978 Handle<JSFunction> function = args.at<JSFunction>(0);
6979#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006980 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006982 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006983 PrintF("]\n");
6984 }
6985#endif
6986
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006987 // Compile the target function. Here we compile using CompileLazyInLoop in
6988 // order to get the optimized version. This helps code like delta-blue
6989 // that calls performance-critical routines through constructors. A
6990 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6991 // direct call. Since the in-loop tracking takes place through CallICs
6992 // this means that things called through constructors are never known to
6993 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006994 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006995 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006996 return Failure::Exception();
6997 }
6998
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006999 // All done. Return the compiled code.
7000 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001 return function->code();
7002}
7003
7004
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007005static MaybeObject* Runtime_LazyRecompile(Arguments args) {
7006 HandleScope scope;
7007 ASSERT(args.length() == 1);
7008 Handle<JSFunction> function = args.at<JSFunction>(0);
7009 // If the function is not optimizable or debugger is active continue using the
7010 // code from the full compiler.
7011 if (!function->shared()->code()->optimizable() ||
7012 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007013 if (FLAG_trace_opt) {
7014 PrintF("[failed to optimize ");
7015 function->PrintName();
7016 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7017 function->shared()->code()->optimizable() ? "T" : "F",
7018 Debug::has_break_points() ? "T" : "F");
7019 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007020 function->ReplaceCode(function->shared()->code());
7021 return function->code();
7022 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007023 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007024 return function->code();
7025 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007026 if (FLAG_trace_opt) {
7027 PrintF("[failed to optimize ");
7028 function->PrintName();
7029 PrintF(": optimized compilation failed]\n");
7030 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007031 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007032 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007033}
7034
7035
7036static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
7037 HandleScope scope;
7038 ASSERT(args.length() == 1);
7039 RUNTIME_ASSERT(args[0]->IsSmi());
7040 Deoptimizer::BailoutType type =
7041 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
7042 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7043 ASSERT(Heap::IsAllocationAllowed());
7044 int frames = deoptimizer->output_count();
7045
7046 JavaScriptFrameIterator it;
7047 JavaScriptFrame* frame = NULL;
7048 for (int i = 0; i < frames; i++) {
7049 if (i != 0) it.Advance();
7050 frame = it.frame();
7051 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
7052 }
7053 delete deoptimizer;
7054
7055 RUNTIME_ASSERT(frame->function()->IsJSFunction());
7056 Handle<JSFunction> function(JSFunction::cast(frame->function()));
7057 Handle<Object> arguments;
7058 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00007059 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007060 if (arguments.is_null()) {
7061 // FunctionGetArguments can't throw an exception, so cast away the
7062 // doubt with an assert.
7063 arguments = Handle<Object>(
7064 Accessors::FunctionGetArguments(*function,
7065 NULL)->ToObjectUnchecked());
7066 ASSERT(*arguments != Heap::null_value());
7067 ASSERT(*arguments != Heap::undefined_value());
7068 }
7069 frame->SetExpression(i, *arguments);
7070 }
7071 }
7072
7073 CompilationCache::MarkForLazyOptimizing(function);
7074 if (type == Deoptimizer::EAGER) {
7075 RUNTIME_ASSERT(function->IsOptimized());
7076 } else {
7077 RUNTIME_ASSERT(!function->IsOptimized());
7078 }
7079
7080 // Avoid doing too much work when running with --always-opt and keep
7081 // the optimized code around.
7082 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
7083 return Heap::undefined_value();
7084 }
7085
7086 // Count the number of optimized activations of the function.
7087 int activations = 0;
7088 while (!it.done()) {
7089 JavaScriptFrame* frame = it.frame();
7090 if (frame->is_optimized() && frame->function() == *function) {
7091 activations++;
7092 }
7093 it.Advance();
7094 }
7095
7096 // TODO(kasperl): For now, we cannot support removing the optimized
7097 // code when we have recursive invocations of the same function.
7098 if (activations == 0) {
7099 if (FLAG_trace_deopt) {
7100 PrintF("[removing optimized code for: ");
7101 function->PrintName();
7102 PrintF("]\n");
7103 }
7104 function->ReplaceCode(function->shared()->code());
7105 }
7106 return Heap::undefined_value();
7107}
7108
7109
7110static MaybeObject* Runtime_NotifyOSR(Arguments args) {
7111 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7112 delete deoptimizer;
7113 return Heap::undefined_value();
7114}
7115
7116
7117static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
7118 HandleScope scope;
7119 ASSERT(args.length() == 1);
7120 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7121 if (!function->IsOptimized()) return Heap::undefined_value();
7122
7123 Deoptimizer::DeoptimizeFunction(*function);
7124
7125 return Heap::undefined_value();
7126}
7127
7128
7129static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
7130 HandleScope scope;
7131 ASSERT(args.length() == 1);
7132 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7133
7134 // We're not prepared to handle a function with arguments object.
7135 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7136
7137 // We have hit a back edge in an unoptimized frame for a function that was
7138 // selected for on-stack replacement. Find the unoptimized code object.
7139 Handle<Code> unoptimized(function->shared()->code());
7140 // Keep track of whether we've succeeded in optimizing.
7141 bool succeeded = unoptimized->optimizable();
7142 if (succeeded) {
7143 // If we are trying to do OSR when there are already optimized
7144 // activations of the function, it means (a) the function is directly or
7145 // indirectly recursive and (b) an optimized invocation has been
7146 // deoptimized so that we are currently in an unoptimized activation.
7147 // Check for optimized activations of this function.
7148 JavaScriptFrameIterator it;
7149 while (succeeded && !it.done()) {
7150 JavaScriptFrame* frame = it.frame();
7151 succeeded = !frame->is_optimized() || frame->function() != *function;
7152 it.Advance();
7153 }
7154 }
7155
7156 int ast_id = AstNode::kNoNumber;
7157 if (succeeded) {
7158 // The top JS function is this one, the PC is somewhere in the
7159 // unoptimized code.
7160 JavaScriptFrameIterator it;
7161 JavaScriptFrame* frame = it.frame();
7162 ASSERT(frame->function() == *function);
7163 ASSERT(frame->code() == *unoptimized);
7164 ASSERT(unoptimized->contains(frame->pc()));
7165
7166 // Use linear search of the unoptimized code's stack check table to find
7167 // the AST id matching the PC.
7168 Address start = unoptimized->instruction_start();
7169 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007170 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007171 uint32_t table_length = Memory::uint32_at(table_cursor);
7172 table_cursor += kIntSize;
7173 for (unsigned i = 0; i < table_length; ++i) {
7174 // Table entries are (AST id, pc offset) pairs.
7175 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7176 if (pc_offset == target_pc_offset) {
7177 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7178 break;
7179 }
7180 table_cursor += 2 * kIntSize;
7181 }
7182 ASSERT(ast_id != AstNode::kNoNumber);
7183 if (FLAG_trace_osr) {
7184 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7185 function->PrintName();
7186 PrintF("]\n");
7187 }
7188
7189 // Try to compile the optimized code. A true return value from
7190 // CompileOptimized means that compilation succeeded, not necessarily
7191 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007192 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7193 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007194 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7195 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007196 if (data->OsrPcOffset()->value() >= 0) {
7197 if (FLAG_trace_osr) {
7198 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007199 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007200 }
7201 ASSERT(data->OsrAstId()->value() == ast_id);
7202 } else {
7203 // We may never generate the desired OSR entry if we emit an
7204 // early deoptimize.
7205 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007206 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007207 } else {
7208 succeeded = false;
7209 }
7210 }
7211
7212 // Revert to the original stack checks in the original unoptimized code.
7213 if (FLAG_trace_osr) {
7214 PrintF("[restoring original stack checks in ");
7215 function->PrintName();
7216 PrintF("]\n");
7217 }
7218 StackCheckStub check_stub;
7219 Handle<Code> check_code = check_stub.GetCode();
7220 Handle<Code> replacement_code(
7221 Builtins::builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007222 Deoptimizer::RevertStackCheckCode(*unoptimized,
7223 *check_code,
7224 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007225
7226 // Allow OSR only at nesting level zero again.
7227 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7228
7229 // If the optimization attempt succeeded, return the AST id tagged as a
7230 // smi. This tells the builtin that we need to translate the unoptimized
7231 // frame to an optimized one.
7232 if (succeeded) {
7233 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7234 return Smi::FromInt(ast_id);
7235 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007236 if (function->IsMarkedForLazyRecompilation()) {
7237 function->ReplaceCode(function->shared()->code());
7238 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007239 return Smi::FromInt(-1);
7240 }
7241}
7242
7243
lrn@chromium.org303ada72010-10-27 09:33:13 +00007244static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007245 HandleScope scope;
7246 ASSERT(args.length() == 1);
7247 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7248 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7249}
7250
7251
lrn@chromium.org303ada72010-10-27 09:33:13 +00007252static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007253 HandleScope scope;
7254 ASSERT(args.length() == 1);
7255 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7256 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7257}
7258
7259
lrn@chromium.org303ada72010-10-27 09:33:13 +00007260static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007261 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007262 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007263
kasper.lund7276f142008-07-30 08:49:36 +00007264 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007265 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007266 Object* result;
7267 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
7268 if (!maybe_result->ToObject(&result)) return maybe_result;
7269 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007270
7271 Top::set_context(Context::cast(result));
7272
kasper.lund7276f142008-07-30 08:49:36 +00007273 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007274}
7275
lrn@chromium.org303ada72010-10-27 09:33:13 +00007276
7277MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
7278 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007279 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007280 Object* js_object = object;
7281 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007282 MaybeObject* maybe_js_object = js_object->ToObject();
7283 if (!maybe_js_object->ToObject(&js_object)) {
7284 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7285 return maybe_js_object;
7286 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007287 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007288 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007289 Handle<Object> result =
7290 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7291 return Top::Throw(*result);
7292 }
7293 }
7294
lrn@chromium.org303ada72010-10-27 09:33:13 +00007295 Object* result;
7296 { MaybeObject* maybe_result =
7297 Heap::AllocateWithContext(Top::context(),
7298 JSObject::cast(js_object),
7299 is_catch_context);
7300 if (!maybe_result->ToObject(&result)) return maybe_result;
7301 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007302
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007303 Context* context = Context::cast(result);
7304 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007305
kasper.lund7276f142008-07-30 08:49:36 +00007306 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307}
7308
7309
lrn@chromium.org303ada72010-10-27 09:33:13 +00007310static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007311 NoHandleAllocation ha;
7312 ASSERT(args.length() == 1);
7313 return PushContextHelper(args[0], false);
7314}
7315
7316
lrn@chromium.org303ada72010-10-27 09:33:13 +00007317static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007318 NoHandleAllocation ha;
7319 ASSERT(args.length() == 1);
7320 return PushContextHelper(args[0], true);
7321}
7322
7323
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007324static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007325 HandleScope scope;
7326 ASSERT(args.length() == 2);
7327
7328 CONVERT_ARG_CHECKED(Context, context, 0);
7329 CONVERT_ARG_CHECKED(String, name, 1);
7330
7331 int index;
7332 PropertyAttributes attributes;
7333 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007334 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007335
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007336 // If the slot was not found the result is true.
7337 if (holder.is_null()) {
7338 return Heap::true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339 }
7340
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007341 // If the slot was found in a context, it should be DONT_DELETE.
7342 if (holder->IsContext()) {
7343 return Heap::false_value();
7344 }
7345
7346 // The slot was found in a JSObject, either a context extension object,
7347 // the global object, or an arguments object. Try to delete it
7348 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7349 // which allows deleting all parameters in functions that mention
7350 // 'arguments', we do this even for the case of slots found on an
7351 // arguments object. The slot was found on an arguments object if the
7352 // index is non-negative.
7353 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7354 if (index >= 0) {
7355 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7356 } else {
7357 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7358 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007359}
7360
7361
ager@chromium.orga1645e22009-09-09 19:27:10 +00007362// A mechanism to return a pair of Object pointers in registers (if possible).
7363// How this is achieved is calling convention-dependent.
7364// All currently supported x86 compiles uses calling conventions that are cdecl
7365// variants where a 64-bit value is returned in two 32-bit registers
7366// (edx:eax on ia32, r1:r0 on ARM).
7367// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7368// In Win64 calling convention, a struct of two pointers is returned in memory,
7369// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007370#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007371struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007372 MaybeObject* x;
7373 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007374};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007375
lrn@chromium.org303ada72010-10-27 09:33:13 +00007376static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007377 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007378 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7379 // In Win64 they are assigned to a hidden first argument.
7380 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007381}
7382#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007383typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007384static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007386 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007388#endif
7389
7390
lrn@chromium.org303ada72010-10-27 09:33:13 +00007391static inline MaybeObject* Unhole(MaybeObject* x,
7392 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7394 USE(attributes);
7395 return x->IsTheHole() ? Heap::undefined_value() : x;
7396}
7397
7398
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007399static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7400 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007401 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007402 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007403 JSFunction* context_extension_function =
7404 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007405 // If the holder isn't a context extension object, we just return it
7406 // as the receiver. This allows arguments objects to be used as
7407 // receivers, but only if they are put in the context scope chain
7408 // explicitly via a with-statement.
7409 Object* constructor = holder->map()->constructor();
7410 if (constructor != context_extension_function) return holder;
7411 // Fall back to using the global object as the receiver if the
7412 // property turns out to be a local variable allocated in a context
7413 // extension object - introduced via eval.
7414 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007415}
7416
7417
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007418static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007419 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007420 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007421
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007422 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007423 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007424 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007426 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427
7428 int index;
7429 PropertyAttributes attributes;
7430 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007431 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007432
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007433 // If the index is non-negative, the slot has been found in a local
7434 // variable or a parameter. Read it from the context object or the
7435 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007436 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007437 // If the "property" we were looking for is a local variable or an
7438 // argument in a context, the receiver is the global object; see
7439 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7440 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007441 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007442 ? Context::cast(*holder)->get(index)
7443 : JSObject::cast(*holder)->GetElement(index);
7444 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007445 }
7446
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007447 // If the holder is found, we read the property from it.
7448 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007449 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007450 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007451 JSObject* receiver;
7452 if (object->IsGlobalObject()) {
7453 receiver = GlobalObject::cast(object)->global_receiver();
7454 } else if (context->is_exception_holder(*holder)) {
7455 receiver = Top::context()->global()->global_receiver();
7456 } else {
7457 receiver = ComputeReceiverForNonGlobal(object);
7458 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007459 // No need to unhole the value here. This is taken care of by the
7460 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007461 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007462 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007463 }
7464
7465 if (throw_error) {
7466 // The property doesn't exist - throw exception.
7467 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007468 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007469 return MakePair(Top::Throw(*reference_error), NULL);
7470 } else {
7471 // The property doesn't exist - return undefined
7472 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7473 }
7474}
7475
7476
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007477static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007478 return LoadContextSlotHelper(args, true);
7479}
7480
7481
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007482static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007483 return LoadContextSlotHelper(args, false);
7484}
7485
7486
lrn@chromium.org303ada72010-10-27 09:33:13 +00007487static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007488 HandleScope scope;
7489 ASSERT(args.length() == 3);
7490
7491 Handle<Object> value(args[0]);
7492 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007493 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007494
7495 int index;
7496 PropertyAttributes attributes;
7497 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007498 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007499
7500 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007501 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007502 // Ignore if read_only variable.
7503 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007504 // Context is a fixed array and set cannot fail.
7505 Context::cast(*holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007506 }
7507 } else {
7508 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007509 Handle<Object> result =
7510 SetElement(Handle<JSObject>::cast(holder), index, value);
7511 if (result.is_null()) {
7512 ASSERT(Top::has_pending_exception());
7513 return Failure::Exception();
7514 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007515 }
7516 return *value;
7517 }
7518
7519 // Slow case: The property is not in a FixedArray context.
7520 // It is either in an JSObject extension context or it was not found.
7521 Handle<JSObject> context_ext;
7522
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007523 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007524 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007525 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007526 } else {
7527 // The property was not found. It needs to be stored in the global context.
7528 ASSERT(attributes == ABSENT);
7529 attributes = NONE;
7530 context_ext = Handle<JSObject>(Top::context()->global());
7531 }
7532
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007533 // Set the property, but ignore if read_only variable on the context
7534 // extension object itself.
7535 if ((attributes & READ_ONLY) == 0 ||
7536 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007537 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, NONE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007538 }
7539 return *value;
7540}
7541
7542
lrn@chromium.org303ada72010-10-27 09:33:13 +00007543static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007544 HandleScope scope;
7545 ASSERT(args.length() == 1);
7546
7547 return Top::Throw(args[0]);
7548}
7549
7550
lrn@chromium.org303ada72010-10-27 09:33:13 +00007551static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007552 HandleScope scope;
7553 ASSERT(args.length() == 1);
7554
7555 return Top::ReThrow(args[0]);
7556}
7557
7558
lrn@chromium.org303ada72010-10-27 09:33:13 +00007559static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007560 ASSERT_EQ(0, args.length());
7561 return Top::PromoteScheduledException();
7562}
7563
7564
lrn@chromium.org303ada72010-10-27 09:33:13 +00007565static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007566 HandleScope scope;
7567 ASSERT(args.length() == 1);
7568
7569 Handle<Object> name(args[0]);
7570 Handle<Object> reference_error =
7571 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7572 return Top::Throw(*reference_error);
7573}
7574
7575
lrn@chromium.org303ada72010-10-27 09:33:13 +00007576static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007577 NoHandleAllocation na;
7578 return Top::StackOverflow();
7579}
7580
7581
lrn@chromium.org303ada72010-10-27 09:33:13 +00007582static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007583 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007584
7585 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007586 if (StackGuard::IsStackOverflow()) {
7587 return Runtime_StackOverflow(args);
7588 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007589
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007590 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007591}
7592
7593
7594// NOTE: These PrintXXX functions are defined for all builds (not just
7595// DEBUG builds) because we may want to be able to trace function
7596// calls in all modes.
7597static void PrintString(String* str) {
7598 // not uncommon to have empty strings
7599 if (str->length() > 0) {
7600 SmartPointer<char> s =
7601 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7602 PrintF("%s", *s);
7603 }
7604}
7605
7606
7607static void PrintObject(Object* obj) {
7608 if (obj->IsSmi()) {
7609 PrintF("%d", Smi::cast(obj)->value());
7610 } else if (obj->IsString() || obj->IsSymbol()) {
7611 PrintString(String::cast(obj));
7612 } else if (obj->IsNumber()) {
7613 PrintF("%g", obj->Number());
7614 } else if (obj->IsFailure()) {
7615 PrintF("<failure>");
7616 } else if (obj->IsUndefined()) {
7617 PrintF("<undefined>");
7618 } else if (obj->IsNull()) {
7619 PrintF("<null>");
7620 } else if (obj->IsTrue()) {
7621 PrintF("<true>");
7622 } else if (obj->IsFalse()) {
7623 PrintF("<false>");
7624 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007625 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007626 }
7627}
7628
7629
7630static int StackSize() {
7631 int n = 0;
7632 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7633 return n;
7634}
7635
7636
7637static void PrintTransition(Object* result) {
7638 // indentation
7639 { const int nmax = 80;
7640 int n = StackSize();
7641 if (n <= nmax)
7642 PrintF("%4d:%*s", n, n, "");
7643 else
7644 PrintF("%4d:%*s", n, nmax, "...");
7645 }
7646
7647 if (result == NULL) {
7648 // constructor calls
7649 JavaScriptFrameIterator it;
7650 JavaScriptFrame* frame = it.frame();
7651 if (frame->IsConstructor()) PrintF("new ");
7652 // function name
7653 Object* fun = frame->function();
7654 if (fun->IsJSFunction()) {
7655 PrintObject(JSFunction::cast(fun)->shared()->name());
7656 } else {
7657 PrintObject(fun);
7658 }
7659 // function arguments
7660 // (we are intentionally only printing the actually
7661 // supplied parameters, not all parameters required)
7662 PrintF("(this=");
7663 PrintObject(frame->receiver());
7664 const int length = frame->GetProvidedParametersCount();
7665 for (int i = 0; i < length; i++) {
7666 PrintF(", ");
7667 PrintObject(frame->GetParameter(i));
7668 }
7669 PrintF(") {\n");
7670
7671 } else {
7672 // function result
7673 PrintF("} -> ");
7674 PrintObject(result);
7675 PrintF("\n");
7676 }
7677}
7678
7679
lrn@chromium.org303ada72010-10-27 09:33:13 +00007680static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007681 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007682 NoHandleAllocation ha;
7683 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007684 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007685}
7686
7687
lrn@chromium.org303ada72010-10-27 09:33:13 +00007688static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007689 NoHandleAllocation ha;
7690 PrintTransition(args[0]);
7691 return args[0]; // return TOS
7692}
7693
7694
lrn@chromium.org303ada72010-10-27 09:33:13 +00007695static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007696 NoHandleAllocation ha;
7697 ASSERT(args.length() == 1);
7698
7699#ifdef DEBUG
7700 if (args[0]->IsString()) {
7701 // If we have a string, assume it's a code "marker"
7702 // and print some interesting cpu debugging info.
7703 JavaScriptFrameIterator it;
7704 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007705 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7706 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007707 } else {
7708 PrintF("DebugPrint: ");
7709 }
7710 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007711 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007712 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007713 HeapObject::cast(args[0])->map()->Print();
7714 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007715#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007716 // ShortPrint is available in release mode. Print is not.
7717 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007718#endif
7719 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007720 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007721
7722 return args[0]; // return TOS
7723}
7724
7725
lrn@chromium.org303ada72010-10-27 09:33:13 +00007726static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007727 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007728 NoHandleAllocation ha;
7729 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007730 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731}
7732
7733
lrn@chromium.org303ada72010-10-27 09:33:13 +00007734static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007735 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007736 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007737
7738 // According to ECMA-262, section 15.9.1, page 117, the precision of
7739 // the number in a Date object representing a particular instant in
7740 // time is milliseconds. Therefore, we floor the result of getting
7741 // the OS time.
7742 double millis = floor(OS::TimeCurrentMillis());
7743 return Heap::NumberFromDouble(millis);
7744}
7745
7746
lrn@chromium.org303ada72010-10-27 09:33:13 +00007747static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007749 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007750
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007751 CONVERT_ARG_CHECKED(String, str, 0);
7752 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007753
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007754 CONVERT_ARG_CHECKED(JSArray, output, 1);
7755 RUNTIME_ASSERT(output->HasFastElements());
7756
7757 AssertNoAllocation no_allocation;
7758
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007759 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007760 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7761 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007762 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007763 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007764 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007765 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007766 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7767 }
7768
7769 if (result) {
7770 return *output;
7771 } else {
7772 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007773 }
7774}
7775
7776
lrn@chromium.org303ada72010-10-27 09:33:13 +00007777static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007778 NoHandleAllocation ha;
7779 ASSERT(args.length() == 1);
7780
7781 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007782 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007783 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7784}
7785
7786
lrn@chromium.org303ada72010-10-27 09:33:13 +00007787static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007788 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007789 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007790
7791 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7792}
7793
7794
lrn@chromium.org303ada72010-10-27 09:33:13 +00007795static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007796 NoHandleAllocation ha;
7797 ASSERT(args.length() == 1);
7798
7799 CONVERT_DOUBLE_CHECKED(x, args[0]);
7800 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7801}
7802
7803
lrn@chromium.org303ada72010-10-27 09:33:13 +00007804static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007805 ASSERT(args.length() == 1);
7806 Object* global = args[0];
7807 if (!global->IsJSGlobalObject()) return Heap::null_value();
7808 return JSGlobalObject::cast(global)->global_receiver();
7809}
7810
7811
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007812static MaybeObject* Runtime_ParseJson(Arguments args) {
7813 HandleScope scope;
7814 ASSERT_EQ(1, args.length());
7815 CONVERT_ARG_CHECKED(String, source, 0);
7816
7817 Handle<Object> result = JsonParser::Parse(source);
7818 if (result.is_null()) {
7819 // Syntax error or stack overflow in scanner.
7820 ASSERT(Top::has_pending_exception());
7821 return Failure::Exception();
7822 }
7823 return *result;
7824}
7825
7826
lrn@chromium.org303ada72010-10-27 09:33:13 +00007827static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007828 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007829 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007830 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007831
ager@chromium.org381abbb2009-02-25 13:23:22 +00007832 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007833 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007834 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7835 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007836 true,
7837 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007838 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007839 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007840 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007841 return *fun;
7842}
7843
7844
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007845static ObjectPair CompileGlobalEval(Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007846 Handle<Object> receiver,
7847 StrictModeFlag mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007848 // Deal with a normal eval call with a string argument. Compile it
7849 // and return the compiled function bound in the local context.
7850 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7851 source,
7852 Handle<Context>(Top::context()),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007853 Top::context()->IsGlobalContext(),
7854 mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007855 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7856 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7857 shared,
7858 Handle<Context>(Top::context()),
7859 NOT_TENURED);
7860 return MakePair(*compiled, *receiver);
7861}
7862
7863
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007864static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007865 ASSERT(args.length() == 4);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007866 if (!args[0]->IsJSFunction()) {
7867 return MakePair(Top::ThrowIllegalOperation(), NULL);
7868 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007869
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007870 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007871 Handle<JSFunction> callee = args.at<JSFunction>(0);
7872 Handle<Object> receiver; // Will be overwritten.
7873
7874 // Compute the calling context.
7875 Handle<Context> context = Handle<Context>(Top::context());
7876#ifdef DEBUG
7877 // Make sure Top::context() agrees with the old code that traversed
7878 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007879 StackFrameLocator locator;
7880 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007881 ASSERT(Context::cast(frame->context()) == *context);
7882#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007883
7884 // Find where the 'eval' symbol is bound. It is unaliased only if
7885 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007886 int index = -1;
7887 PropertyAttributes attributes = ABSENT;
7888 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007889 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7890 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007891 // Stop search when eval is found or when the global context is
7892 // reached.
7893 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007894 if (context->is_function_context()) {
7895 context = Handle<Context>(Context::cast(context->closure()->context()));
7896 } else {
7897 context = Handle<Context>(context->previous());
7898 }
7899 }
7900
iposva@chromium.org245aa852009-02-10 00:49:54 +00007901 // If eval could not be resolved, it has been deleted and we need to
7902 // throw a reference error.
7903 if (attributes == ABSENT) {
7904 Handle<Object> name = Factory::eval_symbol();
7905 Handle<Object> reference_error =
7906 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007907 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007908 }
7909
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007910 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007911 // 'eval' is not bound in the global context. Just call the function
7912 // with the given arguments. This is not necessarily the global eval.
7913 if (receiver->IsContext()) {
7914 context = Handle<Context>::cast(receiver);
7915 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007916 } else if (receiver->IsJSContextExtensionObject()) {
7917 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007918 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007919 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007920 }
7921
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007922 // 'eval' is bound in the global context, but it may have been overwritten.
7923 // Compare it to the builtin 'GlobalEval' function to make sure.
7924 if (*callee != Top::global_context()->global_eval_fun() ||
7925 !args[1]->IsString()) {
7926 return MakePair(*callee, Top::context()->global()->global_receiver());
7927 }
7928
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007929 ASSERT(args[3]->IsSmi());
7930 return CompileGlobalEval(args.at<String>(1),
7931 args.at<Object>(2),
7932 static_cast<StrictModeFlag>(
7933 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007934}
7935
7936
7937static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007938 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007939 if (!args[0]->IsJSFunction()) {
7940 return MakePair(Top::ThrowIllegalOperation(), NULL);
7941 }
7942
7943 HandleScope scope;
7944 Handle<JSFunction> callee = args.at<JSFunction>(0);
7945
7946 // 'eval' is bound in the global context, but it may have been overwritten.
7947 // Compare it to the builtin 'GlobalEval' function to make sure.
7948 if (*callee != Top::global_context()->global_eval_fun() ||
7949 !args[1]->IsString()) {
7950 return MakePair(*callee, Top::context()->global()->global_receiver());
7951 }
7952
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007953 ASSERT(args[3]->IsSmi());
7954 return CompileGlobalEval(args.at<String>(1),
7955 args.at<Object>(2),
7956 static_cast<StrictModeFlag>(
7957 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007958}
7959
7960
lrn@chromium.org303ada72010-10-27 09:33:13 +00007961static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007962 // This utility adjusts the property attributes for newly created Function
7963 // object ("new Function(...)") by changing the map.
7964 // All it does is changing the prototype property to enumerable
7965 // as specified in ECMA262, 15.3.5.2.
7966 HandleScope scope;
7967 ASSERT(args.length() == 1);
7968 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7969 ASSERT(func->map()->instance_type() ==
7970 Top::function_instance_map()->instance_type());
7971 ASSERT(func->map()->instance_size() ==
7972 Top::function_instance_map()->instance_size());
7973 func->set_map(*Top::function_instance_map());
7974 return *func;
7975}
7976
7977
lrn@chromium.org303ada72010-10-27 09:33:13 +00007978static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007979 // Allocate a block of memory in NewSpace (filled with a filler).
7980 // Use as fallback for allocation in generated code when NewSpace
7981 // is full.
7982 ASSERT(args.length() == 1);
7983 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7984 int size = size_smi->value();
7985 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7986 RUNTIME_ASSERT(size > 0);
7987 static const int kMinFreeNewSpaceAfterGC =
7988 Heap::InitialSemiSpaceSize() * 3/4;
7989 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007990 Object* allocation;
7991 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7992 if (maybe_allocation->ToObject(&allocation)) {
7993 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7994 }
7995 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007996 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007997}
7998
7999
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008000// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008001// array. Returns true if the element was pushed on the stack and
8002// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008003static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008004 ASSERT(args.length() == 2);
8005 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008006 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008007 RUNTIME_ASSERT(array->HasFastElements());
8008 int length = Smi::cast(array->length())->value();
8009 FixedArray* elements = FixedArray::cast(array->elements());
8010 for (int i = 0; i < length; i++) {
8011 if (elements->get(i) == element) return Heap::false_value();
8012 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008013 Object* obj;
8014 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
8015 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8016 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008017 return Heap::true_value();
8018}
8019
8020
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008021/**
8022 * A simple visitor visits every element of Array's.
8023 * The backend storage can be a fixed array for fast elements case,
8024 * or a dictionary for sparse array. Since Dictionary is a subtype
8025 * of FixedArray, the class can be used by both fast and slow cases.
8026 * The second parameter of the constructor, fast_elements, specifies
8027 * whether the storage is a FixedArray or Dictionary.
8028 *
8029 * An index limit is used to deal with the situation that a result array
8030 * length overflows 32-bit non-negative integer.
8031 */
8032class ArrayConcatVisitor {
8033 public:
8034 ArrayConcatVisitor(Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008035 bool fast_elements) :
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008036 storage_(storage),
8037 index_offset_(0u),
8038 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008039
8040 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008041 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008042 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008043
8044 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008045 if (index < static_cast<uint32_t>(storage_->length())) {
8046 storage_->set(index, *elm);
8047 return;
8048 }
8049 // Our initial estimate of length was foiled, possibly by
8050 // getters on the arrays increasing the length of later arrays
8051 // during iteration.
8052 // This shouldn't happen in anything but pathological cases.
8053 SetDictionaryMode(index);
8054 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008055 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008056 ASSERT(!fast_elements_);
8057 Handle<NumberDictionary> dict(storage_.cast<NumberDictionary>());
8058 Handle<NumberDictionary> result =
8059 Factory::DictionaryAtNumberPut(dict, index, elm);
8060 if (!result.is_identical_to(dict)) {
8061 storage_ = Handle<FixedArray>::cast(result);
8062 }
8063}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008064
8065 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008066 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8067 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008068 } else {
8069 index_offset_ += delta;
8070 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008071 }
8072
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008073 Handle<JSArray> ToArray() {
8074 Handle<JSArray> array = Factory::NewJSArray(0);
8075 Handle<Object> length =
8076 Factory::NewNumber(static_cast<double>(index_offset_));
8077 Handle<Map> map;
8078 if (fast_elements_) {
8079 map = Factory::GetFastElementsMap(Handle<Map>(array->map()));
8080 } else {
8081 map = Factory::GetSlowElementsMap(Handle<Map>(array->map()));
8082 }
8083 array->set_map(*map);
8084 array->set_length(*length);
8085 array->set_elements(*storage_);
8086 return array;
8087 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008088
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008089 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008090 // Convert storage to dictionary mode.
8091 void SetDictionaryMode(uint32_t index) {
8092 ASSERT(fast_elements_);
8093 Handle<FixedArray> current_storage(storage_.ToHandle());
8094 HandleCell<NumberDictionary> slow_storage(
8095 Factory::NewNumberDictionary(current_storage->length()));
8096 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8097 for (uint32_t i = 0; i < current_length; i++) {
8098 HandleScope loop_scope;
8099 Handle<Object> element(current_storage->get(i));
8100 if (!element->IsTheHole()) {
8101 slow_storage =
8102 Factory::DictionaryAtNumberPut(slow_storage.ToHandle(), i, element);
8103 }
8104 }
8105 storage_ = slow_storage.cast<FixedArray>();
8106 fast_elements_ = false;
8107 }
8108
8109 HandleCell<FixedArray> storage_;
8110 // Index after last seen index. Always less than or equal to
8111 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008112 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008113 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008114};
8115
8116
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008117static uint32_t EstimateElementCount(Handle<JSArray> array) {
8118 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8119 int element_count = 0;
8120 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008121 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008122 // Fast elements can't have lengths that are not representable by
8123 // a 32-bit signed integer.
8124 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8125 int fast_length = static_cast<int>(length);
8126 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8127 for (int i = 0; i < fast_length; i++) {
8128 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008129 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008130 break;
8131 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008132 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008133 Handle<NumberDictionary> dictionary(
8134 NumberDictionary::cast(array->elements()));
8135 int capacity = dictionary->Capacity();
8136 for (int i = 0; i < capacity; i++) {
8137 Handle<Object> key(dictionary->KeyAt(i));
8138 if (dictionary->IsKey(*key)) {
8139 element_count++;
8140 }
8141 }
8142 break;
8143 }
8144 default:
8145 // External arrays are always dense.
8146 return length;
8147 }
8148 // As an estimate, we assume that the prototype doesn't contain any
8149 // inherited elements.
8150 return element_count;
8151}
8152
8153
8154
8155template<class ExternalArrayClass, class ElementType>
8156static void IterateExternalArrayElements(Handle<JSObject> receiver,
8157 bool elements_are_ints,
8158 bool elements_are_guaranteed_smis,
8159 ArrayConcatVisitor* visitor) {
8160 Handle<ExternalArrayClass> array(
8161 ExternalArrayClass::cast(receiver->elements()));
8162 uint32_t len = static_cast<uint32_t>(array->length());
8163
8164 ASSERT(visitor != NULL);
8165 if (elements_are_ints) {
8166 if (elements_are_guaranteed_smis) {
8167 for (uint32_t j = 0; j < len; j++) {
8168 HandleScope loop_scope;
8169 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8170 visitor->visit(j, e);
8171 }
8172 } else {
8173 for (uint32_t j = 0; j < len; j++) {
8174 HandleScope loop_scope;
8175 int64_t val = static_cast<int64_t>(array->get(j));
8176 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8177 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8178 visitor->visit(j, e);
8179 } else {
8180 Handle<Object> e =
8181 Factory::NewNumber(static_cast<ElementType>(val));
8182 visitor->visit(j, e);
8183 }
8184 }
8185 }
8186 } else {
8187 for (uint32_t j = 0; j < len; j++) {
8188 HandleScope loop_scope;
8189 Handle<Object> e = Factory::NewNumber(array->get(j));
8190 visitor->visit(j, e);
8191 }
8192 }
8193}
8194
8195
8196// Used for sorting indices in a List<uint32_t>.
8197static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8198 uint32_t a = *ap;
8199 uint32_t b = *bp;
8200 return (a == b) ? 0 : (a < b) ? -1 : 1;
8201}
8202
8203
8204static void CollectElementIndices(Handle<JSObject> object,
8205 uint32_t range,
8206 List<uint32_t>* indices) {
8207 JSObject::ElementsKind kind = object->GetElementsKind();
8208 switch (kind) {
8209 case JSObject::FAST_ELEMENTS: {
8210 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8211 uint32_t length = static_cast<uint32_t>(elements->length());
8212 if (range < length) length = range;
8213 for (uint32_t i = 0; i < length; i++) {
8214 if (!elements->get(i)->IsTheHole()) {
8215 indices->Add(i);
8216 }
8217 }
8218 break;
8219 }
8220 case JSObject::DICTIONARY_ELEMENTS: {
8221 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008222 uint32_t capacity = dict->Capacity();
8223 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008224 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008225 Handle<Object> k(dict->KeyAt(j));
8226 if (dict->IsKey(*k)) {
8227 ASSERT(k->IsNumber());
8228 uint32_t index = static_cast<uint32_t>(k->Number());
8229 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008230 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008231 }
8232 }
8233 }
8234 break;
8235 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008236 default: {
8237 int dense_elements_length;
8238 switch (kind) {
8239 case JSObject::PIXEL_ELEMENTS: {
8240 dense_elements_length =
8241 PixelArray::cast(object->elements())->length();
8242 break;
8243 }
8244 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8245 dense_elements_length =
8246 ExternalByteArray::cast(object->elements())->length();
8247 break;
8248 }
8249 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8250 dense_elements_length =
8251 ExternalUnsignedByteArray::cast(object->elements())->length();
8252 break;
8253 }
8254 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8255 dense_elements_length =
8256 ExternalShortArray::cast(object->elements())->length();
8257 break;
8258 }
8259 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8260 dense_elements_length =
8261 ExternalUnsignedShortArray::cast(object->elements())->length();
8262 break;
8263 }
8264 case JSObject::EXTERNAL_INT_ELEMENTS: {
8265 dense_elements_length =
8266 ExternalIntArray::cast(object->elements())->length();
8267 break;
8268 }
8269 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8270 dense_elements_length =
8271 ExternalUnsignedIntArray::cast(object->elements())->length();
8272 break;
8273 }
8274 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8275 dense_elements_length =
8276 ExternalFloatArray::cast(object->elements())->length();
8277 break;
8278 }
8279 default:
8280 UNREACHABLE();
8281 dense_elements_length = 0;
8282 break;
8283 }
8284 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8285 if (range <= length) {
8286 length = range;
8287 // We will add all indices, so we might as well clear it first
8288 // and avoid duplicates.
8289 indices->Clear();
8290 }
8291 for (uint32_t i = 0; i < length; i++) {
8292 indices->Add(i);
8293 }
8294 if (length == range) return; // All indices accounted for already.
8295 break;
8296 }
8297 }
8298
8299 Handle<Object> prototype(object->GetPrototype());
8300 if (prototype->IsJSObject()) {
8301 // The prototype will usually have no inherited element indices,
8302 // but we have to check.
8303 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8304 }
8305}
8306
8307
8308/**
8309 * A helper function that visits elements of a JSArray in numerical
8310 * order.
8311 *
8312 * The visitor argument called for each existing element in the array
8313 * with the element index and the element's value.
8314 * Afterwards it increments the base-index of the visitor by the array
8315 * length.
8316 */
8317static void IterateElements(Handle<JSArray> receiver,
8318 ArrayConcatVisitor* visitor) {
8319 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8320 switch (receiver->GetElementsKind()) {
8321 case JSObject::FAST_ELEMENTS: {
8322 // Run through the elements FixedArray and use HasElement and GetElement
8323 // to check the prototype for missing elements.
8324 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8325 int fast_length = static_cast<int>(length);
8326 ASSERT(fast_length <= elements->length());
8327 for (int j = 0; j < fast_length; j++) {
8328 HandleScope loop_scope;
8329 Handle<Object> element_value(elements->get(j));
8330 if (!element_value->IsTheHole()) {
8331 visitor->visit(j, element_value);
8332 } else if (receiver->HasElement(j)) {
8333 // Call GetElement on receiver, not its prototype, or getters won't
8334 // have the correct receiver.
8335 element_value = GetElement(receiver, j);
8336 visitor->visit(j, element_value);
8337 }
8338 }
8339 break;
8340 }
8341 case JSObject::DICTIONARY_ELEMENTS: {
8342 Handle<NumberDictionary> dict(receiver->element_dictionary());
8343 List<uint32_t> indices(dict->Capacity() / 2);
8344 // Collect all indices in the object and the prototypes less
8345 // than length. This might introduce duplicates in the indices list.
8346 CollectElementIndices(receiver, length, &indices);
8347 indices.Sort(&compareUInt32);
8348 int j = 0;
8349 int n = indices.length();
8350 while (j < n) {
8351 HandleScope loop_scope;
8352 uint32_t index = indices[j];
8353 Handle<Object> element = GetElement(receiver, index);
8354 visitor->visit(index, element);
8355 // Skip to next different index (i.e., omit duplicates).
8356 do {
8357 j++;
8358 } while (j < n && indices[j] == index);
8359 }
8360 break;
8361 }
8362 case JSObject::PIXEL_ELEMENTS: {
8363 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8364 for (uint32_t j = 0; j < length; j++) {
8365 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8366 visitor->visit(j, e);
8367 }
8368 break;
8369 }
8370 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8371 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8372 receiver, true, true, visitor);
8373 break;
8374 }
8375 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8376 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8377 receiver, true, true, visitor);
8378 break;
8379 }
8380 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8381 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8382 receiver, true, true, visitor);
8383 break;
8384 }
8385 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8386 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8387 receiver, true, true, visitor);
8388 break;
8389 }
8390 case JSObject::EXTERNAL_INT_ELEMENTS: {
8391 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8392 receiver, true, false, visitor);
8393 break;
8394 }
8395 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8396 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8397 receiver, true, false, visitor);
8398 break;
8399 }
8400 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8401 IterateExternalArrayElements<ExternalFloatArray, float>(
8402 receiver, false, false, visitor);
8403 break;
8404 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008405 default:
8406 UNREACHABLE();
8407 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008408 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008409 visitor->increase_index_offset(length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008410}
8411
8412
8413/**
8414 * Array::concat implementation.
8415 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008416 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008417 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008418 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008419static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008420 ASSERT(args.length() == 1);
8421 HandleScope handle_scope;
8422
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008423 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8424 int argument_count = static_cast<int>(arguments->length()->Number());
8425 RUNTIME_ASSERT(arguments->HasFastElements());
8426 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008427
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008428 // Pass 1: estimate the length and number of elements of the result.
8429 // The actual length can be larger if any of the arguments have getters
8430 // that mutate other arguments (but will otherwise be precise).
8431 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008432
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008433 uint32_t estimate_result_length = 0;
8434 uint32_t estimate_nof_elements = 0;
8435 {
8436 for (int i = 0; i < argument_count; i++) {
8437 HandleScope loop_scope;
8438 Handle<Object> obj(elements->get(i));
8439 uint32_t length_estimate;
8440 uint32_t element_estimate;
8441 if (obj->IsJSArray()) {
8442 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8443 length_estimate =
8444 static_cast<uint32_t>(array->length()->Number());
8445 element_estimate =
8446 EstimateElementCount(array);
8447 } else {
8448 length_estimate = 1;
8449 element_estimate = 1;
8450 }
8451 // Avoid overflows by capping at kMaxElementCount.
8452 if (JSObject::kMaxElementCount - estimate_result_length <
8453 length_estimate) {
8454 estimate_result_length = JSObject::kMaxElementCount;
8455 } else {
8456 estimate_result_length += length_estimate;
8457 }
8458 if (JSObject::kMaxElementCount - estimate_nof_elements <
8459 element_estimate) {
8460 estimate_nof_elements = JSObject::kMaxElementCount;
8461 } else {
8462 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008463 }
8464 }
8465 }
8466
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008467 // If estimated number of elements is more than half of length, a
8468 // fixed array (fast case) is more time and space-efficient than a
8469 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008470 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008471
8472 Handle<FixedArray> storage;
8473 if (fast_case) {
8474 // The backing storage array must have non-existing elements to
8475 // preserve holes across concat operations.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008476 storage = Factory::NewFixedArrayWithHoles(estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008477 } else {
8478 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8479 uint32_t at_least_space_for = estimate_nof_elements +
8480 (estimate_nof_elements >> 2);
8481 storage = Handle<FixedArray>::cast(
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008482 Factory::NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008483 }
8484
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008485 ArrayConcatVisitor visitor(storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008486
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008487 for (int i = 0; i < argument_count; i++) {
8488 Handle<Object> obj(elements->get(i));
8489 if (obj->IsJSArray()) {
8490 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8491 IterateElements(array, &visitor);
8492 } else {
8493 visitor.visit(0, obj);
8494 visitor.increase_index_offset(1);
8495 }
8496 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008497
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008498 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008499}
8500
8501
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008502// This will not allocate (flatten the string), but it may run
8503// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008504static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008505 NoHandleAllocation ha;
8506 ASSERT(args.length() == 1);
8507
8508 CONVERT_CHECKED(String, string, args[0]);
8509 StringInputBuffer buffer(string);
8510 while (buffer.has_more()) {
8511 uint16_t character = buffer.GetNext();
8512 PrintF("%c", character);
8513 }
8514 return string;
8515}
8516
ager@chromium.org5ec48922009-05-05 07:25:34 +00008517// Moves all own elements of an object, that are below a limit, to positions
8518// starting at zero. All undefined values are placed after non-undefined values,
8519// and are followed by non-existing element. Does not change the length
8520// property.
8521// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008522static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008523 ASSERT(args.length() == 2);
8524 CONVERT_CHECKED(JSObject, object, args[0]);
8525 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8526 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008527}
8528
8529
8530// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008531static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008532 ASSERT(args.length() == 2);
8533 CONVERT_CHECKED(JSArray, from, args[0]);
8534 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008535 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008536 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008537 if (new_elements->map() == Heap::fixed_array_map() ||
8538 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008539 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008540 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008541 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008542 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008543 Object* new_map;
8544 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008545 to->set_map(Map::cast(new_map));
8546 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008547 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008548 Object* obj;
8549 { MaybeObject* maybe_obj = from->ResetElements();
8550 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8551 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008552 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008553 return to;
8554}
8555
8556
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008557// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008558static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008559 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008560 CONVERT_CHECKED(JSObject, object, args[0]);
8561 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008562 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008563 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008564 } else if (object->IsJSArray()) {
8565 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008566 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008567 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008568 }
8569}
8570
8571
lrn@chromium.org303ada72010-10-27 09:33:13 +00008572static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008573 HandleScope handle_scope;
8574
8575 ASSERT_EQ(3, args.length());
8576
ager@chromium.orgac091b72010-05-05 07:34:42 +00008577 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008578 Handle<Object> key1 = args.at<Object>(1);
8579 Handle<Object> key2 = args.at<Object>(2);
8580
8581 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008582 if (!key1->ToArrayIndex(&index1)
8583 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008584 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008585 }
8586
ager@chromium.orgac091b72010-05-05 07:34:42 +00008587 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8588 Handle<Object> tmp1 = GetElement(jsobject, index1);
8589 Handle<Object> tmp2 = GetElement(jsobject, index2);
8590
8591 SetElement(jsobject, index1, tmp2);
8592 SetElement(jsobject, index2, tmp1);
8593
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008594 return Heap::undefined_value();
8595}
8596
8597
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008598// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008599// might have elements. Can either return keys (positive integers) or
8600// intervals (pair of a negative integer (-start-1) followed by a
8601// positive (length)) or undefined values.
8602// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008603static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008604 ASSERT(args.length() == 2);
8605 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008606 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008607 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008608 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008609 // Create an array and get all the keys into it, then remove all the
8610 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008611 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008612 int keys_length = keys->length();
8613 for (int i = 0; i < keys_length; i++) {
8614 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008615 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008616 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008617 // Zap invalid keys.
8618 keys->set_undefined(i);
8619 }
8620 }
8621 return *Factory::NewJSArrayWithElements(keys);
8622 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008623 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008624 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8625 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008626 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008627 uint32_t actual_length =
8628 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008629 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008630 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008631 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008632 single_interval->set(1, *length_object);
8633 return *Factory::NewJSArrayWithElements(single_interval);
8634 }
8635}
8636
8637
8638// DefineAccessor takes an optional final argument which is the
8639// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8640// to the way accessors are implemented, it is set for both the getter
8641// and setter on the first call to DefineAccessor and ignored on
8642// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008643static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008644 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8645 // Compute attributes.
8646 PropertyAttributes attributes = NONE;
8647 if (args.length() == 5) {
8648 CONVERT_CHECKED(Smi, attrs, args[4]);
8649 int value = attrs->value();
8650 // Only attribute bits should be set.
8651 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8652 attributes = static_cast<PropertyAttributes>(value);
8653 }
8654
8655 CONVERT_CHECKED(JSObject, obj, args[0]);
8656 CONVERT_CHECKED(String, name, args[1]);
8657 CONVERT_CHECKED(Smi, flag, args[2]);
8658 CONVERT_CHECKED(JSFunction, fun, args[3]);
8659 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8660}
8661
8662
lrn@chromium.org303ada72010-10-27 09:33:13 +00008663static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008664 ASSERT(args.length() == 3);
8665 CONVERT_CHECKED(JSObject, obj, args[0]);
8666 CONVERT_CHECKED(String, name, args[1]);
8667 CONVERT_CHECKED(Smi, flag, args[2]);
8668 return obj->LookupAccessor(name, flag->value() == 0);
8669}
8670
8671
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008672#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008673static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008674 ASSERT(args.length() == 0);
8675 return Execution::DebugBreakHelper();
8676}
8677
8678
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008679// Helper functions for wrapping and unwrapping stack frame ids.
8680static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008681 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008682 return Smi::FromInt(id >> 2);
8683}
8684
8685
8686static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8687 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8688}
8689
8690
8691// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008692// args[0]: debug event listener function to set or null or undefined for
8693// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008694// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008695static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008696 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008697 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8698 args[0]->IsUndefined() ||
8699 args[0]->IsNull());
8700 Handle<Object> callback = args.at<Object>(0);
8701 Handle<Object> data = args.at<Object>(1);
8702 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008703
8704 return Heap::undefined_value();
8705}
8706
8707
lrn@chromium.org303ada72010-10-27 09:33:13 +00008708static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008709 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008710 StackGuard::DebugBreak();
8711 return Heap::undefined_value();
8712}
8713
8714
lrn@chromium.org303ada72010-10-27 09:33:13 +00008715static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8716 LookupResult* result,
8717 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008718 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008719 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008720 case NORMAL:
8721 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008722 if (value->IsTheHole()) {
8723 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008724 }
8725 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008726 case FIELD:
8727 value =
8728 JSObject::cast(
8729 result->holder())->FastPropertyAt(result->GetFieldIndex());
8730 if (value->IsTheHole()) {
8731 return Heap::undefined_value();
8732 }
8733 return value;
8734 case CONSTANT_FUNCTION:
8735 return result->GetConstantFunction();
8736 case CALLBACKS: {
8737 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008738 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008739 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008740 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008741 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008742 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008743 ASSERT(maybe_value->IsException());
8744 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008745 Top::clear_pending_exception();
8746 if (caught_exception != NULL) {
8747 *caught_exception = true;
8748 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008749 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008750 }
8751 return value;
8752 } else {
8753 return Heap::undefined_value();
8754 }
8755 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008756 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008757 case MAP_TRANSITION:
8758 case CONSTANT_TRANSITION:
8759 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008760 return Heap::undefined_value();
8761 default:
8762 UNREACHABLE();
8763 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008764 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008765 return Heap::undefined_value();
8766}
8767
8768
ager@chromium.org32912102009-01-16 10:38:43 +00008769// Get debugger related details for an object property.
8770// args[0]: object holding property
8771// args[1]: name of the property
8772//
8773// The array returned contains the following information:
8774// 0: Property value
8775// 1: Property details
8776// 2: Property value is exception
8777// 3: Getter function if defined
8778// 4: Setter function if defined
8779// Items 2-4 are only filled if the property has either a getter or a setter
8780// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008781static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008782 HandleScope scope;
8783
8784 ASSERT(args.length() == 2);
8785
8786 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8787 CONVERT_ARG_CHECKED(String, name, 1);
8788
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008789 // Make sure to set the current context to the context before the debugger was
8790 // entered (if the debugger is entered). The reason for switching context here
8791 // is that for some property lookups (accessors and interceptors) callbacks
8792 // into the embedding application can occour, and the embedding application
8793 // could have the assumption that its own global context is the current
8794 // context and not some internal debugger context.
8795 SaveContext save;
8796 if (Debug::InDebugger()) {
8797 Top::set_context(*Debug::debugger_entry()->GetContext());
8798 }
8799
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008800 // Skip the global proxy as it has no properties and always delegates to the
8801 // real global object.
8802 if (obj->IsJSGlobalProxy()) {
8803 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8804 }
8805
8806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008807 // Check if the name is trivially convertible to an index and get the element
8808 // if so.
8809 uint32_t index;
8810 if (name->AsArrayIndex(&index)) {
8811 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008812 Object* element_or_char;
8813 { MaybeObject* maybe_element_or_char =
8814 Runtime::GetElementOrCharAt(obj, index);
8815 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8816 return maybe_element_or_char;
8817 }
8818 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008819 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008820 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8821 return *Factory::NewJSArrayWithElements(details);
8822 }
8823
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008824 // Find the number of objects making up this.
8825 int length = LocalPrototypeChainLength(*obj);
8826
8827 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008828 Handle<JSObject> jsproto = obj;
8829 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008830 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008831 jsproto->LocalLookup(*name, &result);
8832 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008833 // LookupResult is not GC safe as it holds raw object pointers.
8834 // GC can happen later in this code so put the required fields into
8835 // local variables using handles when required for later use.
8836 PropertyType result_type = result.type();
8837 Handle<Object> result_callback_obj;
8838 if (result_type == CALLBACKS) {
8839 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8840 }
8841 Smi* property_details = result.GetPropertyDetails().AsSmi();
8842 // DebugLookupResultValue can cause GC so details from LookupResult needs
8843 // to be copied to handles before this.
8844 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008845 Object* raw_value;
8846 { MaybeObject* maybe_raw_value =
8847 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8848 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8849 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008850 Handle<Object> value(raw_value);
8851
8852 // If the callback object is a fixed array then it contains JavaScript
8853 // getter and/or setter.
8854 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8855 result_callback_obj->IsFixedArray();
8856 Handle<FixedArray> details =
8857 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8858 details->set(0, *value);
8859 details->set(1, property_details);
8860 if (hasJavaScriptAccessors) {
8861 details->set(2,
8862 caught_exception ? Heap::true_value()
8863 : Heap::false_value());
8864 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8865 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8866 }
8867
8868 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008869 }
8870 if (i < length - 1) {
8871 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8872 }
8873 }
8874
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008875 return Heap::undefined_value();
8876}
8877
8878
lrn@chromium.org303ada72010-10-27 09:33:13 +00008879static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880 HandleScope scope;
8881
8882 ASSERT(args.length() == 2);
8883
8884 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8885 CONVERT_ARG_CHECKED(String, name, 1);
8886
8887 LookupResult result;
8888 obj->Lookup(*name, &result);
8889 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008890 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008891 }
8892 return Heap::undefined_value();
8893}
8894
8895
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008896// Return the property type calculated from the property details.
8897// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008898static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008899 ASSERT(args.length() == 1);
8900 CONVERT_CHECKED(Smi, details, args[0]);
8901 PropertyType type = PropertyDetails(details).type();
8902 return Smi::FromInt(static_cast<int>(type));
8903}
8904
8905
8906// Return the property attribute calculated from the property details.
8907// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008908static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008909 ASSERT(args.length() == 1);
8910 CONVERT_CHECKED(Smi, details, args[0]);
8911 PropertyAttributes attributes = PropertyDetails(details).attributes();
8912 return Smi::FromInt(static_cast<int>(attributes));
8913}
8914
8915
8916// Return the property insertion index calculated from the property details.
8917// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008918static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008919 ASSERT(args.length() == 1);
8920 CONVERT_CHECKED(Smi, details, args[0]);
8921 int index = PropertyDetails(details).index();
8922 return Smi::FromInt(index);
8923}
8924
8925
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008926// Return property value from named interceptor.
8927// args[0]: object
8928// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008929static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008930 HandleScope scope;
8931 ASSERT(args.length() == 2);
8932 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8933 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8934 CONVERT_ARG_CHECKED(String, name, 1);
8935
8936 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008937 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008938}
8939
8940
8941// Return element value from indexed interceptor.
8942// args[0]: object
8943// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008944static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8945 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008946 HandleScope scope;
8947 ASSERT(args.length() == 2);
8948 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8949 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8950 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8951
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008952 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008953}
8954
8955
lrn@chromium.org303ada72010-10-27 09:33:13 +00008956static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008957 ASSERT(args.length() >= 1);
8958 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008959 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008960 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008961 return Top::Throw(Heap::illegal_execution_state_symbol());
8962 }
8963
8964 return Heap::true_value();
8965}
8966
8967
lrn@chromium.org303ada72010-10-27 09:33:13 +00008968static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008969 HandleScope scope;
8970 ASSERT(args.length() == 1);
8971
8972 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008973 Object* result;
8974 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8975 if (!maybe_result->ToObject(&result)) return maybe_result;
8976 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008977
8978 // Count all frames which are relevant to debugging stack trace.
8979 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008980 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008981 if (id == StackFrame::NO_ID) {
8982 // If there is no JavaScript stack frame count is 0.
8983 return Smi::FromInt(0);
8984 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008985 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8986 return Smi::FromInt(n);
8987}
8988
8989
8990static const int kFrameDetailsFrameIdIndex = 0;
8991static const int kFrameDetailsReceiverIndex = 1;
8992static const int kFrameDetailsFunctionIndex = 2;
8993static const int kFrameDetailsArgumentCountIndex = 3;
8994static const int kFrameDetailsLocalCountIndex = 4;
8995static const int kFrameDetailsSourcePositionIndex = 5;
8996static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008997static const int kFrameDetailsAtReturnIndex = 7;
8998static const int kFrameDetailsDebuggerFrameIndex = 8;
8999static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009000
9001// Return an array with frame details
9002// args[0]: number: break id
9003// args[1]: number: frame index
9004//
9005// The array returned contains the following information:
9006// 0: Frame id
9007// 1: Receiver
9008// 2: Function
9009// 3: Argument count
9010// 4: Local count
9011// 5: Source position
9012// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009013// 7: Is at return
9014// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009015// Arguments name, value
9016// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009017// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00009018static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019 HandleScope scope;
9020 ASSERT(args.length() == 2);
9021
9022 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009023 Object* check;
9024 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9025 if (!maybe_check->ToObject(&check)) return maybe_check;
9026 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009027 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9028
9029 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009030 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009031 if (id == StackFrame::NO_ID) {
9032 // If there are no JavaScript stack frames return undefined.
9033 return Heap::undefined_value();
9034 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009035 int count = 0;
9036 JavaScriptFrameIterator it(id);
9037 for (; !it.done(); it.Advance()) {
9038 if (count == index) break;
9039 count++;
9040 }
9041 if (it.done()) return Heap::undefined_value();
9042
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009043 bool is_optimized_frame =
9044 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
9045
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009046 // Traverse the saved contexts chain to find the active context for the
9047 // selected frame.
9048 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009049 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009050 save = save->prev();
9051 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009052 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053
9054 // Get the frame id.
9055 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
9056
9057 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00009058 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009059
9060 // Check for constructor frame.
9061 bool constructor = it.frame()->IsConstructor();
9062
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009063 // Get scope info and read from it for local variable information.
9064 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009065 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009066 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009067
9068 // Get the context.
9069 Handle<Context> context(Context::cast(it.frame()->context()));
9070
9071 // Get the locals names and values into a temporary array.
9072 //
9073 // TODO(1240907): Hide compiler-introduced stack variables
9074 // (e.g. .result)? For users of the debugger, they will probably be
9075 // confusing.
9076 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009077
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009078 // Fill in the names of the locals.
9079 for (int i = 0; i < info.NumberOfLocals(); i++) {
9080 locals->set(i * 2, *info.LocalName(i));
9081 }
9082
9083 // Fill in the values of the locals.
9084 for (int i = 0; i < info.NumberOfLocals(); i++) {
9085 if (is_optimized_frame) {
9086 // If we are inspecting an optimized frame use undefined as the
9087 // value for all locals.
9088 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009089 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009090 // for locals in optimized frames.
9091 locals->set(i * 2 + 1, Heap::undefined_value());
9092 } else if (i < info.number_of_stack_slots()) {
9093 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009094 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9095 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009096 // Traverse the context chain to the function context as all local
9097 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009098 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009099 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009100 context = Handle<Context>(context->previous());
9101 }
9102 ASSERT(context->is_function_context());
9103 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009104 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009105 }
9106 }
9107
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009108 // Check whether this frame is positioned at return. If not top
9109 // frame or if the frame is optimized it cannot be at a return.
9110 bool at_return = false;
9111 if (!is_optimized_frame && index == 0) {
9112 at_return = Debug::IsBreakAtReturn(it.frame());
9113 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009114
9115 // If positioned just before return find the value to be returned and add it
9116 // to the frame information.
9117 Handle<Object> return_value = Factory::undefined_value();
9118 if (at_return) {
9119 StackFrameIterator it2;
9120 Address internal_frame_sp = NULL;
9121 while (!it2.done()) {
9122 if (it2.frame()->is_internal()) {
9123 internal_frame_sp = it2.frame()->sp();
9124 } else {
9125 if (it2.frame()->is_java_script()) {
9126 if (it2.frame()->id() == it.frame()->id()) {
9127 // The internal frame just before the JavaScript frame contains the
9128 // value to return on top. A debug break at return will create an
9129 // internal frame to store the return value (eax/rax/r0) before
9130 // entering the debug break exit frame.
9131 if (internal_frame_sp != NULL) {
9132 return_value =
9133 Handle<Object>(Memory::Object_at(internal_frame_sp));
9134 break;
9135 }
9136 }
9137 }
9138
9139 // Indicate that the previous frame was not an internal frame.
9140 internal_frame_sp = NULL;
9141 }
9142 it2.Advance();
9143 }
9144 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145
9146 // Now advance to the arguments adapter frame (if any). It contains all
9147 // the provided parameters whereas the function frame always have the number
9148 // of arguments matching the functions parameters. The rest of the
9149 // information (except for what is collected above) is the same.
9150 it.AdvanceToArgumentsFrame();
9151
9152 // Find the number of arguments to fill. At least fill the number of
9153 // parameters for the function and fill more if more parameters are provided.
9154 int argument_count = info.number_of_parameters();
9155 if (argument_count < it.frame()->GetProvidedParametersCount()) {
9156 argument_count = it.frame()->GetProvidedParametersCount();
9157 }
9158
9159 // Calculate the size of the result.
9160 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009161 2 * (argument_count + info.NumberOfLocals()) +
9162 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9164
9165 // Add the frame id.
9166 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9167
9168 // Add the function (same as in function frame).
9169 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9170
9171 // Add the arguments count.
9172 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9173
9174 // Add the locals count
9175 details->set(kFrameDetailsLocalCountIndex,
9176 Smi::FromInt(info.NumberOfLocals()));
9177
9178 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009179 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9181 } else {
9182 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
9183 }
9184
9185 // Add the constructor information.
9186 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
9187
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009188 // Add the at return information.
9189 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
9190
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009191 // Add information on whether this frame is invoked in the debugger context.
9192 details->set(kFrameDetailsDebuggerFrameIndex,
9193 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
9194
9195 // Fill the dynamic part.
9196 int details_index = kFrameDetailsFirstDynamicIndex;
9197
9198 // Add arguments name and value.
9199 for (int i = 0; i < argument_count; i++) {
9200 // Name of the argument.
9201 if (i < info.number_of_parameters()) {
9202 details->set(details_index++, *info.parameter_name(i));
9203 } else {
9204 details->set(details_index++, Heap::undefined_value());
9205 }
9206
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009207 // Parameter value. If we are inspecting an optimized frame, use
9208 // undefined as the value.
9209 //
9210 // TODO(3141533): We should be able to get the actual parameter
9211 // value for optimized frames.
9212 if (!is_optimized_frame &&
9213 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009214 details->set(details_index++, it.frame()->GetParameter(i));
9215 } else {
9216 details->set(details_index++, Heap::undefined_value());
9217 }
9218 }
9219
9220 // Add locals name and value from the temporary copy from the function frame.
9221 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9222 details->set(details_index++, locals->get(i));
9223 }
9224
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009225 // Add the value being returned.
9226 if (at_return) {
9227 details->set(details_index++, *return_value);
9228 }
9229
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009230 // Add the receiver (same as in function frame).
9231 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9232 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
9233 Handle<Object> receiver(it.frame()->receiver());
9234 if (!receiver->IsJSObject()) {
9235 // If the receiver is NOT a JSObject we have hit an optimization
9236 // where a value object is not converted into a wrapped JS objects.
9237 // To hide this optimization from the debugger, we wrap the receiver
9238 // by creating correct wrapper object based on the calling frame's
9239 // global context.
9240 it.Advance();
9241 Handle<Context> calling_frames_global_context(
9242 Context::cast(Context::cast(it.frame()->context())->global_context()));
9243 receiver = Factory::ToObject(receiver, calling_frames_global_context);
9244 }
9245 details->set(kFrameDetailsReceiverIndex, *receiver);
9246
9247 ASSERT_EQ(details_size, details_index);
9248 return *Factory::NewJSArrayWithElements(details);
9249}
9250
9251
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009252// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009253static bool CopyContextLocalsToScopeObject(
ager@chromium.orgb5737492010-07-15 09:29:43 +00009254 Handle<SerializedScopeInfo> serialized_scope_info,
9255 ScopeInfo<>& scope_info,
9256 Handle<Context> context,
9257 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009258 // Fill all context locals to the context extension.
9259 for (int i = Context::MIN_CONTEXT_SLOTS;
9260 i < scope_info.number_of_context_slots();
9261 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009262 int context_index = serialized_scope_info->ContextSlotIndex(
9263 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009264
9265 // Don't include the arguments shadow (.arguments) context variable.
9266 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009267 RETURN_IF_EMPTY_HANDLE_VALUE(
9268 SetProperty(scope_object,
9269 scope_info.context_slot_name(i),
9270 Handle<Object>(context->get(context_index)), NONE),
9271 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009272 }
9273 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009274
9275 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009276}
9277
9278
9279// Create a plain JSObject which materializes the local scope for the specified
9280// frame.
9281static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
9282 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009283 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009284 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9285 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009286
9287 // Allocate and initialize a JSObject with all the arguments, stack locals
9288 // heap locals and extension properties of the debugged function.
9289 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
9290
9291 // First fill all parameters.
9292 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009293 RETURN_IF_EMPTY_HANDLE_VALUE(
9294 SetProperty(local_scope,
9295 scope_info.parameter_name(i),
9296 Handle<Object>(frame->GetParameter(i)), NONE),
9297 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009298 }
9299
9300 // Second fill all stack locals.
9301 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009302 RETURN_IF_EMPTY_HANDLE_VALUE(
9303 SetProperty(local_scope,
9304 scope_info.stack_slot_name(i),
9305 Handle<Object>(frame->GetExpression(i)), NONE),
9306 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009307 }
9308
9309 // Third fill all context locals.
9310 Handle<Context> frame_context(Context::cast(frame->context()));
9311 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009312 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9313 function_context, local_scope)) {
9314 return Handle<JSObject>();
9315 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009316
9317 // Finally copy any properties from the function context extension. This will
9318 // be variables introduced by eval.
9319 if (function_context->closure() == *function) {
9320 if (function_context->has_extension() &&
9321 !function_context->IsGlobalContext()) {
9322 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009323 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009324 for (int i = 0; i < keys->length(); i++) {
9325 // Names of variables introduced by eval are strings.
9326 ASSERT(keys->get(i)->IsString());
9327 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009328 RETURN_IF_EMPTY_HANDLE_VALUE(
9329 SetProperty(local_scope, key, GetProperty(ext, key), NONE),
9330 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009331 }
9332 }
9333 }
9334 return local_scope;
9335}
9336
9337
9338// Create a plain JSObject which materializes the closure content for the
9339// context.
9340static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
9341 ASSERT(context->is_function_context());
9342
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009343 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009344 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9345 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009346
9347 // Allocate and initialize a JSObject with all the content of theis function
9348 // closure.
9349 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
9350
9351 // Check whether the arguments shadow object exists.
9352 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00009353 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
9354 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009355 if (arguments_shadow_index >= 0) {
9356 // In this case all the arguments are available in the arguments shadow
9357 // object.
9358 Handle<JSObject> arguments_shadow(
9359 JSObject::cast(context->get(arguments_shadow_index)));
9360 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009361 // We don't expect exception-throwing getters on the arguments shadow.
9362 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009363 RETURN_IF_EMPTY_HANDLE_VALUE(
9364 SetProperty(closure_scope,
9365 scope_info.parameter_name(i),
9366 Handle<Object>(element),
9367 NONE),
9368 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009369 }
9370 }
9371
9372 // Fill all context locals to the context extension.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009373 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9374 context, closure_scope)) {
9375 return Handle<JSObject>();
9376 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009377
9378 // Finally copy any properties from the function context extension. This will
9379 // be variables introduced by eval.
9380 if (context->has_extension()) {
9381 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009382 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009383 for (int i = 0; i < keys->length(); i++) {
9384 // Names of variables introduced by eval are strings.
9385 ASSERT(keys->get(i)->IsString());
9386 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009387 RETURN_IF_EMPTY_HANDLE_VALUE(
9388 SetProperty(closure_scope, key, GetProperty(ext, key), NONE),
9389 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009390 }
9391 }
9392
9393 return closure_scope;
9394}
9395
9396
9397// Iterate over the actual scopes visible from a stack frame. All scopes are
9398// backed by an actual context except the local scope, which is inserted
9399// "artifically" in the context chain.
9400class ScopeIterator {
9401 public:
9402 enum ScopeType {
9403 ScopeTypeGlobal = 0,
9404 ScopeTypeLocal,
9405 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009406 ScopeTypeClosure,
9407 // Every catch block contains an implicit with block (its parameter is
9408 // a JSContextExtensionObject) that extends current scope with a variable
9409 // holding exception object. Such with blocks are treated as scopes of their
9410 // own type.
9411 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009412 };
9413
9414 explicit ScopeIterator(JavaScriptFrame* frame)
9415 : frame_(frame),
9416 function_(JSFunction::cast(frame->function())),
9417 context_(Context::cast(frame->context())),
9418 local_done_(false),
9419 at_local_(false) {
9420
9421 // Check whether the first scope is actually a local scope.
9422 if (context_->IsGlobalContext()) {
9423 // If there is a stack slot for .result then this local scope has been
9424 // created for evaluating top level code and it is not a real local scope.
9425 // Checking for the existence of .result seems fragile, but the scope info
9426 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009427 int index = function_->shared()->scope_info()->
9428 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009429 at_local_ = index < 0;
9430 } else if (context_->is_function_context()) {
9431 at_local_ = true;
9432 }
9433 }
9434
9435 // More scopes?
9436 bool Done() { return context_.is_null(); }
9437
9438 // Move to the next scope.
9439 void Next() {
9440 // If at a local scope mark the local scope as passed.
9441 if (at_local_) {
9442 at_local_ = false;
9443 local_done_ = true;
9444
9445 // If the current context is not associated with the local scope the
9446 // current context is the next real scope, so don't move to the next
9447 // context in this case.
9448 if (context_->closure() != *function_) {
9449 return;
9450 }
9451 }
9452
9453 // The global scope is always the last in the chain.
9454 if (context_->IsGlobalContext()) {
9455 context_ = Handle<Context>();
9456 return;
9457 }
9458
9459 // Move to the next context.
9460 if (context_->is_function_context()) {
9461 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9462 } else {
9463 context_ = Handle<Context>(context_->previous());
9464 }
9465
9466 // If passing the local scope indicate that the current scope is now the
9467 // local scope.
9468 if (!local_done_ &&
9469 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9470 at_local_ = true;
9471 }
9472 }
9473
9474 // Return the type of the current scope.
9475 int Type() {
9476 if (at_local_) {
9477 return ScopeTypeLocal;
9478 }
9479 if (context_->IsGlobalContext()) {
9480 ASSERT(context_->global()->IsGlobalObject());
9481 return ScopeTypeGlobal;
9482 }
9483 if (context_->is_function_context()) {
9484 return ScopeTypeClosure;
9485 }
9486 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009487 // Current scope is either an explicit with statement or a with statement
9488 // implicitely generated for a catch block.
9489 // If the extension object here is a JSContextExtensionObject then
9490 // current with statement is one frome a catch block otherwise it's a
9491 // regular with statement.
9492 if (context_->extension()->IsJSContextExtensionObject()) {
9493 return ScopeTypeCatch;
9494 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009495 return ScopeTypeWith;
9496 }
9497
9498 // Return the JavaScript object with the content of the current scope.
9499 Handle<JSObject> ScopeObject() {
9500 switch (Type()) {
9501 case ScopeIterator::ScopeTypeGlobal:
9502 return Handle<JSObject>(CurrentContext()->global());
9503 break;
9504 case ScopeIterator::ScopeTypeLocal:
9505 // Materialize the content of the local scope into a JSObject.
9506 return MaterializeLocalScope(frame_);
9507 break;
9508 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009509 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009510 // Return the with object.
9511 return Handle<JSObject>(CurrentContext()->extension());
9512 break;
9513 case ScopeIterator::ScopeTypeClosure:
9514 // Materialize the content of the closure scope into a JSObject.
9515 return MaterializeClosure(CurrentContext());
9516 break;
9517 }
9518 UNREACHABLE();
9519 return Handle<JSObject>();
9520 }
9521
9522 // Return the context for this scope. For the local context there might not
9523 // be an actual context.
9524 Handle<Context> CurrentContext() {
9525 if (at_local_ && context_->closure() != *function_) {
9526 return Handle<Context>();
9527 }
9528 return context_;
9529 }
9530
9531#ifdef DEBUG
9532 // Debug print of the content of the current scope.
9533 void DebugPrint() {
9534 switch (Type()) {
9535 case ScopeIterator::ScopeTypeGlobal:
9536 PrintF("Global:\n");
9537 CurrentContext()->Print();
9538 break;
9539
9540 case ScopeIterator::ScopeTypeLocal: {
9541 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009542 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009543 scope_info.Print();
9544 if (!CurrentContext().is_null()) {
9545 CurrentContext()->Print();
9546 if (CurrentContext()->has_extension()) {
9547 Handle<JSObject> extension =
9548 Handle<JSObject>(CurrentContext()->extension());
9549 if (extension->IsJSContextExtensionObject()) {
9550 extension->Print();
9551 }
9552 }
9553 }
9554 break;
9555 }
9556
9557 case ScopeIterator::ScopeTypeWith: {
9558 PrintF("With:\n");
9559 Handle<JSObject> extension =
9560 Handle<JSObject>(CurrentContext()->extension());
9561 extension->Print();
9562 break;
9563 }
9564
ager@chromium.orga1645e22009-09-09 19:27:10 +00009565 case ScopeIterator::ScopeTypeCatch: {
9566 PrintF("Catch:\n");
9567 Handle<JSObject> extension =
9568 Handle<JSObject>(CurrentContext()->extension());
9569 extension->Print();
9570 break;
9571 }
9572
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009573 case ScopeIterator::ScopeTypeClosure: {
9574 PrintF("Closure:\n");
9575 CurrentContext()->Print();
9576 if (CurrentContext()->has_extension()) {
9577 Handle<JSObject> extension =
9578 Handle<JSObject>(CurrentContext()->extension());
9579 if (extension->IsJSContextExtensionObject()) {
9580 extension->Print();
9581 }
9582 }
9583 break;
9584 }
9585
9586 default:
9587 UNREACHABLE();
9588 }
9589 PrintF("\n");
9590 }
9591#endif
9592
9593 private:
9594 JavaScriptFrame* frame_;
9595 Handle<JSFunction> function_;
9596 Handle<Context> context_;
9597 bool local_done_;
9598 bool at_local_;
9599
9600 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9601};
9602
9603
lrn@chromium.org303ada72010-10-27 09:33:13 +00009604static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009605 HandleScope scope;
9606 ASSERT(args.length() == 2);
9607
9608 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009609 Object* check;
9610 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9611 if (!maybe_check->ToObject(&check)) return maybe_check;
9612 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009613 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9614
9615 // Get the frame where the debugging is performed.
9616 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9617 JavaScriptFrameIterator it(id);
9618 JavaScriptFrame* frame = it.frame();
9619
9620 // Count the visible scopes.
9621 int n = 0;
9622 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9623 n++;
9624 }
9625
9626 return Smi::FromInt(n);
9627}
9628
9629
9630static const int kScopeDetailsTypeIndex = 0;
9631static const int kScopeDetailsObjectIndex = 1;
9632static const int kScopeDetailsSize = 2;
9633
9634// Return an array with scope details
9635// args[0]: number: break id
9636// args[1]: number: frame index
9637// args[2]: number: scope index
9638//
9639// The array returned contains the following information:
9640// 0: Scope type
9641// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009642static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009643 HandleScope scope;
9644 ASSERT(args.length() == 3);
9645
9646 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009647 Object* check;
9648 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9649 if (!maybe_check->ToObject(&check)) return maybe_check;
9650 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009651 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9652 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9653
9654 // Get the frame where the debugging is performed.
9655 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9656 JavaScriptFrameIterator frame_it(id);
9657 JavaScriptFrame* frame = frame_it.frame();
9658
9659 // Find the requested scope.
9660 int n = 0;
9661 ScopeIterator it(frame);
9662 for (; !it.Done() && n < index; it.Next()) {
9663 n++;
9664 }
9665 if (it.Done()) {
9666 return Heap::undefined_value();
9667 }
9668
9669 // Calculate the size of the result.
9670 int details_size = kScopeDetailsSize;
9671 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9672
9673 // Fill in scope details.
9674 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009675 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009676 RETURN_IF_EMPTY_HANDLE(scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009677 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009678
9679 return *Factory::NewJSArrayWithElements(details);
9680}
9681
9682
lrn@chromium.org303ada72010-10-27 09:33:13 +00009683static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009684 HandleScope scope;
9685 ASSERT(args.length() == 0);
9686
9687#ifdef DEBUG
9688 // Print the scopes for the top frame.
9689 StackFrameLocator locator;
9690 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9691 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9692 it.DebugPrint();
9693 }
9694#endif
9695 return Heap::undefined_value();
9696}
9697
9698
lrn@chromium.org303ada72010-10-27 09:33:13 +00009699static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009700 HandleScope scope;
9701 ASSERT(args.length() == 1);
9702
9703 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009704 Object* result;
9705 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9706 if (!maybe_result->ToObject(&result)) return maybe_result;
9707 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009708
9709 // Count all archived V8 threads.
9710 int n = 0;
9711 for (ThreadState* thread = ThreadState::FirstInUse();
9712 thread != NULL;
9713 thread = thread->Next()) {
9714 n++;
9715 }
9716
9717 // Total number of threads is current thread and archived threads.
9718 return Smi::FromInt(n + 1);
9719}
9720
9721
9722static const int kThreadDetailsCurrentThreadIndex = 0;
9723static const int kThreadDetailsThreadIdIndex = 1;
9724static const int kThreadDetailsSize = 2;
9725
9726// Return an array with thread details
9727// args[0]: number: break id
9728// args[1]: number: thread index
9729//
9730// The array returned contains the following information:
9731// 0: Is current thread?
9732// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009733static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009734 HandleScope scope;
9735 ASSERT(args.length() == 2);
9736
9737 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009738 Object* check;
9739 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9740 if (!maybe_check->ToObject(&check)) return maybe_check;
9741 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009742 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9743
9744 // Allocate array for result.
9745 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9746
9747 // Thread index 0 is current thread.
9748 if (index == 0) {
9749 // Fill the details.
9750 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9751 details->set(kThreadDetailsThreadIdIndex,
9752 Smi::FromInt(ThreadManager::CurrentId()));
9753 } else {
9754 // Find the thread with the requested index.
9755 int n = 1;
9756 ThreadState* thread = ThreadState::FirstInUse();
9757 while (index != n && thread != NULL) {
9758 thread = thread->Next();
9759 n++;
9760 }
9761 if (thread == NULL) {
9762 return Heap::undefined_value();
9763 }
9764
9765 // Fill the details.
9766 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9767 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9768 }
9769
9770 // Convert to JS array and return.
9771 return *Factory::NewJSArrayWithElements(details);
9772}
9773
9774
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009775// Sets the disable break state
9776// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009777static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009778 HandleScope scope;
9779 ASSERT(args.length() == 1);
9780 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9781 Debug::set_disable_break(disable_break);
9782 return Heap::undefined_value();
9783}
9784
9785
lrn@chromium.org303ada72010-10-27 09:33:13 +00009786static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009787 HandleScope scope;
9788 ASSERT(args.length() == 1);
9789
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009790 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9791 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009792 // Find the number of break points
9793 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9794 if (break_locations->IsUndefined()) return Heap::undefined_value();
9795 // Return array as JS array
9796 return *Factory::NewJSArrayWithElements(
9797 Handle<FixedArray>::cast(break_locations));
9798}
9799
9800
9801// Set a break point in a function
9802// args[0]: function
9803// args[1]: number: break source position (within the function source)
9804// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009805static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009806 HandleScope scope;
9807 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009808 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9809 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009810 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9811 RUNTIME_ASSERT(source_position >= 0);
9812 Handle<Object> break_point_object_arg = args.at<Object>(2);
9813
9814 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009815 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009816
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009817 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009818}
9819
9820
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009821Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9822 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009823 // Iterate the heap looking for SharedFunctionInfo generated from the
9824 // script. The inner most SharedFunctionInfo containing the source position
9825 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009826 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009827 // which is found is not compiled it is compiled and the heap is iterated
9828 // again as the compilation might create inner functions from the newly
9829 // compiled function and the actual requested break point might be in one of
9830 // these functions.
9831 bool done = false;
9832 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009833 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009834 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009835 while (!done) {
9836 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009837 for (HeapObject* obj = iterator.next();
9838 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009839 if (obj->IsSharedFunctionInfo()) {
9840 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9841 if (shared->script() == *script) {
9842 // If the SharedFunctionInfo found has the requested script data and
9843 // contains the source position it is a candidate.
9844 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009845 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009846 start_position = shared->start_position();
9847 }
9848 if (start_position <= position &&
9849 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009850 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009851 // candidate this is the new candidate.
9852 if (target.is_null()) {
9853 target_start_position = start_position;
9854 target = shared;
9855 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009856 if (target_start_position == start_position &&
9857 shared->end_position() == target->end_position()) {
9858 // If a top-level function contain only one function
9859 // declartion the source for the top-level and the function is
9860 // the same. In that case prefer the non top-level function.
9861 if (!shared->is_toplevel()) {
9862 target_start_position = start_position;
9863 target = shared;
9864 }
9865 } else if (target_start_position <= start_position &&
9866 shared->end_position() <= target->end_position()) {
9867 // This containment check includes equality as a function inside
9868 // a top-level function can share either start or end position
9869 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009870 target_start_position = start_position;
9871 target = shared;
9872 }
9873 }
9874 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009875 }
9876 }
9877 }
9878
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009879 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009880 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009881 }
9882
9883 // If the candidate found is compiled we are done. NOTE: when lazy
9884 // compilation of inner functions is introduced some additional checking
9885 // needs to be done here to compile inner functions.
9886 done = target->is_compiled();
9887 if (!done) {
9888 // If the candidate is not compiled compile it to reveal any inner
9889 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009890 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009891 }
9892 }
9893
9894 return *target;
9895}
9896
9897
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009898// Changes the state of a break point in a script and returns source position
9899// where break point was set. NOTE: Regarding performance see the NOTE for
9900// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009901// args[0]: script to set break point in
9902// args[1]: number: break source position (within the script source)
9903// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009904static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009905 HandleScope scope;
9906 ASSERT(args.length() == 3);
9907 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9908 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9909 RUNTIME_ASSERT(source_position >= 0);
9910 Handle<Object> break_point_object_arg = args.at<Object>(2);
9911
9912 // Get the script from the script wrapper.
9913 RUNTIME_ASSERT(wrapper->value()->IsScript());
9914 Handle<Script> script(Script::cast(wrapper->value()));
9915
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009916 Object* result = Runtime::FindSharedFunctionInfoInScript(
9917 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009918 if (!result->IsUndefined()) {
9919 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9920 // Find position within function. The script position might be before the
9921 // source position of the first function.
9922 int position;
9923 if (shared->start_position() > source_position) {
9924 position = 0;
9925 } else {
9926 position = source_position - shared->start_position();
9927 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009928 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9929 position += shared->start_position();
9930 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009931 }
9932 return Heap::undefined_value();
9933}
9934
9935
9936// Clear a break point
9937// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009938static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009939 HandleScope scope;
9940 ASSERT(args.length() == 1);
9941 Handle<Object> break_point_object_arg = args.at<Object>(0);
9942
9943 // Clear break point.
9944 Debug::ClearBreakPoint(break_point_object_arg);
9945
9946 return Heap::undefined_value();
9947}
9948
9949
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009950// Change the state of break on exceptions.
9951// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9952// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009953static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009954 HandleScope scope;
9955 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009956 RUNTIME_ASSERT(args[0]->IsNumber());
9957 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009958
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009959 // If the number doesn't match an enum value, the ChangeBreakOnException
9960 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009961 ExceptionBreakType type =
9962 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009963 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009964 Debug::ChangeBreakOnException(type, enable);
9965 return Heap::undefined_value();
9966}
9967
9968
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009969// Returns the state of break on exceptions
9970// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009971static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009972 HandleScope scope;
9973 ASSERT(args.length() == 1);
9974 RUNTIME_ASSERT(args[0]->IsNumber());
9975
9976 ExceptionBreakType type =
9977 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9978 bool result = Debug::IsBreakOnException(type);
9979 return Smi::FromInt(result);
9980}
9981
9982
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009983// Prepare for stepping
9984// args[0]: break id for checking execution state
9985// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009986// args[2]: number of times to perform the step, for step out it is the number
9987// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009988static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989 HandleScope scope;
9990 ASSERT(args.length() == 3);
9991 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009992 Object* check;
9993 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9994 if (!maybe_check->ToObject(&check)) return maybe_check;
9995 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009996 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9997 return Top::Throw(Heap::illegal_argument_symbol());
9998 }
9999
10000 // Get the step action and check validity.
10001 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10002 if (step_action != StepIn &&
10003 step_action != StepNext &&
10004 step_action != StepOut &&
10005 step_action != StepInMin &&
10006 step_action != StepMin) {
10007 return Top::Throw(Heap::illegal_argument_symbol());
10008 }
10009
10010 // Get the number of steps.
10011 int step_count = NumberToInt32(args[2]);
10012 if (step_count < 1) {
10013 return Top::Throw(Heap::illegal_argument_symbol());
10014 }
10015
ager@chromium.orga1645e22009-09-09 19:27:10 +000010016 // Clear all current stepping setup.
10017 Debug::ClearStepping();
10018
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010019 // Prepare step.
10020 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
10021 return Heap::undefined_value();
10022}
10023
10024
10025// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010026static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010027 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010028 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010029 Debug::ClearStepping();
10030 return Heap::undefined_value();
10031}
10032
10033
10034// Creates a copy of the with context chain. The copy of the context chain is
10035// is linked to the function context supplied.
10036static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10037 Handle<Context> function_context) {
10038 // At the bottom of the chain. Return the function context to link to.
10039 if (context_chain->is_function_context()) {
10040 return function_context;
10041 }
10042
10043 // Recursively copy the with contexts.
10044 Handle<Context> previous(context_chain->previous());
10045 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010046 Handle<Context> context = CopyWithContextChain(function_context, previous);
10047 return Factory::NewWithContext(context,
10048 extension,
10049 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010050}
10051
10052
10053// Helper function to find or create the arguments object for
10054// Runtime_DebugEvaluate.
10055static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
10056 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010057 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010058 const ScopeInfo<>* sinfo,
10059 Handle<Context> function_context) {
10060 // Try to find the value of 'arguments' to pass as parameter. If it is not
10061 // found (that is the debugged function does not reference 'arguments' and
10062 // does not support eval) then create an 'arguments' object.
10063 int index;
10064 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010065 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010066 if (index != -1) {
10067 return Handle<Object>(frame->GetExpression(index));
10068 }
10069 }
10070
10071 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010072 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010073 if (index != -1) {
10074 return Handle<Object>(function_context->get(index));
10075 }
10076 }
10077
10078 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010079 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
10080 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010081
10082 AssertNoAllocation no_gc;
10083 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010084 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010085 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010086 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010087 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010088 return arguments;
10089}
10090
10091
10092// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010093// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010094// extension part has all the parameters and locals of the function on the
10095// stack frame. A function which calls eval with the code to evaluate is then
10096// compiled in this context and called in this context. As this context
10097// replaces the context of the function on the stack frame a new (empty)
10098// function is created as well to be used as the closure for the context.
10099// This function and the context acts as replacements for the function on the
10100// stack frame presenting the same view of the values of parameters and
10101// local variables as if the piece of JavaScript was evaluated at the point
10102// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010103static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010104 HandleScope scope;
10105
10106 // Check the execution state and decode arguments frame and source to be
10107 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010108 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010109 Object* check_result;
10110 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10111 if (!maybe_check_result->ToObject(&check_result)) {
10112 return maybe_check_result;
10113 }
10114 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10116 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010117 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010118 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010119
10120 // Handle the processing of break.
10121 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010122
10123 // Get the frame where the debugging is performed.
10124 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10125 JavaScriptFrameIterator it(id);
10126 JavaScriptFrame* frame = it.frame();
10127 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010128 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010129 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010130
10131 // Traverse the saved contexts chain to find the active context for the
10132 // selected frame.
10133 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010134 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010135 save = save->prev();
10136 }
10137 ASSERT(save != NULL);
10138 SaveContext savex;
10139 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010140
10141 // Create the (empty) function replacing the function on the stack frame for
10142 // the purpose of evaluating in the context created below. It is important
10143 // that this function does not describe any parameters and local variables
10144 // in the context. If it does then this will cause problems with the lookup
10145 // in Context::Lookup, where context slots for parameters and local variables
10146 // are looked at before the extension object.
10147 Handle<JSFunction> go_between =
10148 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
10149 go_between->set_context(function->context());
10150#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010151 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010152 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10153 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10154#endif
10155
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010156 // Materialize the content of the local scope into a JSObject.
10157 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010158 RETURN_IF_EMPTY_HANDLE(local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010159
10160 // Allocate a new context for the debug evaluation and set the extension
10161 // object build.
10162 Handle<Context> context =
10163 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010164 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010165 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010166 Handle<Context> frame_context(Context::cast(frame->context()));
10167 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010168 context = CopyWithContextChain(frame_context, context);
10169
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010170 if (additional_context->IsJSObject()) {
10171 context = Factory::NewWithContext(context,
10172 Handle<JSObject>::cast(additional_context), false);
10173 }
10174
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010175 // Wrap the evaluation statement in a new function compiled in the newly
10176 // created context. The function has one parameter which has to be called
10177 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010178 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010179 // function(arguments,__source__) {return eval(__source__);}
10180 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010181 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010182 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010183 Handle<String> function_source =
10184 Factory::NewStringFromAscii(Vector<const char>(source_str,
10185 source_str_length));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010186
10187 // Currently, the eval code will be executed in non-strict mode,
10188 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010189 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010190 Compiler::CompileEval(function_source,
10191 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010192 context->IsGlobalContext(),
10193 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010194 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010195 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010196 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010197
10198 // Invoke the result of the compilation to get the evaluation function.
10199 bool has_pending_exception;
10200 Handle<Object> receiver(frame->receiver());
10201 Handle<Object> evaluation_function =
10202 Execution::Call(compiled_function, receiver, 0, NULL,
10203 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010204 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010205
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010206 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
10207 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010208
10209 // Invoke the evaluation function and return the result.
10210 const int argc = 2;
10211 Object** argv[argc] = { arguments.location(),
10212 Handle<Object>::cast(source).location() };
10213 Handle<Object> result =
10214 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10215 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010216 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010217
10218 // Skip the global proxy as it has no properties and always delegates to the
10219 // real global object.
10220 if (result->IsJSGlobalProxy()) {
10221 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10222 }
10223
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010224 return *result;
10225}
10226
10227
lrn@chromium.org303ada72010-10-27 09:33:13 +000010228static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010229 HandleScope scope;
10230
10231 // Check the execution state and decode arguments frame and source to be
10232 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010233 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010234 Object* check_result;
10235 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10236 if (!maybe_check_result->ToObject(&check_result)) {
10237 return maybe_check_result;
10238 }
10239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010241 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010242 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010243
10244 // Handle the processing of break.
10245 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010246
10247 // Enter the top context from before the debugger was invoked.
10248 SaveContext save;
10249 SaveContext* top = &save;
10250 while (top != NULL && *top->context() == *Debug::debug_context()) {
10251 top = top->prev();
10252 }
10253 if (top != NULL) {
10254 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010255 }
10256
10257 // Get the global context now set to the top context from before the
10258 // debugger was invoked.
10259 Handle<Context> context = Top::global_context();
10260
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010261 bool is_global = true;
10262
10263 if (additional_context->IsJSObject()) {
10264 // Create a function context first, than put 'with' context on top of it.
10265 Handle<JSFunction> go_between = Factory::NewFunction(
10266 Factory::empty_string(), Factory::undefined_value());
10267 go_between->set_context(*context);
10268 context =
10269 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
10270 context->set_extension(JSObject::cast(*additional_context));
10271 is_global = false;
10272 }
10273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010275 // Currently, the eval code will be executed in non-strict mode,
10276 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010277 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010278 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010279 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010280 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010281 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
10282 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010283
10284 // Invoke the result of the compilation to get the evaluation function.
10285 bool has_pending_exception;
10286 Handle<Object> receiver = Top::global();
10287 Handle<Object> result =
10288 Execution::Call(compiled_function, receiver, 0, NULL,
10289 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010290 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291 return *result;
10292}
10293
10294
lrn@chromium.org303ada72010-10-27 09:33:13 +000010295static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010297 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010299 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010300 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010301
10302 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010303 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010304 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10305 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10306 // because using
10307 // instances->set(i, *GetScriptWrapper(script))
10308 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10309 // already have deferenced the instances handle.
10310 Handle<JSValue> wrapper = GetScriptWrapper(script);
10311 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010312 }
10313
10314 // Return result as a JS array.
10315 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
10316 Handle<JSArray>::cast(result)->SetContent(*instances);
10317 return *result;
10318}
10319
10320
10321// Helper function used by Runtime_DebugReferencedBy below.
10322static int DebugReferencedBy(JSObject* target,
10323 Object* instance_filter, int max_references,
10324 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325 JSFunction* arguments_function) {
10326 NoHandleAllocation ha;
10327 AssertNoAllocation no_alloc;
10328
10329 // Iterate the heap.
10330 int count = 0;
10331 JSObject* last = NULL;
10332 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010333 HeapObject* heap_obj = NULL;
10334 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335 (max_references == 0 || count < max_references)) {
10336 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010337 if (heap_obj->IsJSObject()) {
10338 // Skip context extension objects and argument arrays as these are
10339 // checked in the context of functions using them.
10340 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010341 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010342 obj->map()->constructor() == arguments_function) {
10343 continue;
10344 }
10345
10346 // Check if the JS object has a reference to the object looked for.
10347 if (obj->ReferencesObject(target)) {
10348 // Check instance filter if supplied. This is normally used to avoid
10349 // references from mirror objects (see Runtime_IsInPrototypeChain).
10350 if (!instance_filter->IsUndefined()) {
10351 Object* V = obj;
10352 while (true) {
10353 Object* prototype = V->GetPrototype();
10354 if (prototype->IsNull()) {
10355 break;
10356 }
10357 if (instance_filter == prototype) {
10358 obj = NULL; // Don't add this object.
10359 break;
10360 }
10361 V = prototype;
10362 }
10363 }
10364
10365 if (obj != NULL) {
10366 // Valid reference found add to instance array if supplied an update
10367 // count.
10368 if (instances != NULL && count < instances_size) {
10369 instances->set(count, obj);
10370 }
10371 last = obj;
10372 count++;
10373 }
10374 }
10375 }
10376 }
10377
10378 // Check for circular reference only. This can happen when the object is only
10379 // referenced from mirrors and has a circular reference in which case the
10380 // object is not really alive and would have been garbage collected if not
10381 // referenced from the mirror.
10382 if (count == 1 && last == target) {
10383 count = 0;
10384 }
10385
10386 // Return the number of referencing objects found.
10387 return count;
10388}
10389
10390
10391// Scan the heap for objects with direct references to an object
10392// args[0]: the object to find references to
10393// args[1]: constructor function for instances to exclude (Mirror)
10394// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010395static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010396 ASSERT(args.length() == 3);
10397
10398 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010399 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010400
10401 // Check parameters.
10402 CONVERT_CHECKED(JSObject, target, args[0]);
10403 Object* instance_filter = args[1];
10404 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10405 instance_filter->IsJSObject());
10406 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10407 RUNTIME_ASSERT(max_references >= 0);
10408
10409 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010410 JSObject* arguments_boilerplate =
10411 Top::context()->global_context()->arguments_boilerplate();
10412 JSFunction* arguments_function =
10413 JSFunction::cast(arguments_boilerplate->map()->constructor());
10414
10415 // Get the number of referencing objects.
10416 int count;
10417 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010418 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419
10420 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010421 Object* object;
10422 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10423 if (!maybe_object->ToObject(&object)) return maybe_object;
10424 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010425 FixedArray* instances = FixedArray::cast(object);
10426
10427 // Fill the referencing objects.
10428 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010429 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010430
10431 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010432 Object* result;
10433 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10434 Top::context()->global_context()->array_function());
10435 if (!maybe_result->ToObject(&result)) return maybe_result;
10436 }
10437 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010438 return result;
10439}
10440
10441
10442// Helper function used by Runtime_DebugConstructedBy below.
10443static int DebugConstructedBy(JSFunction* constructor, int max_references,
10444 FixedArray* instances, int instances_size) {
10445 AssertNoAllocation no_alloc;
10446
10447 // Iterate the heap.
10448 int count = 0;
10449 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010450 HeapObject* heap_obj = NULL;
10451 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010452 (max_references == 0 || count < max_references)) {
10453 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010454 if (heap_obj->IsJSObject()) {
10455 JSObject* obj = JSObject::cast(heap_obj);
10456 if (obj->map()->constructor() == constructor) {
10457 // Valid reference found add to instance array if supplied an update
10458 // count.
10459 if (instances != NULL && count < instances_size) {
10460 instances->set(count, obj);
10461 }
10462 count++;
10463 }
10464 }
10465 }
10466
10467 // Return the number of referencing objects found.
10468 return count;
10469}
10470
10471
10472// Scan the heap for objects constructed by a specific function.
10473// args[0]: the constructor to find instances of
10474// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010475static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010476 ASSERT(args.length() == 2);
10477
10478 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010479 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010480
10481 // Check parameters.
10482 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10483 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10484 RUNTIME_ASSERT(max_references >= 0);
10485
10486 // Get the number of referencing objects.
10487 int count;
10488 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10489
10490 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010491 Object* object;
10492 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10493 if (!maybe_object->ToObject(&object)) return maybe_object;
10494 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010495 FixedArray* instances = FixedArray::cast(object);
10496
10497 // Fill the referencing objects.
10498 count = DebugConstructedBy(constructor, max_references, instances, count);
10499
10500 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010501 Object* result;
10502 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10503 Top::context()->global_context()->array_function());
10504 if (!maybe_result->ToObject(&result)) return maybe_result;
10505 }
10506 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507 return result;
10508}
10509
10510
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010511// Find the effective prototype object as returned by __proto__.
10512// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010513static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010514 ASSERT(args.length() == 1);
10515
10516 CONVERT_CHECKED(JSObject, obj, args[0]);
10517
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010518 // Use the __proto__ accessor.
10519 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010520}
10521
10522
lrn@chromium.org303ada72010-10-27 09:33:13 +000010523static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010524 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010525 CPU::DebugBreak();
10526 return Heap::undefined_value();
10527}
10528
10529
lrn@chromium.org303ada72010-10-27 09:33:13 +000010530static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010531#ifdef DEBUG
10532 HandleScope scope;
10533 ASSERT(args.length() == 1);
10534 // Get the function and make sure it is compiled.
10535 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010536 Handle<SharedFunctionInfo> shared(func->shared());
10537 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010538 return Failure::Exception();
10539 }
10540 func->code()->PrintLn();
10541#endif // DEBUG
10542 return Heap::undefined_value();
10543}
ager@chromium.org9085a012009-05-11 19:22:57 +000010544
10545
lrn@chromium.org303ada72010-10-27 09:33:13 +000010546static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010547#ifdef DEBUG
10548 HandleScope scope;
10549 ASSERT(args.length() == 1);
10550 // Get the function and make sure it is compiled.
10551 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010552 Handle<SharedFunctionInfo> shared(func->shared());
10553 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010554 return Failure::Exception();
10555 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010556 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010557#endif // DEBUG
10558 return Heap::undefined_value();
10559}
10560
10561
lrn@chromium.org303ada72010-10-27 09:33:13 +000010562static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010563 NoHandleAllocation ha;
10564 ASSERT(args.length() == 1);
10565
10566 CONVERT_CHECKED(JSFunction, f, args[0]);
10567 return f->shared()->inferred_name();
10568}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010569
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010570
10571static int FindSharedFunctionInfosForScript(Script* script,
10572 FixedArray* buffer) {
10573 AssertNoAllocation no_allocations;
10574
10575 int counter = 0;
10576 int buffer_size = buffer->length();
10577 HeapIterator iterator;
10578 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10579 ASSERT(obj != NULL);
10580 if (!obj->IsSharedFunctionInfo()) {
10581 continue;
10582 }
10583 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10584 if (shared->script() != script) {
10585 continue;
10586 }
10587 if (counter < buffer_size) {
10588 buffer->set(counter, shared);
10589 }
10590 counter++;
10591 }
10592 return counter;
10593}
10594
10595// For a script finds all SharedFunctionInfo's in the heap that points
10596// to this script. Returns JSArray of SharedFunctionInfo wrapped
10597// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010598static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010599 Arguments args) {
10600 ASSERT(args.length() == 1);
10601 HandleScope scope;
10602 CONVERT_CHECKED(JSValue, script_value, args[0]);
10603
10604 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10605
10606 const int kBufferSize = 32;
10607
10608 Handle<FixedArray> array;
10609 array = Factory::NewFixedArray(kBufferSize);
10610 int number = FindSharedFunctionInfosForScript(*script, *array);
10611 if (number > kBufferSize) {
10612 array = Factory::NewFixedArray(number);
10613 FindSharedFunctionInfosForScript(*script, *array);
10614 }
10615
10616 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10617 result->set_length(Smi::FromInt(number));
10618
10619 LiveEdit::WrapSharedFunctionInfos(result);
10620
10621 return *result;
10622}
10623
10624// For a script calculates compilation information about all its functions.
10625// The script source is explicitly specified by the second argument.
10626// The source of the actual script is not used, however it is important that
10627// all generated code keeps references to this particular instance of script.
10628// Returns a JSArray of compilation infos. The array is ordered so that
10629// each function with all its descendant is always stored in a continues range
10630// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010631static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010632 ASSERT(args.length() == 2);
10633 HandleScope scope;
10634 CONVERT_CHECKED(JSValue, script, args[0]);
10635 CONVERT_ARG_CHECKED(String, source, 1);
10636 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10637
10638 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10639
10640 if (Top::has_pending_exception()) {
10641 return Failure::Exception();
10642 }
10643
10644 return result;
10645}
10646
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010647// Changes the source of the script to a new_source.
10648// If old_script_name is provided (i.e. is a String), also creates a copy of
10649// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010650static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010651 ASSERT(args.length() == 3);
10652 HandleScope scope;
10653 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10654 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010655 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010656
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010657 CONVERT_CHECKED(Script, original_script_pointer,
10658 original_script_value->value());
10659 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010660
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010661 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10662 new_source,
10663 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010664
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010665 if (old_script->IsScript()) {
10666 Handle<Script> script_handle(Script::cast(old_script));
10667 return *(GetScriptWrapper(script_handle));
10668 } else {
10669 return Heap::null_value();
10670 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010671}
10672
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010673
10674static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10675 ASSERT(args.length() == 1);
10676 HandleScope scope;
10677 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10678 return LiveEdit::FunctionSourceUpdated(shared_info);
10679}
10680
10681
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010682// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010683static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010684 ASSERT(args.length() == 2);
10685 HandleScope scope;
10686 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10687 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10688
ager@chromium.orgac091b72010-05-05 07:34:42 +000010689 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010690}
10691
10692// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010693static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010694 ASSERT(args.length() == 2);
10695 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010696 Handle<Object> function_object(args[0]);
10697 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010698
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010699 if (function_object->IsJSValue()) {
10700 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10701 if (script_object->IsJSValue()) {
10702 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10703 script_object = Handle<Object>(script);
10704 }
10705
10706 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10707 } else {
10708 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10709 // and we check it in this function.
10710 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010711
10712 return Heap::undefined_value();
10713}
10714
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010715
10716// In a code of a parent function replaces original function as embedded object
10717// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010718static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010719 ASSERT(args.length() == 3);
10720 HandleScope scope;
10721
10722 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10723 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10724 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10725
10726 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10727 subst_wrapper);
10728
10729 return Heap::undefined_value();
10730}
10731
10732
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010733// Updates positions of a shared function info (first parameter) according
10734// to script source change. Text change is described in second parameter as
10735// array of groups of 3 numbers:
10736// (change_begin, change_end, change_end_new_position).
10737// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010738static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010739 ASSERT(args.length() == 2);
10740 HandleScope scope;
10741 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10742 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10743
ager@chromium.orgac091b72010-05-05 07:34:42 +000010744 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010745}
10746
10747
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010748// For array of SharedFunctionInfo's (each wrapped in JSValue)
10749// checks that none of them have activations on stacks (of any thread).
10750// Returns array of the same length with corresponding results of
10751// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010752static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010753 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010754 HandleScope scope;
10755 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010756 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010757
ager@chromium.org357bf652010-04-12 11:30:10 +000010758 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010759}
10760
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010761// Compares 2 strings line-by-line, then token-wise and returns diff in form
10762// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10763// of diff chunks.
10764static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010765 ASSERT(args.length() == 2);
10766 HandleScope scope;
10767 CONVERT_ARG_CHECKED(String, s1, 0);
10768 CONVERT_ARG_CHECKED(String, s2, 1);
10769
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010770 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010771}
10772
10773
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010774
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010775// A testing entry. Returns statement position which is the closest to
10776// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010777static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010778 ASSERT(args.length() == 2);
10779 HandleScope scope;
10780 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10781 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10782
10783 Handle<Code> code(function->code());
10784
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010785 if (code->kind() != Code::FUNCTION &&
10786 code->kind() != Code::OPTIMIZED_FUNCTION) {
10787 return Heap::undefined_value();
10788 }
10789
10790 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010791 int closest_pc = 0;
10792 int distance = kMaxInt;
10793 while (!it.done()) {
10794 int statement_position = static_cast<int>(it.rinfo()->data());
10795 // Check if this break point is closer that what was previously found.
10796 if (source_position <= statement_position &&
10797 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010798 closest_pc =
10799 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010800 distance = statement_position - source_position;
10801 // Check whether we can't get any closer.
10802 if (distance == 0) break;
10803 }
10804 it.next();
10805 }
10806
10807 return Smi::FromInt(closest_pc);
10808}
10809
10810
ager@chromium.org357bf652010-04-12 11:30:10 +000010811// Calls specified function with or without entering the debugger.
10812// This is used in unit tests to run code as if debugger is entered or simply
10813// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010814static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010815 ASSERT(args.length() == 2);
10816 HandleScope scope;
10817 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10818 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10819
10820 Handle<Object> result;
10821 bool pending_exception;
10822 {
10823 if (without_debugger) {
10824 result = Execution::Call(function, Top::global(), 0, NULL,
10825 &pending_exception);
10826 } else {
10827 EnterDebugger enter_debugger;
10828 result = Execution::Call(function, Top::global(), 0, NULL,
10829 &pending_exception);
10830 }
10831 }
10832 if (!pending_exception) {
10833 return *result;
10834 } else {
10835 return Failure::Exception();
10836 }
10837}
10838
10839
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010840// Sets a v8 flag.
10841static MaybeObject* Runtime_SetFlags(Arguments args) {
10842 CONVERT_CHECKED(String, arg, args[0]);
10843 SmartPointer<char> flags =
10844 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10845 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10846 return Heap::undefined_value();
10847}
10848
10849
10850// Performs a GC.
10851// Presently, it only does a full GC.
10852static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10853 Heap::CollectAllGarbage(true);
10854 return Heap::undefined_value();
10855}
10856
10857
10858// Gets the current heap usage.
10859static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10860 int usage = static_cast<int>(Heap::SizeOfObjects());
10861 if (!Smi::IsValid(usage)) {
10862 return *Factory::NewNumberFromInt(usage);
10863 }
10864 return Smi::FromInt(usage);
10865}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010866#endif // ENABLE_DEBUGGER_SUPPORT
10867
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010868
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010869#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000010870static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010871 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010872 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010873
10874 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010875 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10876 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010877 return Heap::undefined_value();
10878}
10879
10880
lrn@chromium.org303ada72010-10-27 09:33:13 +000010881static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010882 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010883 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010884
10885 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010886 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10887 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010888 return Heap::undefined_value();
10889}
10890
10891#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010892
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010893// Finds the script object from the script data. NOTE: This operation uses
10894// heap traversal to find the function generated for the source position
10895// for the requested break point. For lazily compiled functions several heap
10896// traversals might be required rendering this operation as a rather slow
10897// operation. However for setting break points which is normally done through
10898// some kind of user interaction the performance is not crucial.
10899static Handle<Object> Runtime_GetScriptFromScriptName(
10900 Handle<String> script_name) {
10901 // Scan the heap for Script objects to find the script with the requested
10902 // script data.
10903 Handle<Script> script;
10904 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010905 HeapObject* obj = NULL;
10906 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010907 // If a script is found check if it has the script data requested.
10908 if (obj->IsScript()) {
10909 if (Script::cast(obj)->name()->IsString()) {
10910 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10911 script = Handle<Script>(Script::cast(obj));
10912 }
10913 }
10914 }
10915 }
10916
10917 // If no script with the requested script data is found return undefined.
10918 if (script.is_null()) return Factory::undefined_value();
10919
10920 // Return the script found.
10921 return GetScriptWrapper(script);
10922}
10923
10924
10925// Get the script object from script data. NOTE: Regarding performance
10926// see the NOTE for GetScriptFromScriptData.
10927// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010928static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010929 HandleScope scope;
10930
10931 ASSERT(args.length() == 1);
10932
10933 CONVERT_CHECKED(String, script_name, args[0]);
10934
10935 // Find the requested script.
10936 Handle<Object> result =
10937 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10938 return *result;
10939}
10940
10941
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010942// Determines whether the given stack frame should be displayed in
10943// a stack trace. The caller is the error constructor that asked
10944// for the stack trace to be collected. The first time a construct
10945// call to this function is encountered it is skipped. The seen_caller
10946// in/out parameter is used to remember if the caller has been seen
10947// yet.
10948static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10949 bool* seen_caller) {
10950 // Only display JS frames.
10951 if (!raw_frame->is_java_script())
10952 return false;
10953 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10954 Object* raw_fun = frame->function();
10955 // Not sure when this can happen but skip it just in case.
10956 if (!raw_fun->IsJSFunction())
10957 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010958 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010959 *seen_caller = true;
10960 return false;
10961 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010962 // Skip all frames until we've seen the caller. Also, skip the most
10963 // obvious builtin calls. Some builtin calls (such as Number.ADD
10964 // which is invoked using 'call') are very difficult to recognize
10965 // so we're leaving them in for now.
10966 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010967}
10968
10969
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010970// Collect the raw data for a stack trace. Returns an array of 4
10971// element segments each containing a receiver, function, code and
10972// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010973static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010974 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010975 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010976 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10977
10978 HandleScope scope;
10979
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010980 limit = Max(limit, 0); // Ensure that limit is not negative.
10981 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010982 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010983
10984 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010985 // If the caller parameter is a function we skip frames until we're
10986 // under it before starting to collect.
10987 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010988 int cursor = 0;
10989 int frames_seen = 0;
10990 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010991 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010992 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010993 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010994 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010995 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10996 frame->Summarize(&frames);
10997 for (int i = frames.length() - 1; i >= 0; i--) {
10998 Handle<Object> recv = frames[i].receiver();
10999 Handle<JSFunction> fun = frames[i].function();
11000 Handle<Code> code = frames[i].code();
11001 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
11002 FixedArray* elements = FixedArray::cast(result->elements());
11003 if (cursor + 3 < elements->length()) {
11004 elements->set(cursor++, *recv);
11005 elements->set(cursor++, *fun);
11006 elements->set(cursor++, *code);
11007 elements->set(cursor++, *offset);
11008 } else {
11009 SetElement(result, cursor++, recv);
11010 SetElement(result, cursor++, fun);
11011 SetElement(result, cursor++, code);
11012 SetElement(result, cursor++, offset);
11013 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011014 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011015 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011016 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011017 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011018
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011019 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011020 return *result;
11021}
11022
11023
ager@chromium.org3811b432009-10-28 14:53:37 +000011024// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011025static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011026 ASSERT_EQ(args.length(), 0);
11027
11028 NoHandleAllocation ha;
11029
11030 const char* version_string = v8::V8::GetVersion();
11031
11032 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
11033}
11034
11035
lrn@chromium.org303ada72010-10-27 09:33:13 +000011036static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011037 ASSERT(args.length() == 2);
11038 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11039 Smi::cast(args[1])->value());
11040 Top::PrintStack();
11041 OS::Abort();
11042 UNREACHABLE();
11043 return NULL;
11044}
11045
11046
lrn@chromium.org303ada72010-10-27 09:33:13 +000011047static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011048 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011049 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011050 Object* key = args[1];
11051
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011052 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011053 Object* o = cache->get(finger_index);
11054 if (o == key) {
11055 // The fastest case: hit the same place again.
11056 return cache->get(finger_index + 1);
11057 }
11058
11059 for (int i = finger_index - 2;
11060 i >= JSFunctionResultCache::kEntriesIndex;
11061 i -= 2) {
11062 o = cache->get(i);
11063 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011064 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011065 return cache->get(i + 1);
11066 }
11067 }
11068
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011069 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011070 ASSERT(size <= cache->length());
11071
11072 for (int i = size - 2; i > finger_index; i -= 2) {
11073 o = cache->get(i);
11074 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011075 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011076 return cache->get(i + 1);
11077 }
11078 }
11079
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011080 // There is no value in the cache. Invoke the function and cache result.
11081 HandleScope scope;
11082
11083 Handle<JSFunctionResultCache> cache_handle(cache);
11084 Handle<Object> key_handle(key);
11085 Handle<Object> value;
11086 {
11087 Handle<JSFunction> factory(JSFunction::cast(
11088 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11089 // TODO(antonm): consider passing a receiver when constructing a cache.
11090 Handle<Object> receiver(Top::global_context()->global());
11091 // This handle is nor shared, nor used later, so it's safe.
11092 Object** argv[] = { key_handle.location() };
11093 bool pending_exception = false;
11094 value = Execution::Call(factory,
11095 receiver,
11096 1,
11097 argv,
11098 &pending_exception);
11099 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011100 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011101
11102#ifdef DEBUG
11103 cache_handle->JSFunctionResultCacheVerify();
11104#endif
11105
11106 // Function invocation may have cleared the cache. Reread all the data.
11107 finger_index = cache_handle->finger_index();
11108 size = cache_handle->size();
11109
11110 // If we have spare room, put new data into it, otherwise evict post finger
11111 // entry which is likely to be the least recently used.
11112 int index = -1;
11113 if (size < cache_handle->length()) {
11114 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11115 index = size;
11116 } else {
11117 index = finger_index + JSFunctionResultCache::kEntrySize;
11118 if (index == cache_handle->length()) {
11119 index = JSFunctionResultCache::kEntriesIndex;
11120 }
11121 }
11122
11123 ASSERT(index % 2 == 0);
11124 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11125 ASSERT(index < cache_handle->length());
11126
11127 cache_handle->set(index, *key_handle);
11128 cache_handle->set(index + 1, *value);
11129 cache_handle->set_finger_index(index);
11130
11131#ifdef DEBUG
11132 cache_handle->JSFunctionResultCacheVerify();
11133#endif
11134
11135 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011136}
11137
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011138
11139static MaybeObject* Runtime_NewMessageObject(Arguments args) {
11140 HandleScope scope;
11141 CONVERT_ARG_CHECKED(String, type, 0);
11142 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
11143 return *Factory::NewJSMessageObject(type,
11144 arguments,
11145 0,
11146 0,
11147 Factory::undefined_value(),
11148 Factory::undefined_value(),
11149 Factory::undefined_value());
11150}
11151
11152
11153static MaybeObject* Runtime_MessageGetType(Arguments args) {
11154 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11155 return message->type();
11156}
11157
11158
11159static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
11160 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11161 return message->arguments();
11162}
11163
11164
11165static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
11166 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11167 return Smi::FromInt(message->start_position());
11168}
11169
11170
11171static MaybeObject* Runtime_MessageGetScript(Arguments args) {
11172 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11173 return message->script();
11174}
11175
11176
kasper.lund44510672008-07-25 07:37:58 +000011177#ifdef DEBUG
11178// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11179// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011180static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000011181 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011182 HandleScope scope;
11183 Handle<JSArray> result = Factory::NewJSArray(0);
11184 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011185 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011186#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011187 { \
11188 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011189 Handle<String> name; \
11190 /* Inline runtime functions have an underscore in front of the name. */ \
11191 if (inline_runtime_functions) { \
11192 name = Factory::NewStringFromAscii( \
11193 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11194 } else { \
11195 name = Factory::NewStringFromAscii( \
11196 Vector<const char>(#Name, StrLength(#Name))); \
11197 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011198 Handle<JSArray> pair = Factory::NewJSArray(0); \
11199 SetElement(pair, 0, name); \
11200 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
11201 SetElement(result, index++, pair); \
11202 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011203 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011204 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011205 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011206 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011207 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011208#undef ADD_ENTRY
11209 return *result;
11210}
kasper.lund44510672008-07-25 07:37:58 +000011211#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011212
11213
lrn@chromium.org303ada72010-10-27 09:33:13 +000011214static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011215 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011216 CONVERT_CHECKED(String, format, args[0]);
11217 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011218 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011219 Logger::LogRuntime(chars, elms);
11220 return Heap::undefined_value();
11221}
11222
11223
lrn@chromium.org303ada72010-10-27 09:33:13 +000011224static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011225 UNREACHABLE(); // implemented as macro in the parser
11226 return NULL;
11227}
11228
11229
11230// ----------------------------------------------------------------------------
11231// Implementation of Runtime
11232
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011233#define F(name, number_of_args, result_size) \
11234 { Runtime::k##name, Runtime::RUNTIME, #name, \
11235 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011236
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011237
11238#define I(name, number_of_args, result_size) \
11239 { Runtime::kInline##name, Runtime::INLINE, \
11240 "_" #name, NULL, number_of_args, result_size },
11241
11242Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011243 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011244 INLINE_FUNCTION_LIST(I)
11245 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011246};
11247
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011248
lrn@chromium.org303ada72010-10-27 09:33:13 +000011249MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011250 ASSERT(dictionary != NULL);
11251 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11252 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011253 Object* name_symbol;
11254 { MaybeObject* maybe_name_symbol =
11255 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
11256 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11257 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011258 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011259 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11260 String::cast(name_symbol),
11261 Smi::FromInt(i),
11262 PropertyDetails(NONE, NORMAL));
11263 if (!maybe_dictionary->ToObject(&dictionary)) {
11264 // Non-recoverable failure. Calling code must restart heap
11265 // initialization.
11266 return maybe_dictionary;
11267 }
11268 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011269 }
11270 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011271}
11272
11273
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011274Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11275 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
11276 if (entry != kNotFound) {
11277 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
11278 int function_index = Smi::cast(smi_index)->value();
11279 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011280 }
11281 return NULL;
11282}
11283
11284
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011285Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
11286 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11287}
11288
11289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011290void Runtime::PerformGC(Object* result) {
11291 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011292 if (failure->IsRetryAfterGC()) {
11293 // Try to do a garbage collection; ignore it if it fails. The C
11294 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011295 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011296 } else {
11297 // Handle last resort GC and make sure to allow future allocations
11298 // to grow the heap without causing GCs (if possible).
11299 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000011300 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011301 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011302}
11303
11304
11305} } // namespace v8::internal