blob: 5534db557ce53faee9c85aed9681749804354619 [file] [log] [blame]
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001// Copyright 2006-2009 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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "compiler.h"
37#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000038#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include "debug.h"
40#include "execution.h"
41#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000042#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000043#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "platform.h"
45#include "runtime.h"
46#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000047#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000048#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000049#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000050#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051
kasperl@chromium.org71affb52009-05-26 05:44:31 +000052namespace v8 {
53namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
55
ager@chromium.org3e875802009-06-29 08:26:34 +000056#define RUNTIME_ASSERT(value) \
57 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
59// Cast the given object to a value of the specified type and store
60// it in a variable with the given name. If the object is not of the
61// expected type call IllegalOperation and return.
62#define CONVERT_CHECKED(Type, name, obj) \
63 RUNTIME_ASSERT(obj->Is##Type()); \
64 Type* name = Type::cast(obj);
65
66#define CONVERT_ARG_CHECKED(Type, name, index) \
67 RUNTIME_ASSERT(args[index]->Is##Type()); \
68 Handle<Type> name = args.at<Type>(index);
69
kasper.lundbd3ec4e2008-07-09 11:06:54 +000070// Cast the given object to a boolean and store it in a variable with
71// the given name. If the object is not a boolean call IllegalOperation
72// and return.
73#define CONVERT_BOOLEAN_CHECKED(name, obj) \
74 RUNTIME_ASSERT(obj->IsBoolean()); \
75 bool name = (obj)->IsTrue();
76
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000077// Cast the given object to a Smi and store its value in an int variable
78// with the given name. If the object is not a Smi call IllegalOperation
79// and return.
80#define CONVERT_SMI_CHECKED(name, obj) \
81 RUNTIME_ASSERT(obj->IsSmi()); \
82 int name = Smi::cast(obj)->value();
83
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000084// Cast the given object to a double and store it in a variable with
85// the given name. If the object is not a number (as opposed to
86// the number not-a-number) call IllegalOperation and return.
87#define CONVERT_DOUBLE_CHECKED(name, obj) \
88 RUNTIME_ASSERT(obj->IsNumber()); \
89 double name = (obj)->Number();
90
91// Call the specified converter on the object *comand store the result in
92// a variable of the specified type with the given name. If the
93// object is not a Number call IllegalOperation and return.
94#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
95 RUNTIME_ASSERT(obj->IsNumber()); \
96 type name = NumberTo##Type(obj);
97
98// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000099static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101
lrn@chromium.org303ada72010-10-27 09:33:13 +0000102MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000103 StackLimitCheck check;
104 if (check.HasOverflowed()) return Top::StackOverflow();
105
lrn@chromium.org303ada72010-10-27 09:33:13 +0000106 Object* result;
107 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
108 if (!maybe_result->ToObject(&result)) return maybe_result;
109 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000110 JSObject* copy = JSObject::cast(result);
111
112 // Deep copy local properties.
113 if (copy->HasFastProperties()) {
114 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000115 for (int i = 0; i < properties->length(); i++) {
116 Object* value = properties->get(i);
117 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000118 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000119 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
120 if (!maybe_result->ToObject(&result)) return maybe_result;
121 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000122 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000123 }
124 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000125 int nof = copy->map()->inobject_properties();
126 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000127 Object* value = copy->InObjectPropertyAt(i);
128 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000130 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
131 if (!maybe_result->ToObject(&result)) return maybe_result;
132 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000133 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 }
135 }
136 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000137 { MaybeObject* maybe_result =
138 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000141 FixedArray* names = FixedArray::cast(result);
142 copy->GetLocalPropertyNames(names, 0);
143 for (int i = 0; i < names->length(); i++) {
144 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000145 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000147 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 // Only deep copy fields from the object literal expression.
149 // In particular, don't try to copy the length attribute of
150 // an array.
151 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000152 Object* value =
153 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000155 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
157 if (!maybe_result->ToObject(&result)) return maybe_result;
158 }
159 { MaybeObject* maybe_result =
160 copy->SetProperty(key_string, result, NONE);
161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000163 }
164 }
165 }
166
167 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000168 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000169 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000170 switch (copy->GetElementsKind()) {
171 case JSObject::FAST_ELEMENTS: {
172 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000173 if (elements->map() == Heap::fixed_cow_array_map()) {
174 Counters::cow_arrays_created_runtime.Increment();
175#ifdef DEBUG
176 for (int i = 0; i < elements->length(); i++) {
177 ASSERT(!elements->get(i)->IsJSObject());
178 }
179#endif
180 } else {
181 for (int i = 0; i < elements->length(); i++) {
182 Object* value = elements->get(i);
183 if (value->IsJSObject()) {
184 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000185 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
186 if (!maybe_result->ToObject(&result)) return maybe_result;
187 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000188 elements->set(i, result);
189 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000190 }
191 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000192 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000194 case JSObject::DICTIONARY_ELEMENTS: {
195 NumberDictionary* element_dictionary = copy->element_dictionary();
196 int capacity = element_dictionary->Capacity();
197 for (int i = 0; i < capacity; i++) {
198 Object* k = element_dictionary->KeyAt(i);
199 if (element_dictionary->IsKey(k)) {
200 Object* value = element_dictionary->ValueAt(i);
201 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000202 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000203 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
204 if (!maybe_result->ToObject(&result)) return maybe_result;
205 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000206 element_dictionary->ValueAtPut(i, result);
207 }
208 }
209 }
210 break;
211 }
212 default:
213 UNREACHABLE();
214 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000215 }
216 return copy;
217}
218
219
lrn@chromium.org303ada72010-10-27 09:33:13 +0000220static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000221 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
222 return DeepCopyBoilerplate(boilerplate);
223}
224
225
lrn@chromium.org303ada72010-10-27 09:33:13 +0000226static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000228 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000229}
230
231
ager@chromium.org236ad962008-09-25 09:45:57 +0000232static Handle<Map> ComputeObjectLiteralMap(
233 Handle<Context> context,
234 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000235 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000236 int properties_length = constant_properties->length();
237 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000238 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000239 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000240 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000241 for (int p = 0; p != properties_length; p += 2) {
242 Object* key = constant_properties->get(p);
243 uint32_t element_index = 0;
244 if (key->IsSymbol()) {
245 number_of_symbol_keys++;
246 } else if (key->ToArrayIndex(&element_index)) {
247 // An index key does not require space in the property backing store.
248 number_of_properties--;
249 } else {
250 // Bail out as a non-symbol non-index key makes caching impossible.
251 // ASSERT to make sure that the if condition after the loop is false.
252 ASSERT(number_of_symbol_keys != number_of_properties);
253 break;
254 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000255 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000256 // If we only have symbols and array indices among keys then we can
257 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000258 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000259 if ((number_of_symbol_keys == number_of_properties) &&
260 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 // Create the fixed array with the key.
262 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000263 if (number_of_symbol_keys > 0) {
264 int index = 0;
265 for (int p = 0; p < properties_length; p += 2) {
266 Object* key = constant_properties->get(p);
267 if (key->IsSymbol()) {
268 keys->set(index++, key);
269 }
270 }
271 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000272 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000273 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000274 return Factory::ObjectLiteralMapFromCache(context, keys);
275 }
276 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000277 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000278 return Factory::CopyMap(
279 Handle<Map>(context->object_function()->initial_map()),
280 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000281}
282
283
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000284static Handle<Object> CreateLiteralBoilerplate(
285 Handle<FixedArray> literals,
286 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000287
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000288
289static Handle<Object> CreateObjectLiteralBoilerplate(
290 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000291 Handle<FixedArray> constant_properties,
292 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000293 // Get the global context from the literals array. This is the
294 // context in which the function was created and we use the object
295 // function from this context to create the object literal. We do
296 // not use the object function from the current global context
297 // because this might be the object function from another context
298 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 Handle<Context> context =
300 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
301
302 bool is_result_from_cache;
303 Handle<Map> map = ComputeObjectLiteralMap(context,
304 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000305 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000306
ager@chromium.org236ad962008-09-25 09:45:57 +0000307 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000308
309 // Normalize the elements of the boilerplate to save space if needed.
310 if (!should_have_fast_elements) NormalizeElements(boilerplate);
311
ager@chromium.org32912102009-01-16 10:38:43 +0000312 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000315 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000316 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 for (int index = 0; index < length; index +=2) {
318 Handle<Object> key(constant_properties->get(index+0));
319 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000320 if (value->IsFixedArray()) {
321 // The value contains the constant_properties of a
322 // simple object literal.
323 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
324 value = CreateLiteralBoilerplate(literals, array);
325 if (value.is_null()) return value;
326 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000327 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000328 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000329 if (key->IsSymbol()) {
330 // If key is a symbol it is not an array element.
331 Handle<String> name(String::cast(*key));
332 ASSERT(!name->AsArrayIndex(&element_index));
333 result = SetProperty(boilerplate, name, value, NONE);
334 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335 // Array index (uint32).
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000336 result = SetElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337 } else {
338 // Non-uint32 number.
339 ASSERT(key->IsNumber());
340 double num = key->Number();
341 char arr[100];
342 Vector<char> buffer(arr, ARRAY_SIZE(arr));
343 const char* str = DoubleToCString(num, buffer);
344 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000345 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000347 // If setting the property on the boilerplate throws an
348 // exception, the exception is converted to an empty handle in
349 // the handle based operations. In that case, we need to
350 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000351 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000352 }
353 }
354
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000355 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000356}
357
358
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000359static Handle<Object> CreateArrayLiteralBoilerplate(
360 Handle<FixedArray> literals,
361 Handle<FixedArray> elements) {
362 // Create the JSArray.
363 Handle<JSFunction> constructor(
364 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
365 Handle<Object> object = Factory::NewJSObject(constructor);
366
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000367 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
368 Handle<FixedArray> copied_elements =
369 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000370
371 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000372 if (is_cow) {
373#ifdef DEBUG
374 // Copy-on-write arrays must be shallow (and simple).
375 for (int i = 0; i < content->length(); i++) {
376 ASSERT(!content->get(i)->IsFixedArray());
377 }
378#endif
379 } else {
380 for (int i = 0; i < content->length(); i++) {
381 if (content->get(i)->IsFixedArray()) {
382 // The value contains the constant_properties of a
383 // simple object literal.
384 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
385 Handle<Object> result =
386 CreateLiteralBoilerplate(literals, fa);
387 if (result.is_null()) return result;
388 content->set(i, *result);
389 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000390 }
391 }
392
393 // Set the elements.
394 Handle<JSArray>::cast(object)->SetContent(*content);
395 return object;
396}
397
398
399static Handle<Object> CreateLiteralBoilerplate(
400 Handle<FixedArray> literals,
401 Handle<FixedArray> array) {
402 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
403 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000404 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
405 return CreateObjectLiteralBoilerplate(literals, elements, true);
406 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
407 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408 case CompileTimeValue::ARRAY_LITERAL:
409 return CreateArrayLiteralBoilerplate(literals, elements);
410 default:
411 UNREACHABLE();
412 return Handle<Object>::null();
413 }
414}
415
416
lrn@chromium.org303ada72010-10-27 09:33:13 +0000417static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000418 // Takes a FixedArray of elements containing the literal elements of
419 // the array literal and produces JSArray with those elements.
420 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000421 // which contains the context from which to get the Array function
422 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000423 HandleScope scope;
424 ASSERT(args.length() == 3);
425 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
426 CONVERT_SMI_CHECKED(literals_index, args[1]);
427 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000429 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
430 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432 // Update the functions literal and return the boilerplate.
433 literals->set(literals_index, *object);
434 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435}
436
437
lrn@chromium.org303ada72010-10-27 09:33:13 +0000438static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000439 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000440 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000441 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
442 CONVERT_SMI_CHECKED(literals_index, args[1]);
443 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000444 CONVERT_SMI_CHECKED(fast_elements, args[3]);
445 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000446
447 // Check if boilerplate exists. If not, create it first.
448 Handle<Object> boilerplate(literals->get(literals_index));
449 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000450 boilerplate = CreateObjectLiteralBoilerplate(literals,
451 constant_properties,
452 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000453 if (boilerplate.is_null()) return Failure::Exception();
454 // Update the functions literal and return the boilerplate.
455 literals->set(literals_index, *boilerplate);
456 }
457 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
458}
459
460
lrn@chromium.org303ada72010-10-27 09:33:13 +0000461static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000462 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000463 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000464 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
465 CONVERT_SMI_CHECKED(literals_index, args[1]);
466 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000467 CONVERT_SMI_CHECKED(fast_elements, args[3]);
468 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000469
470 // Check if boilerplate exists. If not, create it first.
471 Handle<Object> boilerplate(literals->get(literals_index));
472 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000473 boilerplate = CreateObjectLiteralBoilerplate(literals,
474 constant_properties,
475 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000476 if (boilerplate.is_null()) return Failure::Exception();
477 // Update the functions literal and return the boilerplate.
478 literals->set(literals_index, *boilerplate);
479 }
480 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
481}
482
483
lrn@chromium.org303ada72010-10-27 09:33:13 +0000484static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000485 HandleScope scope;
486 ASSERT(args.length() == 3);
487 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
488 CONVERT_SMI_CHECKED(literals_index, args[1]);
489 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
490
491 // Check if boilerplate exists. If not, create it first.
492 Handle<Object> boilerplate(literals->get(literals_index));
493 if (*boilerplate == Heap::undefined_value()) {
494 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
495 if (boilerplate.is_null()) return Failure::Exception();
496 // Update the functions literal and return the boilerplate.
497 literals->set(literals_index, *boilerplate);
498 }
499 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
500}
501
502
lrn@chromium.org303ada72010-10-27 09:33:13 +0000503static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000504 HandleScope scope;
505 ASSERT(args.length() == 3);
506 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
507 CONVERT_SMI_CHECKED(literals_index, args[1]);
508 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
509
510 // Check if boilerplate exists. If not, create it first.
511 Handle<Object> boilerplate(literals->get(literals_index));
512 if (*boilerplate == Heap::undefined_value()) {
513 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
514 if (boilerplate.is_null()) return Failure::Exception();
515 // Update the functions literal and return the boilerplate.
516 literals->set(literals_index, *boilerplate);
517 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000518 if (JSObject::cast(*boilerplate)->elements()->map() ==
519 Heap::fixed_cow_array_map()) {
520 Counters::cow_arrays_created_runtime.Increment();
521 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000522 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
523}
524
525
lrn@chromium.org303ada72010-10-27 09:33:13 +0000526static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000527 ASSERT(args.length() == 2);
528 CONVERT_CHECKED(String, key, args[0]);
529 Object* value = args[1];
530 // Create a catch context extension object.
531 JSFunction* constructor =
532 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000533 Object* object;
534 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
535 if (!maybe_object->ToObject(&object)) return maybe_object;
536 }
ager@chromium.org32912102009-01-16 10:38:43 +0000537 // Assign the exception value to the catch variable and make sure
538 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000539 { MaybeObject* maybe_value =
540 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
541 if (!maybe_value->ToObject(&value)) return maybe_value;
542 }
ager@chromium.org32912102009-01-16 10:38:43 +0000543 return object;
544}
545
546
lrn@chromium.org303ada72010-10-27 09:33:13 +0000547static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 NoHandleAllocation ha;
549 ASSERT(args.length() == 1);
550 Object* obj = args[0];
551 if (!obj->IsJSObject()) return Heap::null_value();
552 return JSObject::cast(obj)->class_name();
553}
554
ager@chromium.org7c537e22008-10-16 08:43:32 +0000555
lrn@chromium.org303ada72010-10-27 09:33:13 +0000556static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 NoHandleAllocation ha;
558 ASSERT(args.length() == 2);
559 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
560 Object* O = args[0];
561 Object* V = args[1];
562 while (true) {
563 Object* prototype = V->GetPrototype();
564 if (prototype->IsNull()) return Heap::false_value();
565 if (O == prototype) return Heap::true_value();
566 V = prototype;
567 }
568}
569
570
ager@chromium.org9085a012009-05-11 19:22:57 +0000571// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000572static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000573 NoHandleAllocation ha;
574 ASSERT(args.length() == 2);
575 CONVERT_CHECKED(JSObject, jsobject, args[0]);
576 CONVERT_CHECKED(JSObject, proto, args[1]);
577
578 // Sanity checks. The old prototype (that we are replacing) could
579 // theoretically be null, but if it is not null then check that we
580 // didn't already install a hidden prototype here.
581 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
582 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
583 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
584
585 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000586 Object* map_or_failure;
587 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
588 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
589 return maybe_map_or_failure;
590 }
591 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000592 Map* new_proto_map = Map::cast(map_or_failure);
593
lrn@chromium.org303ada72010-10-27 09:33:13 +0000594 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
595 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
596 return maybe_map_or_failure;
597 }
598 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000599 Map* new_map = Map::cast(map_or_failure);
600
601 // Set proto's prototype to be the old prototype of the object.
602 new_proto_map->set_prototype(jsobject->GetPrototype());
603 proto->set_map(new_proto_map);
604 new_proto_map->set_is_hidden_prototype();
605
606 // Set the object's prototype to proto.
607 new_map->set_prototype(proto);
608 jsobject->set_map(new_map);
609
610 return Heap::undefined_value();
611}
612
613
lrn@chromium.org303ada72010-10-27 09:33:13 +0000614static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000616 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617 JavaScriptFrameIterator it;
618 return Heap::ToBoolean(it.frame()->IsConstructor());
619}
620
621
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000622// Recursively traverses hidden prototypes if property is not found
623static void GetOwnPropertyImplementation(JSObject* obj,
624 String* name,
625 LookupResult* result) {
626 obj->LocalLookupRealNamedProperty(name, result);
627
628 if (!result->IsProperty()) {
629 Object* proto = obj->GetPrototype();
630 if (proto->IsJSObject() &&
631 JSObject::cast(proto)->map()->is_hidden_prototype())
632 GetOwnPropertyImplementation(JSObject::cast(proto),
633 name, result);
634 }
635}
636
637
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000638// Enumerator used as indices into the array returned from GetOwnProperty
639enum PropertyDescriptorIndices {
640 IS_ACCESSOR_INDEX,
641 VALUE_INDEX,
642 GETTER_INDEX,
643 SETTER_INDEX,
644 WRITABLE_INDEX,
645 ENUMERABLE_INDEX,
646 CONFIGURABLE_INDEX,
647 DESCRIPTOR_SIZE
648};
649
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000650// Returns an array with the property description:
651// if args[1] is not a property on args[0]
652// returns undefined
653// if args[1] is a data property on args[0]
654// [false, value, Writeable, Enumerable, Configurable]
655// if args[1] is an accessor on args[0]
656// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000657static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000658 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000659 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000660 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000661 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
662 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000663 CONVERT_ARG_CHECKED(JSObject, obj, 0);
664 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000665
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000666 // This could be an element.
667 uint32_t index;
668 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000669 switch (obj->HasLocalElement(index)) {
670 case JSObject::UNDEFINED_ELEMENT:
671 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000672
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000673 case JSObject::STRING_CHARACTER_ELEMENT: {
674 // Special handling of string objects according to ECMAScript 5
675 // 15.5.5.2. Note that this might be a string object with elements
676 // other than the actual string value. This is covered by the
677 // subsequent cases.
678 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
679 Handle<String> str(String::cast(js_value->value()));
680 Handle<String> substr = SubString(str, index, index+1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000681
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000682 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
683 elms->set(VALUE_INDEX, *substr);
684 elms->set(WRITABLE_INDEX, Heap::false_value());
685 elms->set(ENUMERABLE_INDEX, Heap::false_value());
686 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
687 return *desc;
688 }
689
690 case JSObject::INTERCEPTED_ELEMENT:
691 case JSObject::FAST_ELEMENT: {
692 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
693 Handle<Object> element = GetElement(Handle<Object>(obj), index);
694 elms->set(VALUE_INDEX, *element);
695 elms->set(WRITABLE_INDEX, Heap::true_value());
696 elms->set(ENUMERABLE_INDEX, Heap::true_value());
697 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
698 return *desc;
699 }
700
701 case JSObject::DICTIONARY_ELEMENT: {
702 NumberDictionary* dictionary = obj->element_dictionary();
703 int entry = dictionary->FindEntry(index);
704 ASSERT(entry != NumberDictionary::kNotFound);
705 PropertyDetails details = dictionary->DetailsAt(entry);
706 switch (details.type()) {
707 case CALLBACKS: {
708 // This is an accessor property with getter and/or setter.
709 FixedArray* callbacks =
710 FixedArray::cast(dictionary->ValueAt(entry));
711 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
712 elms->set(GETTER_INDEX, callbacks->get(0));
713 elms->set(SETTER_INDEX, callbacks->get(1));
714 break;
715 }
716 case NORMAL:
717 // This is a data property.
718 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
719 elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
720 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
721 break;
722 default:
723 UNREACHABLE();
724 break;
725 }
726 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
727 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
728 return *desc;
729 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000730 }
731 }
732
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000733 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000734 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000735
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000736 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000737 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000738 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000739 if (result.type() == CALLBACKS) {
740 Object* structure = result.GetCallbackObject();
ager@chromium.org5c838252010-02-19 08:53:10 +0000741 if (structure->IsProxy() || structure->IsAccessorInfo()) {
742 // Property that is internally implemented as a callback or
743 // an API defined callback.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000744 Object* value;
745 { MaybeObject* maybe_value = obj->GetPropertyWithCallback(
746 *obj, structure, *name, result.holder());
747 if (!maybe_value->ToObject(&value)) return maybe_value;
748 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000749 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
750 elms->set(VALUE_INDEX, value);
751 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000752 } else if (structure->IsFixedArray()) {
753 // __defineGetter__/__defineSetter__ callback.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000754 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
755 elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
756 elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000757 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758 return Heap::undefined_value();
759 }
760 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000761 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
762 elms->set(VALUE_INDEX, result.GetLazyValue());
763 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000764 }
765
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000766 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
767 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000768 return *desc;
769}
770
771
lrn@chromium.org303ada72010-10-27 09:33:13 +0000772static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000773 ASSERT(args.length() == 1);
774 CONVERT_CHECKED(JSObject, obj, args[0]);
775 return obj->PreventExtensions();
776}
777
lrn@chromium.org303ada72010-10-27 09:33:13 +0000778static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000779 ASSERT(args.length() == 1);
780 CONVERT_CHECKED(JSObject, obj, args[0]);
781 return obj->map()->is_extensible() ? Heap::true_value()
782 : Heap::false_value();
783}
784
785
lrn@chromium.org303ada72010-10-27 09:33:13 +0000786static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000787 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000788 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000789 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
790 CONVERT_ARG_CHECKED(String, pattern, 1);
791 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000792 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
793 if (result.is_null()) return Failure::Exception();
794 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795}
796
797
lrn@chromium.org303ada72010-10-27 09:33:13 +0000798static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000799 HandleScope scope;
800 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000801 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000802 return *Factory::CreateApiFunction(data);
803}
804
805
lrn@chromium.org303ada72010-10-27 09:33:13 +0000806static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807 ASSERT(args.length() == 1);
808 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000809 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000810 return Heap::ToBoolean(result);
811}
812
813
lrn@chromium.org303ada72010-10-27 09:33:13 +0000814static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000815 ASSERT(args.length() == 2);
816 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000817 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000818 int index = field->value();
819 int offset = index * kPointerSize + HeapObject::kHeaderSize;
820 InstanceType type = templ->map()->instance_type();
821 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
822 type == OBJECT_TEMPLATE_INFO_TYPE);
823 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000824 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000825 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
826 } else {
827 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
828 }
829 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830}
831
832
lrn@chromium.org303ada72010-10-27 09:33:13 +0000833static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000834 ASSERT(args.length() == 1);
835 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000836 Map* old_map = object->map();
837 bool needs_access_checks = old_map->is_access_check_needed();
838 if (needs_access_checks) {
839 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000840 Object* new_map;
841 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
842 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
843 }
ager@chromium.org32912102009-01-16 10:38:43 +0000844
845 Map::cast(new_map)->set_is_access_check_needed(false);
846 object->set_map(Map::cast(new_map));
847 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000848 return needs_access_checks ? Heap::true_value() : Heap::false_value();
849}
850
851
lrn@chromium.org303ada72010-10-27 09:33:13 +0000852static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000853 ASSERT(args.length() == 1);
854 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000855 Map* old_map = object->map();
856 if (!old_map->is_access_check_needed()) {
857 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000858 Object* new_map;
859 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
860 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
861 }
ager@chromium.org32912102009-01-16 10:38:43 +0000862
863 Map::cast(new_map)->set_is_access_check_needed(true);
864 object->set_map(Map::cast(new_map));
865 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000866 return Heap::undefined_value();
867}
868
869
lrn@chromium.org303ada72010-10-27 09:33:13 +0000870static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 HandleScope scope;
872 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
873 Handle<Object> args[2] = { type_handle, name };
874 Handle<Object> error =
875 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
876 return Top::Throw(*error);
877}
878
879
lrn@chromium.org303ada72010-10-27 09:33:13 +0000880static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 HandleScope scope;
882 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
883
ager@chromium.org3811b432009-10-28 14:53:37 +0000884 Handle<Context> context = args.at<Context>(0);
885 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 bool is_eval = Smi::cast(args[2])->value() == 1;
887
888 // Compute the property attributes. According to ECMA-262, section
889 // 13, page 71, the property must be read-only and
890 // non-deletable. However, neither SpiderMonkey nor KJS creates the
891 // property as read-only, so we don't either.
892 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
893
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894 // Traverse the name/value pairs and set the properties.
895 int length = pairs->length();
896 for (int i = 0; i < length; i += 2) {
897 HandleScope scope;
898 Handle<String> name(String::cast(pairs->get(i)));
899 Handle<Object> value(pairs->get(i + 1));
900
901 // We have to declare a global const property. To capture we only
902 // assign to it when evaluating the assignment for "const x =
903 // <expr>" the initial value is the hole.
904 bool is_const_property = value->IsTheHole();
905
906 if (value->IsUndefined() || is_const_property) {
907 // Lookup the property in the global object, and don't set the
908 // value of the variable if the property is already there.
909 LookupResult lookup;
910 global->Lookup(*name, &lookup);
911 if (lookup.IsProperty()) {
912 // Determine if the property is local by comparing the holder
913 // against the global object. The information will be used to
914 // avoid throwing re-declaration errors when declaring
915 // variables or constants that exist in the prototype chain.
916 bool is_local = (*global == lookup.holder());
917 // Get the property attributes and determine if the property is
918 // read-only.
919 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
920 bool is_read_only = (attributes & READ_ONLY) != 0;
921 if (lookup.type() == INTERCEPTOR) {
922 // If the interceptor says the property is there, we
923 // just return undefined without overwriting the property.
924 // Otherwise, we continue to setting the property.
925 if (attributes != ABSENT) {
926 // Check if the existing property conflicts with regards to const.
927 if (is_local && (is_read_only || is_const_property)) {
928 const char* type = (is_read_only) ? "const" : "var";
929 return ThrowRedeclarationError(type, name);
930 };
931 // The property already exists without conflicting: Go to
932 // the next declaration.
933 continue;
934 }
935 // Fall-through and introduce the absent property by using
936 // SetProperty.
937 } else {
938 if (is_local && (is_read_only || is_const_property)) {
939 const char* type = (is_read_only) ? "const" : "var";
940 return ThrowRedeclarationError(type, name);
941 }
942 // The property already exists without conflicting: Go to
943 // the next declaration.
944 continue;
945 }
946 }
947 } else {
948 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000949 Handle<SharedFunctionInfo> shared =
950 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000951 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000952 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000953 value = function;
954 }
955
956 LookupResult lookup;
957 global->LocalLookup(*name, &lookup);
958
959 PropertyAttributes attributes = is_const_property
960 ? static_cast<PropertyAttributes>(base | READ_ONLY)
961 : base;
962
963 if (lookup.IsProperty()) {
964 // There's a local property that we need to overwrite because
965 // we're either declaring a function or there's an interceptor
966 // that claims the property is absent.
967
968 // Check for conflicting re-declarations. We cannot have
969 // conflicting types in case of intercepted properties because
970 // they are absent.
971 if (lookup.type() != INTERCEPTOR &&
972 (lookup.IsReadOnly() || is_const_property)) {
973 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
974 return ThrowRedeclarationError(type, name);
975 }
976 SetProperty(global, name, value, attributes);
977 } else {
978 // If a property with this name does not already exist on the
979 // global object add the property locally. We take special
980 // precautions to always add it as a local property even in case
981 // of callbacks in the prototype chain (this rules out using
982 // SetProperty). Also, we must use the handle-based version to
983 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000984 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985 }
986 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 return Heap::undefined_value();
989}
990
991
lrn@chromium.org303ada72010-10-27 09:33:13 +0000992static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000994 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995
ager@chromium.org7c537e22008-10-16 08:43:32 +0000996 CONVERT_ARG_CHECKED(Context, context, 0);
997 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000999 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001000 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001001 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002
1003 // Declarations are always done in the function context.
1004 context = Handle<Context>(context->fcontext());
1005
1006 int index;
1007 PropertyAttributes attributes;
1008 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001009 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 context->Lookup(name, flags, &index, &attributes);
1011
1012 if (attributes != ABSENT) {
1013 // The name was declared before; check for conflicting
1014 // re-declarations: This is similar to the code in parser.cc in
1015 // the AstBuildingParser::Declare function.
1016 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1017 // Functions are not read-only.
1018 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1019 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1020 return ThrowRedeclarationError(type, name);
1021 }
1022
1023 // Initialize it if necessary.
1024 if (*initial_value != NULL) {
1025 if (index >= 0) {
1026 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001027 // the function context or the arguments object.
1028 if (holder->IsContext()) {
1029 ASSERT(holder.is_identical_to(context));
1030 if (((attributes & READ_ONLY) == 0) ||
1031 context->get(index)->IsTheHole()) {
1032 context->set(index, *initial_value);
1033 }
1034 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001035 // The holder is an arguments object.
1036 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1037 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038 }
1039 } else {
1040 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001041 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001042 SetProperty(context_ext, name, initial_value, mode);
1043 }
1044 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001045
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001047 // The property is not in the function context. It needs to be
1048 // "declared" in the function context's extension context, or in the
1049 // global context.
1050 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001051 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001052 // The function context's extension context exists - use it.
1053 context_ext = Handle<JSObject>(context->extension());
1054 } else {
1055 // The function context's extension context does not exists - allocate
1056 // it.
1057 context_ext = Factory::NewJSObject(Top::context_extension_function());
1058 // And store it in the extension slot.
1059 context->set_extension(*context_ext);
1060 }
1061 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062
ager@chromium.org7c537e22008-10-16 08:43:32 +00001063 // Declare the property by setting it to the initial value if provided,
1064 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1065 // constant declarations).
1066 ASSERT(!context_ext->HasLocalProperty(*name));
1067 Handle<Object> value(Heap::undefined_value());
1068 if (*initial_value != NULL) value = initial_value;
1069 SetProperty(context_ext, name, value, mode);
1070 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1071 }
1072
1073 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074}
1075
1076
lrn@chromium.org303ada72010-10-27 09:33:13 +00001077static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078 NoHandleAllocation nha;
1079
1080 // Determine if we need to assign to the variable if it already
1081 // exists (based on the number of arguments).
1082 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1083 bool assign = args.length() == 2;
1084
1085 CONVERT_ARG_CHECKED(String, name, 0);
1086 GlobalObject* global = Top::context()->global();
1087
1088 // According to ECMA-262, section 12.2, page 62, the property must
1089 // not be deletable.
1090 PropertyAttributes attributes = DONT_DELETE;
1091
1092 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001093 // there, there is a property with this name in the prototype chain.
1094 // We follow Safari and Firefox behavior and only set the property
1095 // locally if there is an explicit initialization value that we have
1096 // to assign to the property. When adding the property we take
1097 // special precautions to always add it as a local property even in
1098 // case of callbacks in the prototype chain (this rules out using
1099 // SetProperty). We have IgnoreAttributesAndSetLocalProperty for
1100 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001101 // Note that objects can have hidden prototypes, so we need to traverse
1102 // the whole chain of hidden prototypes to do a 'local' lookup.
1103 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001105 while (true) {
1106 real_holder->LocalLookup(*name, &lookup);
1107 if (lookup.IsProperty()) {
1108 // Determine if this is a redeclaration of something read-only.
1109 if (lookup.IsReadOnly()) {
1110 // If we found readonly property on one of hidden prototypes,
1111 // just shadow it.
1112 if (real_holder != Top::context()->global()) break;
1113 return ThrowRedeclarationError("const", name);
1114 }
1115
1116 // Determine if this is a redeclaration of an intercepted read-only
1117 // property and figure out if the property exists at all.
1118 bool found = true;
1119 PropertyType type = lookup.type();
1120 if (type == INTERCEPTOR) {
1121 HandleScope handle_scope;
1122 Handle<JSObject> holder(real_holder);
1123 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1124 real_holder = *holder;
1125 if (intercepted == ABSENT) {
1126 // The interceptor claims the property isn't there. We need to
1127 // make sure to introduce it.
1128 found = false;
1129 } else if ((intercepted & READ_ONLY) != 0) {
1130 // The property is present, but read-only. Since we're trying to
1131 // overwrite it with a variable declaration we must throw a
1132 // re-declaration error. However if we found readonly property
1133 // on one of hidden prototypes, just shadow it.
1134 if (real_holder != Top::context()->global()) break;
1135 return ThrowRedeclarationError("const", name);
1136 }
1137 }
1138
1139 if (found && !assign) {
1140 // The global property is there and we're not assigning any value
1141 // to it. Just return.
1142 return Heap::undefined_value();
1143 }
1144
1145 // Assign the value (or undefined) to the property.
1146 Object* value = (assign) ? args[1] : Heap::undefined_value();
1147 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001148 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001149
1150 Object* proto = real_holder->GetPrototype();
1151 if (!proto->IsJSObject())
1152 break;
1153
1154 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1155 break;
1156
1157 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001158 }
1159
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001160 global = Top::context()->global();
1161 if (assign) {
1162 return global->IgnoreAttributesAndSetLocalProperty(*name,
1163 args[1],
1164 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001166 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167}
1168
1169
lrn@chromium.org303ada72010-10-27 09:33:13 +00001170static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001171 // All constants are declared with an initial value. The name
1172 // of the constant is the first argument and the initial value
1173 // is the second.
1174 RUNTIME_ASSERT(args.length() == 2);
1175 CONVERT_ARG_CHECKED(String, name, 0);
1176 Handle<Object> value = args.at<Object>(1);
1177
1178 // Get the current global object from top.
1179 GlobalObject* global = Top::context()->global();
1180
1181 // According to ECMA-262, section 12.2, page 62, the property must
1182 // not be deletable. Since it's a const, it must be READ_ONLY too.
1183 PropertyAttributes attributes =
1184 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1185
1186 // Lookup the property locally in the global object. If it isn't
1187 // there, we add the property and take special precautions to always
1188 // add it as a local property even in case of callbacks in the
1189 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001190 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191 LookupResult lookup;
1192 global->LocalLookup(*name, &lookup);
1193 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001194 return global->IgnoreAttributesAndSetLocalProperty(*name,
1195 *value,
1196 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 }
1198
1199 // Determine if this is a redeclaration of something not
1200 // read-only. In case the result is hidden behind an interceptor we
1201 // need to ask it for the property attributes.
1202 if (!lookup.IsReadOnly()) {
1203 if (lookup.type() != INTERCEPTOR) {
1204 return ThrowRedeclarationError("var", name);
1205 }
1206
1207 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1208
1209 // Throw re-declaration error if the intercepted property is present
1210 // but not read-only.
1211 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1212 return ThrowRedeclarationError("var", name);
1213 }
1214
1215 // Restore global object from context (in case of GC) and continue
1216 // with setting the value because the property is either absent or
1217 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001218 HandleScope handle_scope;
1219 Handle<GlobalObject>global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220
1221 // BUG 1213579: Handle the case where we have to set a read-only
1222 // property through an interceptor and only do it if it's
1223 // uninitialized, e.g. the hole. Nirk...
lrn@chromium.org303ada72010-10-27 09:33:13 +00001224 SetProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001225 return *value;
1226 }
1227
1228 // Set the value, but only we're assigning the initial value to a
1229 // constant. For now, we determine this by checking if the
1230 // current value is the hole.
1231 PropertyType type = lookup.type();
1232 if (type == FIELD) {
1233 FixedArray* properties = global->properties();
1234 int index = lookup.GetFieldIndex();
1235 if (properties->get(index)->IsTheHole()) {
1236 properties->set(index, *value);
1237 }
1238 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001239 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1240 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 }
1242 } else {
1243 // Ignore re-initialization of constants that have already been
1244 // assigned a function value.
1245 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1246 }
1247
1248 // Use the set value as the result of the operation.
1249 return *value;
1250}
1251
1252
lrn@chromium.org303ada72010-10-27 09:33:13 +00001253static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254 HandleScope scope;
1255 ASSERT(args.length() == 3);
1256
1257 Handle<Object> value(args[0]);
1258 ASSERT(!value->IsTheHole());
1259 CONVERT_ARG_CHECKED(Context, context, 1);
1260 Handle<String> name(String::cast(args[2]));
1261
1262 // Initializations are always done in the function context.
1263 context = Handle<Context>(context->fcontext());
1264
1265 int index;
1266 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001267 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001268 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269 context->Lookup(name, flags, &index, &attributes);
1270
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001271 // In most situations, the property introduced by the const
1272 // declaration should be present in the context extension object.
1273 // However, because declaration and initialization are separate, the
1274 // property might have been deleted (if it was introduced by eval)
1275 // before we reach the initialization point.
1276 //
1277 // Example:
1278 //
1279 // function f() { eval("delete x; const x;"); }
1280 //
1281 // In that case, the initialization behaves like a normal assignment
1282 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001284 // Property was found in a context.
1285 if (holder->IsContext()) {
1286 // The holder cannot be the function context. If it is, there
1287 // should have been a const redeclaration error when declaring
1288 // the const property.
1289 ASSERT(!holder.is_identical_to(context));
1290 if ((attributes & READ_ONLY) == 0) {
1291 Handle<Context>::cast(holder)->set(index, *value);
1292 }
1293 } else {
1294 // The holder is an arguments object.
1295 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001296 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1297 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 }
1299 return *value;
1300 }
1301
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001302 // The property could not be found, we introduce it in the global
1303 // context.
1304 if (attributes == ABSENT) {
1305 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1306 SetProperty(global, name, value, NONE);
1307 return *value;
1308 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001310 // The property was present in a context extension object.
1311 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001313 if (*context_ext == context->extension()) {
1314 // This is the property that was introduced by the const
1315 // declaration. Set it if it hasn't been set before. NOTE: We
1316 // cannot use GetProperty() to get the current value as it
1317 // 'unholes' the value.
1318 LookupResult lookup;
1319 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1320 ASSERT(lookup.IsProperty()); // the property was declared
1321 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1322
1323 PropertyType type = lookup.type();
1324 if (type == FIELD) {
1325 FixedArray* properties = context_ext->properties();
1326 int index = lookup.GetFieldIndex();
1327 if (properties->get(index)->IsTheHole()) {
1328 properties->set(index, *value);
1329 }
1330 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001331 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1332 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001333 }
1334 } else {
1335 // We should not reach here. Any real, named property should be
1336 // either a field or a dictionary slot.
1337 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 }
1339 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001340 // The property was found in a different context extension object.
1341 // Set it if it is not a read-only property.
1342 if ((attributes & READ_ONLY) == 0) {
1343 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1344 // Setting a property might throw an exception. Exceptions
1345 // are converted to empty handles in handle operations. We
1346 // need to convert back to exceptions here.
1347 if (set.is_null()) {
1348 ASSERT(Top::has_pending_exception());
1349 return Failure::Exception();
1350 }
1351 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001353
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001354 return *value;
1355}
1356
1357
lrn@chromium.org303ada72010-10-27 09:33:13 +00001358static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001359 Arguments args) {
1360 HandleScope scope;
1361 ASSERT(args.length() == 2);
1362 CONVERT_ARG_CHECKED(JSObject, object, 0);
1363 CONVERT_SMI_CHECKED(properties, args[1]);
1364 if (object->HasFastProperties()) {
1365 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1366 }
1367 return *object;
1368}
1369
1370
lrn@chromium.org303ada72010-10-27 09:33:13 +00001371static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001373 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001374 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1375 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001376 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001377 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001378 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001379 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001380 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001381 RUNTIME_ASSERT(index >= 0);
1382 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001383 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001384 Handle<Object> result = RegExpImpl::Exec(regexp,
1385 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001386 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001387 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001388 if (result.is_null()) return Failure::Exception();
1389 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390}
1391
1392
lrn@chromium.org303ada72010-10-27 09:33:13 +00001393static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001394 ASSERT(args.length() == 3);
1395 CONVERT_SMI_CHECKED(elements_count, args[0]);
1396 if (elements_count > JSArray::kMaxFastElementsLength) {
1397 return Top::ThrowIllegalOperation();
1398 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001399 Object* new_object;
1400 { MaybeObject* maybe_new_object =
1401 Heap::AllocateFixedArrayWithHoles(elements_count);
1402 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1403 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001404 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001405 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1406 NEW_SPACE,
1407 OLD_POINTER_SPACE);
1408 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1409 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001410 {
1411 AssertNoAllocation no_gc;
1412 HandleScope scope;
1413 reinterpret_cast<HeapObject*>(new_object)->
1414 set_map(Top::global_context()->regexp_result_map());
1415 }
1416 JSArray* array = JSArray::cast(new_object);
1417 array->set_properties(Heap::empty_fixed_array());
1418 array->set_elements(elements);
1419 array->set_length(Smi::FromInt(elements_count));
1420 // Write in-object properties after the length of the array.
1421 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1422 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1423 return array;
1424}
1425
1426
lrn@chromium.org303ada72010-10-27 09:33:13 +00001427static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001428 AssertNoAllocation no_alloc;
1429 ASSERT(args.length() == 5);
1430 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1431 CONVERT_CHECKED(String, source, args[1]);
1432
1433 Object* global = args[2];
1434 if (!global->IsTrue()) global = Heap::false_value();
1435
1436 Object* ignoreCase = args[3];
1437 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1438
1439 Object* multiline = args[4];
1440 if (!multiline->IsTrue()) multiline = Heap::false_value();
1441
1442 Map* map = regexp->map();
1443 Object* constructor = map->constructor();
1444 if (constructor->IsJSFunction() &&
1445 JSFunction::cast(constructor)->initial_map() == map) {
1446 // If we still have the original map, set in-object properties directly.
1447 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1448 // TODO(lrn): Consider skipping write barrier on booleans as well.
1449 // Both true and false should be in oldspace at all times.
1450 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1451 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1452 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1453 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1454 Smi::FromInt(0),
1455 SKIP_WRITE_BARRIER);
1456 return regexp;
1457 }
1458
lrn@chromium.org303ada72010-10-27 09:33:13 +00001459 // Map has changed, so use generic, but slower, method. Since these
1460 // properties were all added as DONT_DELETE they must be present and
1461 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001462 PropertyAttributes final =
1463 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1464 PropertyAttributes writable =
1465 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001466 MaybeObject* result;
1467 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(),
1468 source,
1469 final);
1470 ASSERT(!result->IsFailure());
1471 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(),
1472 global,
1473 final);
1474 ASSERT(!result->IsFailure());
1475 result =
1476 regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(),
1477 ignoreCase,
1478 final);
1479 ASSERT(!result->IsFailure());
1480 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(),
1481 multiline,
1482 final);
1483 ASSERT(!result->IsFailure());
1484 result =
1485 regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(),
1486 Smi::FromInt(0),
1487 writable);
1488 ASSERT(!result->IsFailure());
1489 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001490 return regexp;
1491}
1492
1493
lrn@chromium.org303ada72010-10-27 09:33:13 +00001494static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001495 HandleScope scope;
1496 ASSERT(args.length() == 1);
1497 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1498 // This is necessary to enable fast checks for absence of elements
1499 // on Array.prototype and below.
1500 prototype->set_elements(Heap::empty_fixed_array());
1501 return Smi::FromInt(0);
1502}
1503
1504
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001505static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1506 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001507 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001508 Handle<String> key = Factory::LookupAsciiSymbol(name);
1509 Handle<Code> code(Builtins::builtin(builtin_name));
1510 Handle<JSFunction> optimized = Factory::NewFunction(key,
1511 JS_OBJECT_TYPE,
1512 JSObject::kHeaderSize,
1513 code,
1514 false);
1515 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001516 SetProperty(holder, key, optimized, NONE);
1517 return optimized;
1518}
1519
1520
lrn@chromium.org303ada72010-10-27 09:33:13 +00001521static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001522 HandleScope scope;
1523 ASSERT(args.length() == 1);
1524 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1525
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001526 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1527 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001528 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1529 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1530 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1531 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001532 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001533
1534 return *holder;
1535}
1536
1537
lrn@chromium.org303ada72010-10-27 09:33:13 +00001538static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001539 // Returns a real global receiver, not one of builtins object.
1540 Context* global_context = Top::context()->global()->global_context();
1541 return global_context->global()->global_receiver();
1542}
1543
1544
lrn@chromium.org303ada72010-10-27 09:33:13 +00001545static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546 HandleScope scope;
1547 ASSERT(args.length() == 4);
1548 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1549 int index = Smi::cast(args[1])->value();
1550 Handle<String> pattern = args.at<String>(2);
1551 Handle<String> flags = args.at<String>(3);
1552
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001553 // Get the RegExp function from the context in the literals array.
1554 // This is the RegExp function from the context in which the
1555 // function was created. We do not use the RegExp function from the
1556 // current global context because this might be the RegExp function
1557 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001558 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001559 Handle<JSFunction>(
1560 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 // Compute the regular expression literal.
1562 bool has_pending_exception;
1563 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001564 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1565 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566 if (has_pending_exception) {
1567 ASSERT(Top::has_pending_exception());
1568 return Failure::Exception();
1569 }
1570 literals->set(index, *regexp);
1571 return *regexp;
1572}
1573
1574
lrn@chromium.org303ada72010-10-27 09:33:13 +00001575static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 NoHandleAllocation ha;
1577 ASSERT(args.length() == 1);
1578
1579 CONVERT_CHECKED(JSFunction, f, args[0]);
1580 return f->shared()->name();
1581}
1582
1583
lrn@chromium.org303ada72010-10-27 09:33:13 +00001584static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001585 NoHandleAllocation ha;
1586 ASSERT(args.length() == 2);
1587
1588 CONVERT_CHECKED(JSFunction, f, args[0]);
1589 CONVERT_CHECKED(String, name, args[1]);
1590 f->shared()->set_name(name);
1591 return Heap::undefined_value();
1592}
1593
1594
lrn@chromium.org303ada72010-10-27 09:33:13 +00001595static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001596 NoHandleAllocation ha;
1597 ASSERT(args.length() == 1);
1598
1599 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001600 Object* obj;
1601 { MaybeObject* maybe_obj = f->RemovePrototype();
1602 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1603 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001604
1605 return Heap::undefined_value();
1606}
1607
1608
lrn@chromium.org303ada72010-10-27 09:33:13 +00001609static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001610 HandleScope scope;
1611 ASSERT(args.length() == 1);
1612
1613 CONVERT_CHECKED(JSFunction, fun, args[0]);
1614 Handle<Object> script = Handle<Object>(fun->shared()->script());
1615 if (!script->IsScript()) return Heap::undefined_value();
1616
1617 return *GetScriptWrapper(Handle<Script>::cast(script));
1618}
1619
1620
lrn@chromium.org303ada72010-10-27 09:33:13 +00001621static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001622 NoHandleAllocation ha;
1623 ASSERT(args.length() == 1);
1624
1625 CONVERT_CHECKED(JSFunction, f, args[0]);
1626 return f->shared()->GetSourceCode();
1627}
1628
1629
lrn@chromium.org303ada72010-10-27 09:33:13 +00001630static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 NoHandleAllocation ha;
1632 ASSERT(args.length() == 1);
1633
1634 CONVERT_CHECKED(JSFunction, fun, args[0]);
1635 int pos = fun->shared()->start_position();
1636 return Smi::FromInt(pos);
1637}
1638
1639
lrn@chromium.org303ada72010-10-27 09:33:13 +00001640static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001641 ASSERT(args.length() == 2);
1642
1643 CONVERT_CHECKED(JSFunction, fun, args[0]);
1644 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1645
1646 Code* code = fun->code();
1647 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1648
1649 Address pc = code->address() + offset;
1650 return Smi::FromInt(fun->code()->SourcePosition(pc));
1651}
1652
1653
1654
lrn@chromium.org303ada72010-10-27 09:33:13 +00001655static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001656 NoHandleAllocation ha;
1657 ASSERT(args.length() == 2);
1658
1659 CONVERT_CHECKED(JSFunction, fun, args[0]);
1660 CONVERT_CHECKED(String, name, args[1]);
1661 fun->SetInstanceClassName(name);
1662 return Heap::undefined_value();
1663}
1664
1665
lrn@chromium.org303ada72010-10-27 09:33:13 +00001666static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001667 NoHandleAllocation ha;
1668 ASSERT(args.length() == 2);
1669
1670 CONVERT_CHECKED(JSFunction, fun, args[0]);
1671 CONVERT_CHECKED(Smi, length, args[1]);
1672 fun->shared()->set_length(length->value());
1673 return length;
1674}
1675
1676
lrn@chromium.org303ada72010-10-27 09:33:13 +00001677static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001678 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001679 ASSERT(args.length() == 2);
1680
1681 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001682 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001683 Object* obj;
1684 { MaybeObject* maybe_obj =
1685 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1686 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1687 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001688 return args[0]; // return TOS
1689}
1690
1691
lrn@chromium.org303ada72010-10-27 09:33:13 +00001692static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001693 NoHandleAllocation ha;
1694 ASSERT(args.length() == 1);
1695
1696 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001697 return f->shared()->IsApiFunction() ? Heap::true_value()
1698 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001699}
1700
lrn@chromium.org303ada72010-10-27 09:33:13 +00001701static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001702 NoHandleAllocation ha;
1703 ASSERT(args.length() == 1);
1704
1705 CONVERT_CHECKED(JSFunction, f, args[0]);
1706 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1707}
1708
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001709
lrn@chromium.org303ada72010-10-27 09:33:13 +00001710static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001711 HandleScope scope;
1712 ASSERT(args.length() == 2);
1713
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001714 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001715 Handle<Object> code = args.at<Object>(1);
1716
1717 Handle<Context> context(target->context());
1718
1719 if (!code->IsNull()) {
1720 RUNTIME_ASSERT(code->IsJSFunction());
1721 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001722 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001723
1724 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001725 return Failure::Exception();
1726 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001727 // Set the code, scope info, formal parameter count,
1728 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001729 target->shared()->set_code(shared->code());
1730 target->set_code(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001731 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001732 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001734 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001735 // Set the source code of the target function to undefined.
1736 // SetCode is only used for built-in constructors like String,
1737 // Array, and Object, and some web code
1738 // doesn't like seeing source code for constructors.
1739 target->shared()->set_script(Heap::undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001740 // Clear the optimization hints related to the compiled code as these are no
1741 // longer valid when the code is overwritten.
1742 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743 context = Handle<Context>(fun->context());
1744
1745 // Make sure we get a fresh copy of the literal vector to avoid
1746 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001747 int number_of_literals = fun->NumberOfLiterals();
1748 Handle<FixedArray> literals =
1749 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001750 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001751 // Insert the object, regexp and array functions in the literals
1752 // array prefix. These are the functions that will be used when
1753 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001754 literals->set(JSFunction::kLiteralGlobalContextIndex,
1755 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001756 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001757 // It's okay to skip the write barrier here because the literals
1758 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001759 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001760 }
1761
1762 target->set_context(*context);
1763 return *target;
1764}
1765
1766
lrn@chromium.org303ada72010-10-27 09:33:13 +00001767static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001768 HandleScope scope;
1769 ASSERT(args.length() == 2);
1770 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1771 CONVERT_SMI_CHECKED(num, args[1]);
1772 RUNTIME_ASSERT(num >= 0);
1773 SetExpectedNofProperties(function, num);
1774 return Heap::undefined_value();
1775}
1776
1777
lrn@chromium.org303ada72010-10-27 09:33:13 +00001778MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001779 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001780 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001781 if (code <= 0xffff) {
1782 return Heap::LookupSingleCharacterStringFromCode(code);
1783 }
1784 }
1785 return Heap::empty_string();
1786}
1787
1788
lrn@chromium.org303ada72010-10-27 09:33:13 +00001789static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001790 NoHandleAllocation ha;
1791 ASSERT(args.length() == 2);
1792
1793 CONVERT_CHECKED(String, subject, args[0]);
1794 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001795 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001797 uint32_t i = 0;
1798 if (index->IsSmi()) {
1799 int value = Smi::cast(index)->value();
1800 if (value < 0) return Heap::nan_value();
1801 i = value;
1802 } else {
1803 ASSERT(index->IsHeapNumber());
1804 double value = HeapNumber::cast(index)->value();
1805 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001806 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001807
1808 // Flatten the string. If someone wants to get a char at an index
1809 // in a cons string, it is likely that more indices will be
1810 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001811 Object* flat;
1812 { MaybeObject* maybe_flat = subject->TryFlatten();
1813 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1814 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001815 subject = String::cast(flat);
1816
1817 if (i >= static_cast<uint32_t>(subject->length())) {
1818 return Heap::nan_value();
1819 }
1820
1821 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001822}
1823
1824
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001826 NoHandleAllocation ha;
1827 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001828 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829}
1830
lrn@chromium.org25156de2010-04-06 13:10:27 +00001831
1832class FixedArrayBuilder {
1833 public:
1834 explicit FixedArrayBuilder(int initial_capacity)
1835 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1836 length_(0) {
1837 // Require a non-zero initial size. Ensures that doubling the size to
1838 // extend the array will work.
1839 ASSERT(initial_capacity > 0);
1840 }
1841
1842 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1843 : array_(backing_store),
1844 length_(0) {
1845 // Require a non-zero initial size. Ensures that doubling the size to
1846 // extend the array will work.
1847 ASSERT(backing_store->length() > 0);
1848 }
1849
1850 bool HasCapacity(int elements) {
1851 int length = array_->length();
1852 int required_length = length_ + elements;
1853 return (length >= required_length);
1854 }
1855
1856 void EnsureCapacity(int elements) {
1857 int length = array_->length();
1858 int required_length = length_ + elements;
1859 if (length < required_length) {
1860 int new_length = length;
1861 do {
1862 new_length *= 2;
1863 } while (new_length < required_length);
1864 Handle<FixedArray> extended_array =
1865 Factory::NewFixedArrayWithHoles(new_length);
1866 array_->CopyTo(0, *extended_array, 0, length_);
1867 array_ = extended_array;
1868 }
1869 }
1870
1871 void Add(Object* value) {
1872 ASSERT(length_ < capacity());
1873 array_->set(length_, value);
1874 length_++;
1875 }
1876
1877 void Add(Smi* value) {
1878 ASSERT(length_ < capacity());
1879 array_->set(length_, value);
1880 length_++;
1881 }
1882
1883 Handle<FixedArray> array() {
1884 return array_;
1885 }
1886
1887 int length() {
1888 return length_;
1889 }
1890
1891 int capacity() {
1892 return array_->length();
1893 }
1894
1895 Handle<JSArray> ToJSArray() {
1896 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1897 result_array->set_length(Smi::FromInt(length_));
1898 return result_array;
1899 }
1900
1901 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1902 target_array->set_elements(*array_);
1903 target_array->set_length(Smi::FromInt(length_));
1904 return target_array;
1905 }
1906
1907 private:
1908 Handle<FixedArray> array_;
1909 int length_;
1910};
1911
1912
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001913// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001914const int kStringBuilderConcatHelperLengthBits = 11;
1915const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001916
1917template <typename schar>
1918static inline void StringBuilderConcatHelper(String*,
1919 schar*,
1920 FixedArray*,
1921 int);
1922
lrn@chromium.org25156de2010-04-06 13:10:27 +00001923typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1924 StringBuilderSubstringLength;
1925typedef BitField<int,
1926 kStringBuilderConcatHelperLengthBits,
1927 kStringBuilderConcatHelperPositionBits>
1928 StringBuilderSubstringPosition;
1929
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001930
1931class ReplacementStringBuilder {
1932 public:
1933 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001934 : array_builder_(estimated_part_count),
1935 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001936 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001937 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001938 // Require a non-zero initial size. Ensures that doubling the size to
1939 // extend the array will work.
1940 ASSERT(estimated_part_count > 0);
1941 }
1942
lrn@chromium.org25156de2010-04-06 13:10:27 +00001943 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
1944 int from,
1945 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001946 ASSERT(from >= 0);
1947 int length = to - from;
1948 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001949 if (StringBuilderSubstringLength::is_valid(length) &&
1950 StringBuilderSubstringPosition::is_valid(from)) {
1951 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1952 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001953 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001954 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001955 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001956 builder->Add(Smi::FromInt(-length));
1957 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001958 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001959 }
1960
1961
1962 void EnsureCapacity(int elements) {
1963 array_builder_.EnsureCapacity(elements);
1964 }
1965
1966
1967 void AddSubjectSlice(int from, int to) {
1968 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001969 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001970 }
1971
1972
1973 void AddString(Handle<String> string) {
1974 int length = string->length();
1975 ASSERT(length > 0);
1976 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00001977 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001978 is_ascii_ = false;
1979 }
1980 IncrementCharacterCount(length);
1981 }
1982
1983
1984 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001985 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001986 return Factory::empty_string();
1987 }
1988
1989 Handle<String> joined_string;
1990 if (is_ascii_) {
1991 joined_string = NewRawAsciiString(character_count_);
1992 AssertNoAllocation no_alloc;
1993 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
1994 char* char_buffer = seq->GetChars();
1995 StringBuilderConcatHelper(*subject_,
1996 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00001997 *array_builder_.array(),
1998 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001999 } else {
2000 // Non-ASCII.
2001 joined_string = NewRawTwoByteString(character_count_);
2002 AssertNoAllocation no_alloc;
2003 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2004 uc16* char_buffer = seq->GetChars();
2005 StringBuilderConcatHelper(*subject_,
2006 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002007 *array_builder_.array(),
2008 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002009 }
2010 return joined_string;
2011 }
2012
2013
2014 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002015 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002016 V8::FatalProcessOutOfMemory("String.replace result too large.");
2017 }
2018 character_count_ += by;
2019 }
2020
lrn@chromium.org25156de2010-04-06 13:10:27 +00002021 Handle<JSArray> GetParts() {
2022 Handle<JSArray> result =
2023 Factory::NewJSArrayWithElements(array_builder_.array());
2024 result->set_length(Smi::FromInt(array_builder_.length()));
2025 return result;
2026 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002027
lrn@chromium.org25156de2010-04-06 13:10:27 +00002028 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002029 Handle<String> NewRawAsciiString(int size) {
2030 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2031 }
2032
2033
2034 Handle<String> NewRawTwoByteString(int size) {
2035 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2036 }
2037
2038
2039 void AddElement(Object* element) {
2040 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002041 ASSERT(array_builder_.capacity() > array_builder_.length());
2042 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002043 }
2044
lrn@chromium.org25156de2010-04-06 13:10:27 +00002045 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002046 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002047 int character_count_;
2048 bool is_ascii_;
2049};
2050
2051
2052class CompiledReplacement {
2053 public:
2054 CompiledReplacement()
2055 : parts_(1), replacement_substrings_(0) {}
2056
2057 void Compile(Handle<String> replacement,
2058 int capture_count,
2059 int subject_length);
2060
2061 void Apply(ReplacementStringBuilder* builder,
2062 int match_from,
2063 int match_to,
2064 Handle<JSArray> last_match_info);
2065
2066 // Number of distinct parts of the replacement pattern.
2067 int parts() {
2068 return parts_.length();
2069 }
2070 private:
2071 enum PartType {
2072 SUBJECT_PREFIX = 1,
2073 SUBJECT_SUFFIX,
2074 SUBJECT_CAPTURE,
2075 REPLACEMENT_SUBSTRING,
2076 REPLACEMENT_STRING,
2077
2078 NUMBER_OF_PART_TYPES
2079 };
2080
2081 struct ReplacementPart {
2082 static inline ReplacementPart SubjectMatch() {
2083 return ReplacementPart(SUBJECT_CAPTURE, 0);
2084 }
2085 static inline ReplacementPart SubjectCapture(int capture_index) {
2086 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2087 }
2088 static inline ReplacementPart SubjectPrefix() {
2089 return ReplacementPart(SUBJECT_PREFIX, 0);
2090 }
2091 static inline ReplacementPart SubjectSuffix(int subject_length) {
2092 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2093 }
2094 static inline ReplacementPart ReplacementString() {
2095 return ReplacementPart(REPLACEMENT_STRING, 0);
2096 }
2097 static inline ReplacementPart ReplacementSubString(int from, int to) {
2098 ASSERT(from >= 0);
2099 ASSERT(to > from);
2100 return ReplacementPart(-from, to);
2101 }
2102
2103 // If tag <= 0 then it is the negation of a start index of a substring of
2104 // the replacement pattern, otherwise it's a value from PartType.
2105 ReplacementPart(int tag, int data)
2106 : tag(tag), data(data) {
2107 // Must be non-positive or a PartType value.
2108 ASSERT(tag < NUMBER_OF_PART_TYPES);
2109 }
2110 // Either a value of PartType or a non-positive number that is
2111 // the negation of an index into the replacement string.
2112 int tag;
2113 // The data value's interpretation depends on the value of tag:
2114 // tag == SUBJECT_PREFIX ||
2115 // tag == SUBJECT_SUFFIX: data is unused.
2116 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2117 // tag == REPLACEMENT_SUBSTRING ||
2118 // tag == REPLACEMENT_STRING: data is index into array of substrings
2119 // of the replacement string.
2120 // tag <= 0: Temporary representation of the substring of the replacement
2121 // string ranging over -tag .. data.
2122 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2123 // substring objects.
2124 int data;
2125 };
2126
2127 template<typename Char>
2128 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2129 Vector<Char> characters,
2130 int capture_count,
2131 int subject_length) {
2132 int length = characters.length();
2133 int last = 0;
2134 for (int i = 0; i < length; i++) {
2135 Char c = characters[i];
2136 if (c == '$') {
2137 int next_index = i + 1;
2138 if (next_index == length) { // No next character!
2139 break;
2140 }
2141 Char c2 = characters[next_index];
2142 switch (c2) {
2143 case '$':
2144 if (i > last) {
2145 // There is a substring before. Include the first "$".
2146 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2147 last = next_index + 1; // Continue after the second "$".
2148 } else {
2149 // Let the next substring start with the second "$".
2150 last = next_index;
2151 }
2152 i = next_index;
2153 break;
2154 case '`':
2155 if (i > last) {
2156 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2157 }
2158 parts->Add(ReplacementPart::SubjectPrefix());
2159 i = next_index;
2160 last = i + 1;
2161 break;
2162 case '\'':
2163 if (i > last) {
2164 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2165 }
2166 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2167 i = next_index;
2168 last = i + 1;
2169 break;
2170 case '&':
2171 if (i > last) {
2172 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2173 }
2174 parts->Add(ReplacementPart::SubjectMatch());
2175 i = next_index;
2176 last = i + 1;
2177 break;
2178 case '0':
2179 case '1':
2180 case '2':
2181 case '3':
2182 case '4':
2183 case '5':
2184 case '6':
2185 case '7':
2186 case '8':
2187 case '9': {
2188 int capture_ref = c2 - '0';
2189 if (capture_ref > capture_count) {
2190 i = next_index;
2191 continue;
2192 }
2193 int second_digit_index = next_index + 1;
2194 if (second_digit_index < length) {
2195 // Peek ahead to see if we have two digits.
2196 Char c3 = characters[second_digit_index];
2197 if ('0' <= c3 && c3 <= '9') { // Double digits.
2198 int double_digit_ref = capture_ref * 10 + c3 - '0';
2199 if (double_digit_ref <= capture_count) {
2200 next_index = second_digit_index;
2201 capture_ref = double_digit_ref;
2202 }
2203 }
2204 }
2205 if (capture_ref > 0) {
2206 if (i > last) {
2207 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2208 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002209 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002210 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2211 last = next_index + 1;
2212 }
2213 i = next_index;
2214 break;
2215 }
2216 default:
2217 i = next_index;
2218 break;
2219 }
2220 }
2221 }
2222 if (length > last) {
2223 if (last == 0) {
2224 parts->Add(ReplacementPart::ReplacementString());
2225 } else {
2226 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2227 }
2228 }
2229 }
2230
2231 ZoneList<ReplacementPart> parts_;
2232 ZoneList<Handle<String> > replacement_substrings_;
2233};
2234
2235
2236void CompiledReplacement::Compile(Handle<String> replacement,
2237 int capture_count,
2238 int subject_length) {
2239 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002240 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002241 AssertNoAllocation no_alloc;
2242 ParseReplacementPattern(&parts_,
2243 replacement->ToAsciiVector(),
2244 capture_count,
2245 subject_length);
2246 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002247 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002248 AssertNoAllocation no_alloc;
2249
2250 ParseReplacementPattern(&parts_,
2251 replacement->ToUC16Vector(),
2252 capture_count,
2253 subject_length);
2254 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002255 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 int substring_index = 0;
2257 for (int i = 0, n = parts_.length(); i < n; i++) {
2258 int tag = parts_[i].tag;
2259 if (tag <= 0) { // A replacement string slice.
2260 int from = -tag;
2261 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002262 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002263 parts_[i].tag = REPLACEMENT_SUBSTRING;
2264 parts_[i].data = substring_index;
2265 substring_index++;
2266 } else if (tag == REPLACEMENT_STRING) {
2267 replacement_substrings_.Add(replacement);
2268 parts_[i].data = substring_index;
2269 substring_index++;
2270 }
2271 }
2272}
2273
2274
2275void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2276 int match_from,
2277 int match_to,
2278 Handle<JSArray> last_match_info) {
2279 for (int i = 0, n = parts_.length(); i < n; i++) {
2280 ReplacementPart part = parts_[i];
2281 switch (part.tag) {
2282 case SUBJECT_PREFIX:
2283 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2284 break;
2285 case SUBJECT_SUFFIX: {
2286 int subject_length = part.data;
2287 if (match_to < subject_length) {
2288 builder->AddSubjectSlice(match_to, subject_length);
2289 }
2290 break;
2291 }
2292 case SUBJECT_CAPTURE: {
2293 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002294 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002295 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2296 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2297 if (from >= 0 && to > from) {
2298 builder->AddSubjectSlice(from, to);
2299 }
2300 break;
2301 }
2302 case REPLACEMENT_SUBSTRING:
2303 case REPLACEMENT_STRING:
2304 builder->AddString(replacement_substrings_[part.data]);
2305 break;
2306 default:
2307 UNREACHABLE();
2308 }
2309 }
2310}
2311
2312
2313
lrn@chromium.org303ada72010-10-27 09:33:13 +00002314MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2315 String* subject,
2316 JSRegExp* regexp,
2317 String* replacement,
2318 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002319 ASSERT(subject->IsFlat());
2320 ASSERT(replacement->IsFlat());
2321
2322 HandleScope handles;
2323
2324 int length = subject->length();
2325 Handle<String> subject_handle(subject);
2326 Handle<JSRegExp> regexp_handle(regexp);
2327 Handle<String> replacement_handle(replacement);
2328 Handle<JSArray> last_match_info_handle(last_match_info);
2329 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2330 subject_handle,
2331 0,
2332 last_match_info_handle);
2333 if (match.is_null()) {
2334 return Failure::Exception();
2335 }
2336 if (match->IsNull()) {
2337 return *subject_handle;
2338 }
2339
2340 int capture_count = regexp_handle->CaptureCount();
2341
2342 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002343 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002344 CompiledReplacement compiled_replacement;
2345 compiled_replacement.Compile(replacement_handle,
2346 capture_count,
2347 length);
2348
2349 bool is_global = regexp_handle->GetFlags().is_global();
2350
2351 // Guessing the number of parts that the final result string is built
2352 // from. Global regexps can match any number of times, so we guess
2353 // conservatively.
2354 int expected_parts =
2355 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2356 ReplacementStringBuilder builder(subject_handle, expected_parts);
2357
2358 // Index of end of last match.
2359 int prev = 0;
2360
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002361 // Number of parts added by compiled replacement plus preceeding
2362 // string and possibly suffix after last match. It is possible for
2363 // all components to use two elements when encoded as two smis.
2364 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002365 bool matched = true;
2366 do {
2367 ASSERT(last_match_info_handle->HasFastElements());
2368 // Increase the capacity of the builder before entering local handle-scope,
2369 // so its internal buffer can safely allocate a new handle if it grows.
2370 builder.EnsureCapacity(parts_added_per_loop);
2371
2372 HandleScope loop_scope;
2373 int start, end;
2374 {
2375 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002376 FixedArray* match_info_array =
2377 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002378
2379 ASSERT_EQ(capture_count * 2 + 2,
2380 RegExpImpl::GetLastCaptureCount(match_info_array));
2381 start = RegExpImpl::GetCapture(match_info_array, 0);
2382 end = RegExpImpl::GetCapture(match_info_array, 1);
2383 }
2384
2385 if (prev < start) {
2386 builder.AddSubjectSlice(prev, start);
2387 }
2388 compiled_replacement.Apply(&builder,
2389 start,
2390 end,
2391 last_match_info_handle);
2392 prev = end;
2393
2394 // Only continue checking for global regexps.
2395 if (!is_global) break;
2396
2397 // Continue from where the match ended, unless it was an empty match.
2398 int next = end;
2399 if (start == end) {
2400 next = end + 1;
2401 if (next > length) break;
2402 }
2403
2404 match = RegExpImpl::Exec(regexp_handle,
2405 subject_handle,
2406 next,
2407 last_match_info_handle);
2408 if (match.is_null()) {
2409 return Failure::Exception();
2410 }
2411 matched = !match->IsNull();
2412 } while (matched);
2413
2414 if (prev < length) {
2415 builder.AddSubjectSlice(prev, length);
2416 }
2417
2418 return *(builder.ToString());
2419}
2420
2421
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002422template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002423MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2424 String* subject,
2425 JSRegExp* regexp,
2426 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002427 ASSERT(subject->IsFlat());
2428
2429 HandleScope handles;
2430
2431 Handle<String> subject_handle(subject);
2432 Handle<JSRegExp> regexp_handle(regexp);
2433 Handle<JSArray> last_match_info_handle(last_match_info);
2434 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2435 subject_handle,
2436 0,
2437 last_match_info_handle);
2438 if (match.is_null()) return Failure::Exception();
2439 if (match->IsNull()) return *subject_handle;
2440
2441 ASSERT(last_match_info_handle->HasFastElements());
2442
2443 HandleScope loop_scope;
2444 int start, end;
2445 {
2446 AssertNoAllocation match_info_array_is_not_in_a_handle;
2447 FixedArray* match_info_array =
2448 FixedArray::cast(last_match_info_handle->elements());
2449
2450 start = RegExpImpl::GetCapture(match_info_array, 0);
2451 end = RegExpImpl::GetCapture(match_info_array, 1);
2452 }
2453
2454 int length = subject->length();
2455 int new_length = length - (end - start);
2456 if (new_length == 0) {
2457 return Heap::empty_string();
2458 }
2459 Handle<ResultSeqString> answer;
2460 if (ResultSeqString::kHasAsciiEncoding) {
2461 answer =
2462 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2463 } else {
2464 answer =
2465 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2466 }
2467
2468 // If the regexp isn't global, only match once.
2469 if (!regexp_handle->GetFlags().is_global()) {
2470 if (start > 0) {
2471 String::WriteToFlat(*subject_handle,
2472 answer->GetChars(),
2473 0,
2474 start);
2475 }
2476 if (end < length) {
2477 String::WriteToFlat(*subject_handle,
2478 answer->GetChars() + start,
2479 end,
2480 length);
2481 }
2482 return *answer;
2483 }
2484
2485 int prev = 0; // Index of end of last match.
2486 int next = 0; // Start of next search (prev unless last match was empty).
2487 int position = 0;
2488
2489 do {
2490 if (prev < start) {
2491 // Add substring subject[prev;start] to answer string.
2492 String::WriteToFlat(*subject_handle,
2493 answer->GetChars() + position,
2494 prev,
2495 start);
2496 position += start - prev;
2497 }
2498 prev = end;
2499 next = end;
2500 // Continue from where the match ended, unless it was an empty match.
2501 if (start == end) {
2502 next++;
2503 if (next > length) break;
2504 }
2505 match = RegExpImpl::Exec(regexp_handle,
2506 subject_handle,
2507 next,
2508 last_match_info_handle);
2509 if (match.is_null()) return Failure::Exception();
2510 if (match->IsNull()) break;
2511
2512 ASSERT(last_match_info_handle->HasFastElements());
2513 HandleScope loop_scope;
2514 {
2515 AssertNoAllocation match_info_array_is_not_in_a_handle;
2516 FixedArray* match_info_array =
2517 FixedArray::cast(last_match_info_handle->elements());
2518 start = RegExpImpl::GetCapture(match_info_array, 0);
2519 end = RegExpImpl::GetCapture(match_info_array, 1);
2520 }
2521 } while (true);
2522
2523 if (prev < length) {
2524 // Add substring subject[prev;length] to answer string.
2525 String::WriteToFlat(*subject_handle,
2526 answer->GetChars() + position,
2527 prev,
2528 length);
2529 position += length - prev;
2530 }
2531
2532 if (position == 0) {
2533 return Heap::empty_string();
2534 }
2535
2536 // Shorten string and fill
2537 int string_size = ResultSeqString::SizeFor(position);
2538 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2539 int delta = allocated_string_size - string_size;
2540
2541 answer->set_length(position);
2542 if (delta == 0) return *answer;
2543
2544 Address end_of_string = answer->address() + string_size;
2545 Heap::CreateFillerObjectAt(end_of_string, delta);
2546
2547 return *answer;
2548}
2549
2550
lrn@chromium.org303ada72010-10-27 09:33:13 +00002551static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002552 ASSERT(args.length() == 4);
2553
2554 CONVERT_CHECKED(String, subject, args[0]);
2555 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002556 Object* flat_subject;
2557 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2558 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2559 return maybe_flat_subject;
2560 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002561 }
2562 subject = String::cast(flat_subject);
2563 }
2564
2565 CONVERT_CHECKED(String, replacement, args[2]);
2566 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002567 Object* flat_replacement;
2568 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2569 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2570 return maybe_flat_replacement;
2571 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002572 }
2573 replacement = String::cast(flat_replacement);
2574 }
2575
2576 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2577 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2578
2579 ASSERT(last_match_info->HasFastElements());
2580
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002581 if (replacement->length() == 0) {
2582 if (subject->HasOnlyAsciiChars()) {
2583 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2584 subject, regexp, last_match_info);
2585 } else {
2586 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2587 subject, regexp, last_match_info);
2588 }
2589 }
2590
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002591 return StringReplaceRegExpWithString(subject,
2592 regexp,
2593 replacement,
2594 last_match_info);
2595}
2596
2597
ager@chromium.org7c537e22008-10-16 08:43:32 +00002598// Perform string match of pattern on subject, starting at start index.
2599// Caller must ensure that 0 <= start_index <= sub->length(),
2600// and should check that pat->length() + start_index <= sub->length()
2601int Runtime::StringMatch(Handle<String> sub,
2602 Handle<String> pat,
2603 int start_index) {
2604 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002605 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002606
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002607 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002608 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002609
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002610 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002611 if (start_index + pattern_length > subject_length) return -1;
2612
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002613 if (!sub->IsFlat()) FlattenString(sub);
2614 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002615
ager@chromium.org7c537e22008-10-16 08:43:32 +00002616 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002617 // Extract flattened substrings of cons strings before determining asciiness.
2618 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002619 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002620 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002621 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002622
ager@chromium.org7c537e22008-10-16 08:43:32 +00002623 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002624 if (seq_pat->IsAsciiRepresentation()) {
2625 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2626 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002627 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002628 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002629 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002630 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002631 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2632 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002633 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002634 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002635 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002636}
2637
2638
lrn@chromium.org303ada72010-10-27 09:33:13 +00002639static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002640 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002641 ASSERT(args.length() == 3);
2642
ager@chromium.org7c537e22008-10-16 08:43:32 +00002643 CONVERT_ARG_CHECKED(String, sub, 0);
2644 CONVERT_ARG_CHECKED(String, pat, 1);
2645
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002646 Object* index = args[2];
2647 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002648 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002649
ager@chromium.org870a0b62008-11-04 11:43:05 +00002650 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002651 int position = Runtime::StringMatch(sub, pat, start_index);
2652 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002653}
2654
2655
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002656template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002657static int StringMatchBackwards(Vector<const schar> subject,
2658 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002659 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002660 int pattern_length = pattern.length();
2661 ASSERT(pattern_length >= 1);
2662 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002663
2664 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002665 for (int i = 0; i < pattern_length; i++) {
2666 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002667 if (c > String::kMaxAsciiCharCode) {
2668 return -1;
2669 }
2670 }
2671 }
2672
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002673 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002674 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002675 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002676 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002677 while (j < pattern_length) {
2678 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002679 break;
2680 }
2681 j++;
2682 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002683 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002684 return i;
2685 }
2686 }
2687 return -1;
2688}
2689
lrn@chromium.org303ada72010-10-27 09:33:13 +00002690static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002691 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002692 ASSERT(args.length() == 3);
2693
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002694 CONVERT_ARG_CHECKED(String, sub, 0);
2695 CONVERT_ARG_CHECKED(String, pat, 1);
2696
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002697 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002698 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002699 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002700
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002701 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002702 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002704 if (start_index + pat_length > sub_length) {
2705 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002706 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002707
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002708 if (pat_length == 0) {
2709 return Smi::FromInt(start_index);
2710 }
2711
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002712 if (!sub->IsFlat()) FlattenString(sub);
2713 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002714
2715 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2716
2717 int position = -1;
2718
2719 if (pat->IsAsciiRepresentation()) {
2720 Vector<const char> pat_vector = pat->ToAsciiVector();
2721 if (sub->IsAsciiRepresentation()) {
2722 position = StringMatchBackwards(sub->ToAsciiVector(),
2723 pat_vector,
2724 start_index);
2725 } else {
2726 position = StringMatchBackwards(sub->ToUC16Vector(),
2727 pat_vector,
2728 start_index);
2729 }
2730 } else {
2731 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2732 if (sub->IsAsciiRepresentation()) {
2733 position = StringMatchBackwards(sub->ToAsciiVector(),
2734 pat_vector,
2735 start_index);
2736 } else {
2737 position = StringMatchBackwards(sub->ToUC16Vector(),
2738 pat_vector,
2739 start_index);
2740 }
2741 }
2742
2743 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002744}
2745
2746
lrn@chromium.org303ada72010-10-27 09:33:13 +00002747static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002748 NoHandleAllocation ha;
2749 ASSERT(args.length() == 2);
2750
2751 CONVERT_CHECKED(String, str1, args[0]);
2752 CONVERT_CHECKED(String, str2, args[1]);
2753
2754 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002755 int str1_length = str1->length();
2756 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002757
2758 // Decide trivial cases without flattening.
2759 if (str1_length == 0) {
2760 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2761 return Smi::FromInt(-str2_length);
2762 } else {
2763 if (str2_length == 0) return Smi::FromInt(str1_length);
2764 }
2765
2766 int end = str1_length < str2_length ? str1_length : str2_length;
2767
2768 // No need to flatten if we are going to find the answer on the first
2769 // character. At this point we know there is at least one character
2770 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002771 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772 if (d != 0) return Smi::FromInt(d);
2773
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002774 str1->TryFlatten();
2775 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002776
2777 static StringInputBuffer buf1;
2778 static StringInputBuffer buf2;
2779
2780 buf1.Reset(str1);
2781 buf2.Reset(str2);
2782
2783 for (int i = 0; i < end; i++) {
2784 uint16_t char1 = buf1.GetNext();
2785 uint16_t char2 = buf2.GetNext();
2786 if (char1 != char2) return Smi::FromInt(char1 - char2);
2787 }
2788
2789 return Smi::FromInt(str1_length - str2_length);
2790}
2791
2792
lrn@chromium.org303ada72010-10-27 09:33:13 +00002793static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002794 NoHandleAllocation ha;
2795 ASSERT(args.length() == 3);
2796
2797 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002798 Object* from = args[1];
2799 Object* to = args[2];
2800 int start, end;
2801 // We have a fast integer-only case here to avoid a conversion to double in
2802 // the common case where from and to are Smis.
2803 if (from->IsSmi() && to->IsSmi()) {
2804 start = Smi::cast(from)->value();
2805 end = Smi::cast(to)->value();
2806 } else {
2807 CONVERT_DOUBLE_CHECKED(from_number, from);
2808 CONVERT_DOUBLE_CHECKED(to_number, to);
2809 start = FastD2I(from_number);
2810 end = FastD2I(to_number);
2811 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002812 RUNTIME_ASSERT(end >= start);
2813 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002814 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002815 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002816 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002817}
2818
2819
lrn@chromium.org303ada72010-10-27 09:33:13 +00002820static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002821 ASSERT_EQ(3, args.length());
2822
2823 CONVERT_ARG_CHECKED(String, subject, 0);
2824 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2825 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2826 HandleScope handles;
2827
2828 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2829
2830 if (match.is_null()) {
2831 return Failure::Exception();
2832 }
2833 if (match->IsNull()) {
2834 return Heap::null_value();
2835 }
2836 int length = subject->length();
2837
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002838 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002839 ZoneList<int> offsets(8);
2840 do {
2841 int start;
2842 int end;
2843 {
2844 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002845 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002846 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2847 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2848 }
2849 offsets.Add(start);
2850 offsets.Add(end);
2851 int index = start < end ? end : end + 1;
2852 if (index > length) break;
2853 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2854 if (match.is_null()) {
2855 return Failure::Exception();
2856 }
2857 } while (!match->IsNull());
2858 int matches = offsets.length() / 2;
2859 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2860 for (int i = 0; i < matches ; i++) {
2861 int from = offsets.at(i * 2);
2862 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002863 Handle<String> match = Factory::NewSubString(subject, from, to);
2864 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002865 }
2866 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2867 result->set_length(Smi::FromInt(matches));
2868 return *result;
2869}
2870
2871
lrn@chromium.org25156de2010-04-06 13:10:27 +00002872// Two smis before and after the match, for very long strings.
2873const int kMaxBuilderEntriesPerRegExpMatch = 5;
2874
2875
2876static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2877 Handle<JSArray> last_match_info,
2878 int match_start,
2879 int match_end) {
2880 // Fill last_match_info with a single capture.
2881 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2882 AssertNoAllocation no_gc;
2883 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2884 RegExpImpl::SetLastCaptureCount(elements, 2);
2885 RegExpImpl::SetLastInput(elements, *subject);
2886 RegExpImpl::SetLastSubject(elements, *subject);
2887 RegExpImpl::SetCapture(elements, 0, match_start);
2888 RegExpImpl::SetCapture(elements, 1, match_end);
2889}
2890
2891
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002892template <typename SubjectChar, typename PatternChar>
2893static bool SearchStringMultiple(Vector<const SubjectChar> subject,
2894 Vector<const PatternChar> pattern,
2895 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002896 FixedArrayBuilder* builder,
2897 int* match_pos) {
2898 int pos = *match_pos;
2899 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002900 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002901 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002902 StringSearch<PatternChar, SubjectChar> search(pattern);
2903 while (pos <= max_search_start) {
2904 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2905 *match_pos = pos;
2906 return false;
2907 }
2908 // Position of end of previous match.
2909 int match_end = pos + pattern_length;
2910 int new_pos = search.Search(subject, match_end);
2911 if (new_pos >= 0) {
2912 // A match.
2913 if (new_pos > match_end) {
2914 ReplacementStringBuilder::AddSubjectSlice(builder,
2915 match_end,
2916 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002917 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002918 pos = new_pos;
2919 builder->Add(pattern_string);
2920 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002921 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002922 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002923 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002924
lrn@chromium.org25156de2010-04-06 13:10:27 +00002925 if (pos < max_search_start) {
2926 ReplacementStringBuilder::AddSubjectSlice(builder,
2927 pos + pattern_length,
2928 subject_length);
2929 }
2930 *match_pos = pos;
2931 return true;
2932}
2933
2934
2935static bool SearchStringMultiple(Handle<String> subject,
2936 Handle<String> pattern,
2937 Handle<JSArray> last_match_info,
2938 FixedArrayBuilder* builder) {
2939 ASSERT(subject->IsFlat());
2940 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002941
2942 // Treating as if a previous match was before first character.
2943 int match_pos = -pattern->length();
2944
2945 for (;;) { // Break when search complete.
2946 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
2947 AssertNoAllocation no_gc;
2948 if (subject->IsAsciiRepresentation()) {
2949 Vector<const char> subject_vector = subject->ToAsciiVector();
2950 if (pattern->IsAsciiRepresentation()) {
2951 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002952 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002953 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002954 builder,
2955 &match_pos)) break;
2956 } else {
2957 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002958 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002959 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002960 builder,
2961 &match_pos)) break;
2962 }
2963 } else {
2964 Vector<const uc16> subject_vector = subject->ToUC16Vector();
2965 if (pattern->IsAsciiRepresentation()) {
2966 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002967 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002968 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002969 builder,
2970 &match_pos)) break;
2971 } else {
2972 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002973 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002974 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002975 builder,
2976 &match_pos)) break;
2977 }
2978 }
2979 }
2980
2981 if (match_pos >= 0) {
2982 SetLastMatchInfoNoCaptures(subject,
2983 last_match_info,
2984 match_pos,
2985 match_pos + pattern->length());
2986 return true;
2987 }
2988 return false; // No matches at all.
2989}
2990
2991
2992static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
2993 Handle<String> subject,
2994 Handle<JSRegExp> regexp,
2995 Handle<JSArray> last_match_array,
2996 FixedArrayBuilder* builder) {
2997 ASSERT(subject->IsFlat());
2998 int match_start = -1;
2999 int match_end = 0;
3000 int pos = 0;
3001 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3002 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3003
3004 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003005 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003006 int subject_length = subject->length();
3007
3008 for (;;) { // Break on failure, return on exception.
3009 RegExpImpl::IrregexpResult result =
3010 RegExpImpl::IrregexpExecOnce(regexp,
3011 subject,
3012 pos,
3013 register_vector);
3014 if (result == RegExpImpl::RE_SUCCESS) {
3015 match_start = register_vector[0];
3016 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3017 if (match_end < match_start) {
3018 ReplacementStringBuilder::AddSubjectSlice(builder,
3019 match_end,
3020 match_start);
3021 }
3022 match_end = register_vector[1];
3023 HandleScope loop_scope;
3024 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3025 if (match_start != match_end) {
3026 pos = match_end;
3027 } else {
3028 pos = match_end + 1;
3029 if (pos > subject_length) break;
3030 }
3031 } else if (result == RegExpImpl::RE_FAILURE) {
3032 break;
3033 } else {
3034 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3035 return result;
3036 }
3037 }
3038
3039 if (match_start >= 0) {
3040 if (match_end < subject_length) {
3041 ReplacementStringBuilder::AddSubjectSlice(builder,
3042 match_end,
3043 subject_length);
3044 }
3045 SetLastMatchInfoNoCaptures(subject,
3046 last_match_array,
3047 match_start,
3048 match_end);
3049 return RegExpImpl::RE_SUCCESS;
3050 } else {
3051 return RegExpImpl::RE_FAILURE; // No matches at all.
3052 }
3053}
3054
3055
3056static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3057 Handle<String> subject,
3058 Handle<JSRegExp> regexp,
3059 Handle<JSArray> last_match_array,
3060 FixedArrayBuilder* builder) {
3061
3062 ASSERT(subject->IsFlat());
3063 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3064 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3065
3066 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003067 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003068
3069 RegExpImpl::IrregexpResult result =
3070 RegExpImpl::IrregexpExecOnce(regexp,
3071 subject,
3072 0,
3073 register_vector);
3074
3075 int capture_count = regexp->CaptureCount();
3076 int subject_length = subject->length();
3077
3078 // Position to search from.
3079 int pos = 0;
3080 // End of previous match. Differs from pos if match was empty.
3081 int match_end = 0;
3082 if (result == RegExpImpl::RE_SUCCESS) {
3083 // Need to keep a copy of the previous match for creating last_match_info
3084 // at the end, so we have two vectors that we swap between.
3085 OffsetsVector registers2(required_registers);
3086 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3087
3088 do {
3089 int match_start = register_vector[0];
3090 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3091 if (match_end < match_start) {
3092 ReplacementStringBuilder::AddSubjectSlice(builder,
3093 match_end,
3094 match_start);
3095 }
3096 match_end = register_vector[1];
3097
3098 {
3099 // Avoid accumulating new handles inside loop.
3100 HandleScope temp_scope;
3101 // Arguments array to replace function is match, captures, index and
3102 // subject, i.e., 3 + capture count in total.
3103 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003104 Handle<String> match = Factory::NewSubString(subject,
3105 match_start,
3106 match_end);
3107 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003108 for (int i = 1; i <= capture_count; i++) {
3109 int start = register_vector[i * 2];
3110 if (start >= 0) {
3111 int end = register_vector[i * 2 + 1];
3112 ASSERT(start <= end);
3113 Handle<String> substring = Factory::NewSubString(subject,
3114 start,
3115 end);
3116 elements->set(i, *substring);
3117 } else {
3118 ASSERT(register_vector[i * 2 + 1] < 0);
3119 elements->set(i, Heap::undefined_value());
3120 }
3121 }
3122 elements->set(capture_count + 1, Smi::FromInt(match_start));
3123 elements->set(capture_count + 2, *subject);
3124 builder->Add(*Factory::NewJSArrayWithElements(elements));
3125 }
3126 // Swap register vectors, so the last successful match is in
3127 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003128 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003129 prev_register_vector = register_vector;
3130 register_vector = tmp;
3131
3132 if (match_end > match_start) {
3133 pos = match_end;
3134 } else {
3135 pos = match_end + 1;
3136 if (pos > subject_length) {
3137 break;
3138 }
3139 }
3140
3141 result = RegExpImpl::IrregexpExecOnce(regexp,
3142 subject,
3143 pos,
3144 register_vector);
3145 } while (result == RegExpImpl::RE_SUCCESS);
3146
3147 if (result != RegExpImpl::RE_EXCEPTION) {
3148 // Finished matching, with at least one match.
3149 if (match_end < subject_length) {
3150 ReplacementStringBuilder::AddSubjectSlice(builder,
3151 match_end,
3152 subject_length);
3153 }
3154
3155 int last_match_capture_count = (capture_count + 1) * 2;
3156 int last_match_array_size =
3157 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3158 last_match_array->EnsureSize(last_match_array_size);
3159 AssertNoAllocation no_gc;
3160 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3161 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3162 RegExpImpl::SetLastSubject(elements, *subject);
3163 RegExpImpl::SetLastInput(elements, *subject);
3164 for (int i = 0; i < last_match_capture_count; i++) {
3165 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3166 }
3167 return RegExpImpl::RE_SUCCESS;
3168 }
3169 }
3170 // No matches at all, return failure or exception result directly.
3171 return result;
3172}
3173
3174
lrn@chromium.org303ada72010-10-27 09:33:13 +00003175static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003176 ASSERT(args.length() == 4);
3177 HandleScope handles;
3178
3179 CONVERT_ARG_CHECKED(String, subject, 1);
3180 if (!subject->IsFlat()) { FlattenString(subject); }
3181 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3182 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3183 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3184
3185 ASSERT(last_match_info->HasFastElements());
3186 ASSERT(regexp->GetFlags().is_global());
3187 Handle<FixedArray> result_elements;
3188 if (result_array->HasFastElements()) {
3189 result_elements =
3190 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3191 } else {
3192 result_elements = Factory::NewFixedArrayWithHoles(16);
3193 }
3194 FixedArrayBuilder builder(result_elements);
3195
3196 if (regexp->TypeTag() == JSRegExp::ATOM) {
3197 Handle<String> pattern(
3198 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003199 if (!pattern->IsFlat()) FlattenString(pattern);
3200 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3201 return *builder.ToJSArray(result_array);
3202 }
3203 return Heap::null_value();
3204 }
3205
3206 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3207
3208 RegExpImpl::IrregexpResult result;
3209 if (regexp->CaptureCount() == 0) {
3210 result = SearchRegExpNoCaptureMultiple(subject,
3211 regexp,
3212 last_match_info,
3213 &builder);
3214 } else {
3215 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3216 }
3217 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3218 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3219 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3220 return Failure::Exception();
3221}
3222
3223
lrn@chromium.org303ada72010-10-27 09:33:13 +00003224static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003225 NoHandleAllocation ha;
3226 ASSERT(args.length() == 2);
3227
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003228 // Fast case where the result is a one character string.
3229 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3230 int value = Smi::cast(args[0])->value();
3231 int radix = Smi::cast(args[1])->value();
3232 if (value >= 0 && value < radix) {
3233 RUNTIME_ASSERT(radix <= 36);
3234 // Character array used for conversion.
3235 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3236 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3237 }
3238 }
3239
3240 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003241 CONVERT_DOUBLE_CHECKED(value, args[0]);
3242 if (isnan(value)) {
3243 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3244 }
3245 if (isinf(value)) {
3246 if (value < 0) {
3247 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3248 }
3249 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3250 }
3251 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3252 int radix = FastD2I(radix_number);
3253 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3254 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003255 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003256 DeleteArray(str);
3257 return result;
3258}
3259
3260
lrn@chromium.org303ada72010-10-27 09:33:13 +00003261static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003262 NoHandleAllocation ha;
3263 ASSERT(args.length() == 2);
3264
3265 CONVERT_DOUBLE_CHECKED(value, args[0]);
3266 if (isnan(value)) {
3267 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3268 }
3269 if (isinf(value)) {
3270 if (value < 0) {
3271 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3272 }
3273 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3274 }
3275 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3276 int f = FastD2I(f_number);
3277 RUNTIME_ASSERT(f >= 0);
3278 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003279 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003280 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003281 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003282}
3283
3284
lrn@chromium.org303ada72010-10-27 09:33:13 +00003285static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003286 NoHandleAllocation ha;
3287 ASSERT(args.length() == 2);
3288
3289 CONVERT_DOUBLE_CHECKED(value, args[0]);
3290 if (isnan(value)) {
3291 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3292 }
3293 if (isinf(value)) {
3294 if (value < 0) {
3295 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3296 }
3297 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3298 }
3299 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3300 int f = FastD2I(f_number);
3301 RUNTIME_ASSERT(f >= -1 && f <= 20);
3302 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003303 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003304 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003305 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003306}
3307
3308
lrn@chromium.org303ada72010-10-27 09:33:13 +00003309static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003310 NoHandleAllocation ha;
3311 ASSERT(args.length() == 2);
3312
3313 CONVERT_DOUBLE_CHECKED(value, args[0]);
3314 if (isnan(value)) {
3315 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3316 }
3317 if (isinf(value)) {
3318 if (value < 0) {
3319 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3320 }
3321 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3322 }
3323 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3324 int f = FastD2I(f_number);
3325 RUNTIME_ASSERT(f >= 1 && f <= 21);
3326 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003327 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003328 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003329 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003330}
3331
3332
3333// Returns a single character string where first character equals
3334// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003335static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003336 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003337 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003338 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003339 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003341 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003342}
3343
3344
lrn@chromium.org303ada72010-10-27 09:33:13 +00003345MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3346 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003347 // Handle [] indexing on Strings
3348 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003349 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3350 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003351 }
3352
3353 // Handle [] indexing on String objects
3354 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003355 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3356 Handle<Object> result =
3357 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3358 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003359 }
3360
3361 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003362 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363 return prototype->GetElement(index);
3364 }
3365
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003366 return GetElement(object, index);
3367}
3368
3369
lrn@chromium.org303ada72010-10-27 09:33:13 +00003370MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003371 return object->GetElement(index);
3372}
3373
3374
lrn@chromium.org303ada72010-10-27 09:33:13 +00003375MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3376 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003377 HandleScope scope;
3378
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003379 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003380 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003381 Handle<Object> error =
3382 Factory::NewTypeError("non_object_property_load",
3383 HandleVector(args, 2));
3384 return Top::Throw(*error);
3385 }
3386
3387 // Check if the given key is an array index.
3388 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003389 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003390 return GetElementOrCharAt(object, index);
3391 }
3392
3393 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003394 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003395 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003396 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003397 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003398 bool has_pending_exception = false;
3399 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003400 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003402 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003403 }
3404
ager@chromium.org32912102009-01-16 10:38:43 +00003405 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003406 // the element if so.
3407 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003408 return GetElementOrCharAt(object, index);
3409 } else {
3410 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003411 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003412 }
3413}
3414
3415
lrn@chromium.org303ada72010-10-27 09:33:13 +00003416static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417 NoHandleAllocation ha;
3418 ASSERT(args.length() == 2);
3419
3420 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003421 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003422
3423 return Runtime::GetObjectProperty(object, key);
3424}
3425
3426
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003427// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003428static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003429 NoHandleAllocation ha;
3430 ASSERT(args.length() == 2);
3431
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003432 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003433 // itself.
3434 //
3435 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003436 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003437 // global proxy object never has properties. This is the case
3438 // because the global proxy object forwards everything to its hidden
3439 // prototype including local lookups.
3440 //
3441 // Additionally, we need to make sure that we do not cache results
3442 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003443 if (args[0]->IsJSObject() &&
3444 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003445 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003446 args[1]->IsString()) {
3447 JSObject* receiver = JSObject::cast(args[0]);
3448 String* key = String::cast(args[1]);
3449 if (receiver->HasFastProperties()) {
3450 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003451 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003452 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3453 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003454 Object* value = receiver->FastPropertyAt(offset);
3455 return value->IsTheHole() ? Heap::undefined_value() : value;
3456 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003457 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003458 LookupResult result;
3459 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003460 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003461 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003462 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003463 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003464 }
3465 } else {
3466 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003467 StringDictionary* dictionary = receiver->property_dictionary();
3468 int entry = dictionary->FindEntry(key);
3469 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003470 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003471 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003472 if (!receiver->IsGlobalObject()) return value;
3473 value = JSGlobalPropertyCell::cast(value)->value();
3474 if (!value->IsTheHole()) return value;
3475 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003476 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003477 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003478 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3479 // Fast case for string indexing using [] with a smi index.
3480 HandleScope scope;
3481 Handle<String> str = args.at<String>(0);
3482 int index = Smi::cast(args[1])->value();
3483 Handle<Object> result = GetCharAt(str, index);
3484 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003485 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003486
3487 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003488 return Runtime::GetObjectProperty(args.at<Object>(0),
3489 args.at<Object>(1));
3490}
3491
3492
lrn@chromium.org303ada72010-10-27 09:33:13 +00003493static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003494 ASSERT(args.length() == 5);
3495 HandleScope scope;
3496 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3497 CONVERT_CHECKED(String, name, args[1]);
3498 CONVERT_CHECKED(Smi, flag_setter, args[2]);
3499 CONVERT_CHECKED(JSFunction, fun, args[3]);
3500 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3501 int unchecked = flag_attr->value();
3502 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3503 RUNTIME_ASSERT(!obj->IsNull());
3504 LookupResult result;
3505 obj->LocalLookupRealNamedProperty(name, &result);
3506
3507 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3508 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3509 // delete it to avoid running into trouble in DefineAccessor, which
3510 // handles this incorrectly if the property is readonly (does nothing)
3511 if (result.IsProperty() &&
3512 (result.type() == FIELD || result.type() == NORMAL
3513 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003514 Object* ok;
3515 { MaybeObject* maybe_ok =
3516 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3517 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3518 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003519 }
3520 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3521}
3522
lrn@chromium.org303ada72010-10-27 09:33:13 +00003523static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003524 ASSERT(args.length() == 4);
3525 HandleScope scope;
3526 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3527 CONVERT_ARG_CHECKED(String, name, 1);
3528 Handle<Object> obj_value = args.at<Object>(2);
3529
3530 CONVERT_CHECKED(Smi, flag, args[3]);
3531 int unchecked = flag->value();
3532 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3533
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003534 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3535
3536 // Check if this is an element.
3537 uint32_t index;
3538 bool is_element = name->AsArrayIndex(&index);
3539
3540 // Special case for elements if any of the flags are true.
3541 // If elements are in fast case we always implicitly assume that:
3542 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3543 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3544 is_element) {
3545 // Normalize the elements to enable attributes on the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003546 NormalizeElements(js_object);
3547 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003548 // Make sure that we never go back to fast case.
3549 dictionary->set_requires_slow_elements();
3550 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003551 NumberDictionarySet(dictionary, index, obj_value, details);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003552 }
3553
ager@chromium.org5c838252010-02-19 08:53:10 +00003554 LookupResult result;
3555 js_object->LocalLookupRealNamedProperty(*name, &result);
3556
ager@chromium.org5c838252010-02-19 08:53:10 +00003557 // Take special care when attributes are different and there is already
3558 // a property. For simplicity we normalize the property which enables us
3559 // to not worry about changing the instance_descriptor and creating a new
3560 // map. The current version of SetObjectProperty does not handle attributes
3561 // correctly in the case where a property is a field and is reset with
3562 // new attributes.
3563 if (result.IsProperty() && attr != result.GetAttributes()) {
3564 // New attributes - normalize to avoid writing to instance descriptor
lrn@chromium.org303ada72010-10-27 09:33:13 +00003565 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003566 // Use IgnoreAttributes version since a readonly property may be
3567 // overridden and SetProperty does not allow this.
3568 return js_object->IgnoreAttributesAndSetLocalProperty(*name,
3569 *obj_value,
3570 attr);
3571 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003572
ager@chromium.org5c838252010-02-19 08:53:10 +00003573 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3574}
3575
3576
lrn@chromium.org303ada72010-10-27 09:33:13 +00003577MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3578 Handle<Object> key,
3579 Handle<Object> value,
3580 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003581 HandleScope scope;
3582
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003583 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003584 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003585 Handle<Object> error =
3586 Factory::NewTypeError("non_object_property_store",
3587 HandleVector(args, 2));
3588 return Top::Throw(*error);
3589 }
3590
3591 // If the object isn't a JavaScript object, we ignore the store.
3592 if (!object->IsJSObject()) return *value;
3593
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003594 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3595
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 // Check if the given key is an array index.
3597 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003598 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003599 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3600 // of a string using [] notation. We need to support this too in
3601 // JavaScript.
3602 // In the case of a String object we just need to redirect the assignment to
3603 // the underlying string if the index is in range. Since the underlying
3604 // string does nothing with the assignment then we can ignore such
3605 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003606 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003607 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003608 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003609
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003610 Handle<Object> result = SetElement(js_object, index, value);
3611 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003612 return *value;
3613 }
3614
3615 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003616 Handle<Object> result;
3617 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003618 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003619 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003620 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003621 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003622 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003623 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003624 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003625 return *value;
3626 }
3627
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003628 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 bool has_pending_exception = false;
3630 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3631 if (has_pending_exception) return Failure::Exception();
3632 Handle<String> name = Handle<String>::cast(converted);
3633
3634 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003635 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003636 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003637 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003638 }
3639}
3640
3641
lrn@chromium.org303ada72010-10-27 09:33:13 +00003642MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3643 Handle<Object> key,
3644 Handle<Object> value,
3645 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003646 HandleScope scope;
3647
3648 // Check if the given key is an array index.
3649 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003650 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003651 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3652 // of a string using [] notation. We need to support this too in
3653 // JavaScript.
3654 // In the case of a String object we just need to redirect the assignment to
3655 // the underlying string if the index is in range. Since the underlying
3656 // string does nothing with the assignment then we can ignore such
3657 // assignments.
3658 if (js_object->IsStringObjectWithCharacterAt(index)) {
3659 return *value;
3660 }
3661
3662 return js_object->SetElement(index, *value);
3663 }
3664
3665 if (key->IsString()) {
3666 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003667 return js_object->SetElement(index, *value);
3668 } else {
3669 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003670 key_string->TryFlatten();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003671 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
3672 *value,
3673 attr);
3674 }
3675 }
3676
3677 // Call-back into JavaScript to convert the key to a string.
3678 bool has_pending_exception = false;
3679 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3680 if (has_pending_exception) return Failure::Exception();
3681 Handle<String> name = Handle<String>::cast(converted);
3682
3683 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003684 return js_object->SetElement(index, *value);
3685 } else {
3686 return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
3687 }
3688}
3689
3690
lrn@chromium.org303ada72010-10-27 09:33:13 +00003691MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3692 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003693 HandleScope scope;
3694
3695 // Check if the given key is an array index.
3696 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003697 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003698 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3699 // characters of a string using [] notation. In the case of a
3700 // String object we just need to redirect the deletion to the
3701 // underlying string if the index is in range. Since the
3702 // underlying string does nothing with the deletion, we can ignore
3703 // such deletions.
3704 if (js_object->IsStringObjectWithCharacterAt(index)) {
3705 return Heap::true_value();
3706 }
3707
3708 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3709 }
3710
3711 Handle<String> key_string;
3712 if (key->IsString()) {
3713 key_string = Handle<String>::cast(key);
3714 } else {
3715 // Call-back into JavaScript to convert the key to a string.
3716 bool has_pending_exception = false;
3717 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3718 if (has_pending_exception) return Failure::Exception();
3719 key_string = Handle<String>::cast(converted);
3720 }
3721
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003722 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003723 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3724}
3725
3726
lrn@chromium.org303ada72010-10-27 09:33:13 +00003727static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728 NoHandleAllocation ha;
3729 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3730
3731 Handle<Object> object = args.at<Object>(0);
3732 Handle<Object> key = args.at<Object>(1);
3733 Handle<Object> value = args.at<Object>(2);
3734
3735 // Compute attributes.
3736 PropertyAttributes attributes = NONE;
3737 if (args.length() == 4) {
3738 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003739 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003740 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003741 RUNTIME_ASSERT(
3742 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3743 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003744 }
3745 return Runtime::SetObjectProperty(object, key, value, attributes);
3746}
3747
3748
3749// Set a local property, even if it is READ_ONLY. If the property does not
3750// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003751static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003753 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003754 CONVERT_CHECKED(JSObject, object, args[0]);
3755 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003756 // Compute attributes.
3757 PropertyAttributes attributes = NONE;
3758 if (args.length() == 4) {
3759 CONVERT_CHECKED(Smi, value_obj, args[3]);
3760 int unchecked_value = value_obj->value();
3761 // Only attribute bits should be set.
3762 RUNTIME_ASSERT(
3763 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3764 attributes = static_cast<PropertyAttributes>(unchecked_value);
3765 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003767 return object->
3768 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003769}
3770
3771
lrn@chromium.org303ada72010-10-27 09:33:13 +00003772static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773 NoHandleAllocation ha;
3774 ASSERT(args.length() == 2);
3775
3776 CONVERT_CHECKED(JSObject, object, args[0]);
3777 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003778 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003779}
3780
3781
ager@chromium.org9085a012009-05-11 19:22:57 +00003782static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3783 Handle<String> key) {
3784 if (object->HasLocalProperty(*key)) return Heap::true_value();
3785 // Handle hidden prototypes. If there's a hidden prototype above this thing
3786 // then we have to check it for properties, because they are supposed to
3787 // look like they are on this object.
3788 Handle<Object> proto(object->GetPrototype());
3789 if (proto->IsJSObject() &&
3790 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3791 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3792 }
3793 return Heap::false_value();
3794}
3795
3796
lrn@chromium.org303ada72010-10-27 09:33:13 +00003797static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798 NoHandleAllocation ha;
3799 ASSERT(args.length() == 2);
3800 CONVERT_CHECKED(String, key, args[1]);
3801
ager@chromium.org9085a012009-05-11 19:22:57 +00003802 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003803 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003804 if (obj->IsJSObject()) {
3805 JSObject* object = JSObject::cast(obj);
3806 // Fast case - no interceptors.
3807 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3808 // Slow case. Either it's not there or we have an interceptor. We should
3809 // have handles for this kind of deal.
3810 HandleScope scope;
3811 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3812 Handle<String>(key));
3813 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003814 // Well, there is one exception: Handle [] on strings.
3815 uint32_t index;
3816 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003817 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003818 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003819 return Heap::true_value();
3820 }
3821 }
3822 return Heap::false_value();
3823}
3824
3825
lrn@chromium.org303ada72010-10-27 09:33:13 +00003826static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003827 NoHandleAllocation na;
3828 ASSERT(args.length() == 2);
3829
3830 // Only JS objects can have properties.
3831 if (args[0]->IsJSObject()) {
3832 JSObject* object = JSObject::cast(args[0]);
3833 CONVERT_CHECKED(String, key, args[1]);
3834 if (object->HasProperty(key)) return Heap::true_value();
3835 }
3836 return Heap::false_value();
3837}
3838
3839
lrn@chromium.org303ada72010-10-27 09:33:13 +00003840static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003841 NoHandleAllocation na;
3842 ASSERT(args.length() == 2);
3843
3844 // Only JS objects can have elements.
3845 if (args[0]->IsJSObject()) {
3846 JSObject* object = JSObject::cast(args[0]);
3847 CONVERT_CHECKED(Smi, index_obj, args[1]);
3848 uint32_t index = index_obj->value();
3849 if (object->HasElement(index)) return Heap::true_value();
3850 }
3851 return Heap::false_value();
3852}
3853
3854
lrn@chromium.org303ada72010-10-27 09:33:13 +00003855static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003856 NoHandleAllocation ha;
3857 ASSERT(args.length() == 2);
3858
3859 CONVERT_CHECKED(JSObject, object, args[0]);
3860 CONVERT_CHECKED(String, key, args[1]);
3861
3862 uint32_t index;
3863 if (key->AsArrayIndex(&index)) {
3864 return Heap::ToBoolean(object->HasElement(index));
3865 }
3866
ager@chromium.org870a0b62008-11-04 11:43:05 +00003867 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3868 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003869}
3870
3871
lrn@chromium.org303ada72010-10-27 09:33:13 +00003872static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003873 HandleScope scope;
3874 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003875 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003876 return *GetKeysFor(object);
3877}
3878
3879
3880// Returns either a FixedArray as Runtime_GetPropertyNames,
3881// or, if the given object has an enum cache that contains
3882// all enumerable properties of the object and its prototypes
3883// have none, the map of the object. This is used to speed up
3884// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003885static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003886 ASSERT(args.length() == 1);
3887
3888 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3889
3890 if (raw_object->IsSimpleEnum()) return raw_object->map();
3891
3892 HandleScope scope;
3893 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003894 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3895 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003896
3897 // Test again, since cache may have been built by preceding call.
3898 if (object->IsSimpleEnum()) return object->map();
3899
3900 return *content;
3901}
3902
3903
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003904// Find the length of the prototype chain that is to to handled as one. If a
3905// prototype object is hidden it is to be viewed as part of the the object it
3906// is prototype for.
3907static int LocalPrototypeChainLength(JSObject* obj) {
3908 int count = 1;
3909 Object* proto = obj->GetPrototype();
3910 while (proto->IsJSObject() &&
3911 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3912 count++;
3913 proto = JSObject::cast(proto)->GetPrototype();
3914 }
3915 return count;
3916}
3917
3918
3919// Return the names of the local named properties.
3920// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00003921static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003922 HandleScope scope;
3923 ASSERT(args.length() == 1);
3924 if (!args[0]->IsJSObject()) {
3925 return Heap::undefined_value();
3926 }
3927 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3928
3929 // Skip the global proxy as it has no properties and always delegates to the
3930 // real global object.
3931 if (obj->IsJSGlobalProxy()) {
3932 // Only collect names if access is permitted.
3933 if (obj->IsAccessCheckNeeded() &&
3934 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3935 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3936 return *Factory::NewJSArray(0);
3937 }
3938 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3939 }
3940
3941 // Find the number of objects making up this.
3942 int length = LocalPrototypeChainLength(*obj);
3943
3944 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003945 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003946 int total_property_count = 0;
3947 Handle<JSObject> jsproto = obj;
3948 for (int i = 0; i < length; i++) {
3949 // Only collect names if access is permitted.
3950 if (jsproto->IsAccessCheckNeeded() &&
3951 !Top::MayNamedAccess(*jsproto,
3952 Heap::undefined_value(),
3953 v8::ACCESS_KEYS)) {
3954 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3955 return *Factory::NewJSArray(0);
3956 }
3957 int n;
3958 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3959 local_property_count[i] = n;
3960 total_property_count += n;
3961 if (i < length - 1) {
3962 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3963 }
3964 }
3965
3966 // Allocate an array with storage for all the property names.
3967 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3968
3969 // Get the property names.
3970 jsproto = obj;
3971 int proto_with_hidden_properties = 0;
3972 for (int i = 0; i < length; i++) {
3973 jsproto->GetLocalPropertyNames(*names,
3974 i == 0 ? 0 : local_property_count[i - 1]);
3975 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3976 proto_with_hidden_properties++;
3977 }
3978 if (i < length - 1) {
3979 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3980 }
3981 }
3982
3983 // Filter out name of hidden propeties object.
3984 if (proto_with_hidden_properties > 0) {
3985 Handle<FixedArray> old_names = names;
3986 names = Factory::NewFixedArray(
3987 names->length() - proto_with_hidden_properties);
3988 int dest_pos = 0;
3989 for (int i = 0; i < total_property_count; i++) {
3990 Object* name = old_names->get(i);
3991 if (name == Heap::hidden_symbol()) {
3992 continue;
3993 }
3994 names->set(dest_pos++, name);
3995 }
3996 }
3997
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003998 return *Factory::NewJSArrayWithElements(names);
3999}
4000
4001
4002// Return the names of the local indexed properties.
4003// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004004static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004005 HandleScope scope;
4006 ASSERT(args.length() == 1);
4007 if (!args[0]->IsJSObject()) {
4008 return Heap::undefined_value();
4009 }
4010 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4011
4012 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4013 Handle<FixedArray> names = Factory::NewFixedArray(n);
4014 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4015 return *Factory::NewJSArrayWithElements(names);
4016}
4017
4018
4019// Return information on whether an object has a named or indexed interceptor.
4020// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004021static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004022 HandleScope scope;
4023 ASSERT(args.length() == 1);
4024 if (!args[0]->IsJSObject()) {
4025 return Smi::FromInt(0);
4026 }
4027 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4028
4029 int result = 0;
4030 if (obj->HasNamedInterceptor()) result |= 2;
4031 if (obj->HasIndexedInterceptor()) result |= 1;
4032
4033 return Smi::FromInt(result);
4034}
4035
4036
4037// Return property names from named interceptor.
4038// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004039static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004040 HandleScope scope;
4041 ASSERT(args.length() == 1);
4042 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4043
4044 if (obj->HasNamedInterceptor()) {
4045 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4046 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4047 }
4048 return Heap::undefined_value();
4049}
4050
4051
4052// Return element names from indexed interceptor.
4053// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004054static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004055 HandleScope scope;
4056 ASSERT(args.length() == 1);
4057 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4058
4059 if (obj->HasIndexedInterceptor()) {
4060 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4061 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4062 }
4063 return Heap::undefined_value();
4064}
4065
4066
lrn@chromium.org303ada72010-10-27 09:33:13 +00004067static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004068 ASSERT_EQ(args.length(), 1);
4069 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4070 HandleScope scope;
4071 Handle<JSObject> object(raw_object);
4072 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4073 LOCAL_ONLY);
4074 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4075 // property array and since the result is mutable we have to create
4076 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004077 int length = contents->length();
4078 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4079 for (int i = 0; i < length; i++) {
4080 Object* entry = contents->get(i);
4081 if (entry->IsString()) {
4082 copy->set(i, entry);
4083 } else {
4084 ASSERT(entry->IsNumber());
4085 HandleScope scope;
4086 Handle<Object> entry_handle(entry);
4087 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4088 copy->set(i, *entry_str);
4089 }
4090 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004091 return *Factory::NewJSArrayWithElements(copy);
4092}
4093
4094
lrn@chromium.org303ada72010-10-27 09:33:13 +00004095static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 NoHandleAllocation ha;
4097 ASSERT(args.length() == 1);
4098
4099 // Compute the frame holding the arguments.
4100 JavaScriptFrameIterator it;
4101 it.AdvanceToArgumentsFrame();
4102 JavaScriptFrame* frame = it.frame();
4103
4104 // Get the actual number of provided arguments.
4105 const uint32_t n = frame->GetProvidedParametersCount();
4106
4107 // Try to convert the key to an index. If successful and within
4108 // index return the the argument from the frame.
4109 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004110 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 return frame->GetParameter(index);
4112 }
4113
4114 // Convert the key to a string.
4115 HandleScope scope;
4116 bool exception = false;
4117 Handle<Object> converted =
4118 Execution::ToString(args.at<Object>(0), &exception);
4119 if (exception) return Failure::Exception();
4120 Handle<String> key = Handle<String>::cast(converted);
4121
4122 // Try to convert the string key into an array index.
4123 if (key->AsArrayIndex(&index)) {
4124 if (index < n) {
4125 return frame->GetParameter(index);
4126 } else {
4127 return Top::initial_object_prototype()->GetElement(index);
4128 }
4129 }
4130
4131 // Handle special arguments properties.
4132 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4133 if (key->Equals(Heap::callee_symbol())) return frame->function();
4134
4135 // Lookup in the initial Object.prototype object.
4136 return Top::initial_object_prototype()->GetProperty(*key);
4137}
4138
4139
lrn@chromium.org303ada72010-10-27 09:33:13 +00004140static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004141 HandleScope scope;
4142
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004143 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004144 Handle<Object> object = args.at<Object>(0);
4145 if (object->IsJSObject()) {
4146 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004147 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004148 MaybeObject* ok = js_object->TransformToFastProperties(0);
4149 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004150 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004151 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004152 return *object;
4153}
4154
4155
lrn@chromium.org303ada72010-10-27 09:33:13 +00004156static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004157 HandleScope scope;
4158
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004159 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004160 Handle<Object> object = args.at<Object>(0);
4161 if (object->IsJSObject()) {
4162 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004163 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004164 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004165 return *object;
4166}
4167
4168
lrn@chromium.org303ada72010-10-27 09:33:13 +00004169static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004170 NoHandleAllocation ha;
4171 ASSERT(args.length() == 1);
4172
4173 return args[0]->ToBoolean();
4174}
4175
4176
4177// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4178// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004179static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180 NoHandleAllocation ha;
4181
4182 Object* obj = args[0];
4183 if (obj->IsNumber()) return Heap::number_symbol();
4184 HeapObject* heap_obj = HeapObject::cast(obj);
4185
4186 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004187 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188
4189 InstanceType instance_type = heap_obj->map()->instance_type();
4190 if (instance_type < FIRST_NONSTRING_TYPE) {
4191 return Heap::string_symbol();
4192 }
4193
4194 switch (instance_type) {
4195 case ODDBALL_TYPE:
4196 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4197 return Heap::boolean_symbol();
4198 }
4199 if (heap_obj->IsNull()) {
4200 return Heap::object_symbol();
4201 }
4202 ASSERT(heap_obj->IsUndefined());
4203 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004204 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205 return Heap::function_symbol();
4206 default:
4207 // For any kind of object not handled above, the spec rule for
4208 // host objects gives that it is okay to return "object"
4209 return Heap::object_symbol();
4210 }
4211}
4212
4213
lrn@chromium.org25156de2010-04-06 13:10:27 +00004214static bool AreDigits(const char*s, int from, int to) {
4215 for (int i = from; i < to; i++) {
4216 if (s[i] < '0' || s[i] > '9') return false;
4217 }
4218
4219 return true;
4220}
4221
4222
4223static int ParseDecimalInteger(const char*s, int from, int to) {
4224 ASSERT(to - from < 10); // Overflow is not possible.
4225 ASSERT(from < to);
4226 int d = s[from] - '0';
4227
4228 for (int i = from + 1; i < to; i++) {
4229 d = 10 * d + (s[i] - '0');
4230 }
4231
4232 return d;
4233}
4234
4235
lrn@chromium.org303ada72010-10-27 09:33:13 +00004236static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004237 NoHandleAllocation ha;
4238 ASSERT(args.length() == 1);
4239 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004240 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004241
4242 // Fast case: short integer or some sorts of junk values.
4243 int len = subject->length();
4244 if (subject->IsSeqAsciiString()) {
4245 if (len == 0) return Smi::FromInt(0);
4246
4247 char const* data = SeqAsciiString::cast(subject)->GetChars();
4248 bool minus = (data[0] == '-');
4249 int start_pos = (minus ? 1 : 0);
4250
4251 if (start_pos == len) {
4252 return Heap::nan_value();
4253 } else if (data[start_pos] > '9') {
4254 // Fast check for a junk value. A valid string may start from a
4255 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4256 // the 'I' character ('Infinity'). All of that have codes not greater than
4257 // '9' except 'I'.
4258 if (data[start_pos] != 'I') {
4259 return Heap::nan_value();
4260 }
4261 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4262 // The maximal/minimal smi has 10 digits. If the string has less digits we
4263 // know it will fit into the smi-data type.
4264 int d = ParseDecimalInteger(data, start_pos, len);
4265 if (minus) {
4266 if (d == 0) return Heap::minus_zero_value();
4267 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004268 } else if (!subject->HasHashCode() &&
4269 len <= String::kMaxArrayIndexSize &&
4270 (len == 1 || data[0] != '0')) {
4271 // String hash is not calculated yet but all the data are present.
4272 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004273 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004274#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004275 subject->Hash(); // Force hash calculation.
4276 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4277 static_cast<int>(hash));
4278#endif
4279 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004280 }
4281 return Smi::FromInt(d);
4282 }
4283 }
4284
4285 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004286 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4287}
4288
4289
lrn@chromium.org303ada72010-10-27 09:33:13 +00004290static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004291 NoHandleAllocation ha;
4292 ASSERT(args.length() == 1);
4293
4294 CONVERT_CHECKED(JSArray, codes, args[0]);
4295 int length = Smi::cast(codes->length())->value();
4296
4297 // Check if the string can be ASCII.
4298 int i;
4299 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004300 Object* element;
4301 { MaybeObject* maybe_element = codes->GetElement(i);
4302 // We probably can't get an exception here, but just in order to enforce
4303 // the checking of inputs in the runtime calls we check here.
4304 if (!maybe_element->ToObject(&element)) return maybe_element;
4305 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004306 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4307 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4308 break;
4309 }
4310
lrn@chromium.org303ada72010-10-27 09:33:13 +00004311 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004312 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004313 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004314 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004315 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004316 }
4317
lrn@chromium.org303ada72010-10-27 09:33:13 +00004318 Object* object = NULL;
4319 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004320 String* result = String::cast(object);
4321 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004322 Object* element;
4323 { MaybeObject* maybe_element = codes->GetElement(i);
4324 if (!maybe_element->ToObject(&element)) return maybe_element;
4325 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004326 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004327 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004328 }
4329 return result;
4330}
4331
4332
4333// kNotEscaped is generated by the following:
4334//
4335// #!/bin/perl
4336// for (my $i = 0; $i < 256; $i++) {
4337// print "\n" if $i % 16 == 0;
4338// my $c = chr($i);
4339// my $escaped = 1;
4340// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4341// print $escaped ? "0, " : "1, ";
4342// }
4343
4344
4345static bool IsNotEscaped(uint16_t character) {
4346 // Only for 8 bit characters, the rest are always escaped (in a different way)
4347 ASSERT(character < 256);
4348 static const char kNotEscaped[256] = {
4349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4353 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4354 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4355 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4356 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4365 };
4366 return kNotEscaped[character] != 0;
4367}
4368
4369
lrn@chromium.org303ada72010-10-27 09:33:13 +00004370static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004371 const char hex_chars[] = "0123456789ABCDEF";
4372 NoHandleAllocation ha;
4373 ASSERT(args.length() == 1);
4374 CONVERT_CHECKED(String, source, args[0]);
4375
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004376 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004377
4378 int escaped_length = 0;
4379 int length = source->length();
4380 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004381 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004382 buffer->Reset(source);
4383 while (buffer->has_more()) {
4384 uint16_t character = buffer->GetNext();
4385 if (character >= 256) {
4386 escaped_length += 6;
4387 } else if (IsNotEscaped(character)) {
4388 escaped_length++;
4389 } else {
4390 escaped_length += 3;
4391 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004392 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004393 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004394 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004395 Top::context()->mark_out_of_memory();
4396 return Failure::OutOfMemoryException();
4397 }
4398 }
4399 }
4400 // No length change implies no change. Return original string if no change.
4401 if (escaped_length == length) {
4402 return source;
4403 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004404 Object* o;
4405 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4406 if (!maybe_o->ToObject(&o)) return maybe_o;
4407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408 String* destination = String::cast(o);
4409 int dest_position = 0;
4410
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004411 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004412 buffer->Rewind();
4413 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004414 uint16_t chr = buffer->GetNext();
4415 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004416 destination->Set(dest_position, '%');
4417 destination->Set(dest_position+1, 'u');
4418 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4419 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4420 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4421 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004423 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004424 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004425 dest_position++;
4426 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004427 destination->Set(dest_position, '%');
4428 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4429 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004430 dest_position += 3;
4431 }
4432 }
4433 return destination;
4434}
4435
4436
4437static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4438 static const signed char kHexValue['g'] = {
4439 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4440 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4441 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4442 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4443 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4444 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4445 -1, 10, 11, 12, 13, 14, 15 };
4446
4447 if (character1 > 'f') return -1;
4448 int hi = kHexValue[character1];
4449 if (hi == -1) return -1;
4450 if (character2 > 'f') return -1;
4451 int lo = kHexValue[character2];
4452 if (lo == -1) return -1;
4453 return (hi << 4) + lo;
4454}
4455
4456
ager@chromium.org870a0b62008-11-04 11:43:05 +00004457static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004458 int i,
4459 int length,
4460 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004461 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004462 int32_t hi = 0;
4463 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004464 if (character == '%' &&
4465 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004466 source->Get(i + 1) == 'u' &&
4467 (hi = TwoDigitHex(source->Get(i + 2),
4468 source->Get(i + 3))) != -1 &&
4469 (lo = TwoDigitHex(source->Get(i + 4),
4470 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 *step = 6;
4472 return (hi << 8) + lo;
4473 } else if (character == '%' &&
4474 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004475 (lo = TwoDigitHex(source->Get(i + 1),
4476 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 *step = 3;
4478 return lo;
4479 } else {
4480 *step = 1;
4481 return character;
4482 }
4483}
4484
4485
lrn@chromium.org303ada72010-10-27 09:33:13 +00004486static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004487 NoHandleAllocation ha;
4488 ASSERT(args.length() == 1);
4489 CONVERT_CHECKED(String, source, args[0]);
4490
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004491 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004492
4493 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004494 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004495
4496 int unescaped_length = 0;
4497 for (int i = 0; i < length; unescaped_length++) {
4498 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004499 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004500 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004501 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004502 i += step;
4503 }
4504
4505 // No length change implies no change. Return original string if no change.
4506 if (unescaped_length == length)
4507 return source;
4508
lrn@chromium.org303ada72010-10-27 09:33:13 +00004509 Object* o;
4510 { MaybeObject* maybe_o = ascii ?
4511 Heap::AllocateRawAsciiString(unescaped_length) :
4512 Heap::AllocateRawTwoByteString(unescaped_length);
4513 if (!maybe_o->ToObject(&o)) return maybe_o;
4514 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515 String* destination = String::cast(o);
4516
4517 int dest_position = 0;
4518 for (int i = 0; i < length; dest_position++) {
4519 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004520 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521 i += step;
4522 }
4523 return destination;
4524}
4525
4526
lrn@chromium.org303ada72010-10-27 09:33:13 +00004527static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004528 NoHandleAllocation ha;
4529
4530 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004531 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004533 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004534
lrn@chromium.org25156de2010-04-06 13:10:27 +00004535 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4536 double value = StringToInt(s, radix);
4537 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004538}
4539
4540
lrn@chromium.org303ada72010-10-27 09:33:13 +00004541static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004542 NoHandleAllocation ha;
4543 CONVERT_CHECKED(String, str, args[0]);
4544
4545 // ECMA-262 section 15.1.2.3, empty string is NaN
4546 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4547
4548 // Create a number object from the value.
4549 return Heap::NumberFromDouble(value);
4550}
4551
4552
4553static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4554static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4555
4556
4557template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004558MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4559 String* s,
4560 int length,
4561 int input_string_length,
4562 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004563 // We try this twice, once with the assumption that the result is no longer
4564 // than the input and, if that assumption breaks, again with the exact
4565 // length. This may not be pretty, but it is nicer than what was here before
4566 // and I hereby claim my vaffel-is.
4567 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004568 // Allocate the resulting string.
4569 //
4570 // NOTE: This assumes that the upper/lower case of an ascii
4571 // character is also ascii. This is currently the case, but it
4572 // might break in the future if we implement more context and locale
4573 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004574 Object* o;
4575 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4576 ? Heap::AllocateRawAsciiString(length)
4577 : Heap::AllocateRawTwoByteString(length);
4578 if (!maybe_o->ToObject(&o)) return maybe_o;
4579 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004580 String* result = String::cast(o);
4581 bool has_changed_character = false;
4582
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004583 // Convert all characters to upper case, assuming that they will fit
4584 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004585 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004587 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004588 // We can assume that the string is not empty
4589 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004590 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004591 bool has_next = buffer->has_more();
4592 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 int char_length = mapping->get(current, next, chars);
4594 if (char_length == 0) {
4595 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004596 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004597 i++;
4598 } else if (char_length == 1) {
4599 // Common case: converting the letter resulted in one character.
4600 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004601 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004602 has_changed_character = true;
4603 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004604 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004605 // We've assumed that the result would be as long as the
4606 // input but here is a character that converts to several
4607 // characters. No matter, we calculate the exact length
4608 // of the result and try the whole thing again.
4609 //
4610 // Note that this leaves room for optimization. We could just
4611 // memcpy what we already have to the result string. Also,
4612 // the result string is the last object allocated we could
4613 // "realloc" it and probably, in the vast majority of cases,
4614 // extend the existing string to be able to hold the full
4615 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004616 int next_length = 0;
4617 if (has_next) {
4618 next_length = mapping->get(next, 0, chars);
4619 if (next_length == 0) next_length = 1;
4620 }
4621 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004622 while (buffer->has_more()) {
4623 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004624 // NOTE: we use 0 as the next character here because, while
4625 // the next character may affect what a character converts to,
4626 // it does not in any case affect the length of what it convert
4627 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004628 int char_length = mapping->get(current, 0, chars);
4629 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004630 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004631 if (current_length > Smi::kMaxValue) {
4632 Top::context()->mark_out_of_memory();
4633 return Failure::OutOfMemoryException();
4634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004635 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004636 // Try again with the real length.
4637 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004638 } else {
4639 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004640 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004641 i++;
4642 }
4643 has_changed_character = true;
4644 }
4645 current = next;
4646 }
4647 if (has_changed_character) {
4648 return result;
4649 } else {
4650 // If we didn't actually change anything in doing the conversion
4651 // we simple return the result and let the converted string
4652 // become garbage; there is no reason to keep two identical strings
4653 // alive.
4654 return s;
4655 }
4656}
4657
4658
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004659namespace {
4660
lrn@chromium.org303ada72010-10-27 09:33:13 +00004661static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
4662
4663
4664// Given a word and two range boundaries returns a word with high bit
4665// set in every byte iff the corresponding input byte was strictly in
4666// the range (m, n). All the other bits in the result are cleared.
4667// This function is only useful when it can be inlined and the
4668// boundaries are statically known.
4669// Requires: all bytes in the input word and the boundaries must be
4670// ascii (less than 0x7F).
4671static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
4672 // Every byte in an ascii string is less than or equal to 0x7F.
4673 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
4674 // Use strict inequalities since in edge cases the function could be
4675 // further simplified.
4676 ASSERT(0 < m && m < n && n < 0x7F);
4677 // Has high bit set in every w byte less than n.
4678 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
4679 // Has high bit set in every w byte greater than m.
4680 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
4681 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
4682}
4683
4684
4685enum AsciiCaseConversion {
4686 ASCII_TO_LOWER,
4687 ASCII_TO_UPPER
4688};
4689
4690
4691template <AsciiCaseConversion dir>
4692struct FastAsciiConverter {
4693 static bool Convert(char* dst, char* src, int length) {
4694#ifdef DEBUG
4695 char* saved_dst = dst;
4696 char* saved_src = src;
4697#endif
4698 // We rely on the distance between upper and lower case letters
4699 // being a known power of 2.
4700 ASSERT('a' - 'A' == (1 << 5));
4701 // Boundaries for the range of input characters than require conversion.
4702 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
4703 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
4704 bool changed = false;
4705 char* const limit = src + length;
4706#ifdef V8_HOST_CAN_READ_UNALIGNED
4707 // Process the prefix of the input that requires no conversion one
4708 // (machine) word at a time.
4709 while (src <= limit - sizeof(uintptr_t)) {
4710 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4711 if (AsciiRangeMask(w, lo, hi) != 0) {
4712 changed = true;
4713 break;
4714 }
4715 *reinterpret_cast<uintptr_t*>(dst) = w;
4716 src += sizeof(uintptr_t);
4717 dst += sizeof(uintptr_t);
4718 }
4719 // Process the remainder of the input performing conversion when
4720 // required one word at a time.
4721 while (src <= limit - sizeof(uintptr_t)) {
4722 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4723 uintptr_t m = AsciiRangeMask(w, lo, hi);
4724 // The mask has high (7th) bit set in every byte that needs
4725 // conversion and we know that the distance between cases is
4726 // 1 << 5.
4727 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
4728 src += sizeof(uintptr_t);
4729 dst += sizeof(uintptr_t);
4730 }
4731#endif
4732 // Process the last few bytes of the input (or the whole input if
4733 // unaligned access is not supported).
4734 while (src < limit) {
4735 char c = *src;
4736 if (lo < c && c < hi) {
4737 c ^= (1 << 5);
4738 changed = true;
4739 }
4740 *dst = c;
4741 ++src;
4742 ++dst;
4743 }
4744#ifdef DEBUG
4745 CheckConvert(saved_dst, saved_src, length, changed);
4746#endif
4747 return changed;
4748 }
4749
4750#ifdef DEBUG
4751 static void CheckConvert(char* dst, char* src, int length, bool changed) {
4752 bool expected_changed = false;
4753 for (int i = 0; i < length; i++) {
4754 if (dst[i] == src[i]) continue;
4755 expected_changed = true;
4756 if (dir == ASCII_TO_LOWER) {
4757 ASSERT('A' <= src[i] && src[i] <= 'Z');
4758 ASSERT(dst[i] == src[i] + ('a' - 'A'));
4759 } else {
4760 ASSERT(dir == ASCII_TO_UPPER);
4761 ASSERT('a' <= src[i] && src[i] <= 'z');
4762 ASSERT(dst[i] == src[i] - ('a' - 'A'));
4763 }
4764 }
4765 ASSERT(expected_changed == changed);
4766 }
4767#endif
4768};
4769
4770
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004771struct ToLowerTraits {
4772 typedef unibrow::ToLowercase UnibrowConverter;
4773
lrn@chromium.org303ada72010-10-27 09:33:13 +00004774 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004775};
4776
4777
4778struct ToUpperTraits {
4779 typedef unibrow::ToUppercase UnibrowConverter;
4780
lrn@chromium.org303ada72010-10-27 09:33:13 +00004781 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004782};
4783
4784} // namespace
4785
4786
4787template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004788MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004789 Arguments args,
4790 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004791 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004792 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004793 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004794
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004795 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004796 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004797 if (length == 0) return s;
4798
4799 // Simpler handling of ascii strings.
4800 //
4801 // NOTE: This assumes that the upper/lower case of an ascii
4802 // character is also ascii. This is currently the case, but it
4803 // might break in the future if we implement more context and locale
4804 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004805 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004806 Object* o;
4807 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
4808 if (!maybe_o->ToObject(&o)) return maybe_o;
4809 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004810 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004811 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004812 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004813 return has_changed_character ? result : s;
4814 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004815
lrn@chromium.org303ada72010-10-27 09:33:13 +00004816 Object* answer;
4817 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
4818 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
4819 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004820 if (answer->IsSmi()) {
4821 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004822 { MaybeObject* maybe_answer =
4823 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
4824 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
4825 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004826 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004827 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004828}
4829
4830
lrn@chromium.org303ada72010-10-27 09:33:13 +00004831static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004832 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833}
4834
4835
lrn@chromium.org303ada72010-10-27 09:33:13 +00004836static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004837 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838}
4839
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004840
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004841static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
4842 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
4843}
4844
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004845
lrn@chromium.org303ada72010-10-27 09:33:13 +00004846static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004847 NoHandleAllocation ha;
4848 ASSERT(args.length() == 3);
4849
4850 CONVERT_CHECKED(String, s, args[0]);
4851 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
4852 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
4853
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004854 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004855 int length = s->length();
4856
4857 int left = 0;
4858 if (trimLeft) {
4859 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
4860 left++;
4861 }
4862 }
4863
4864 int right = length;
4865 if (trimRight) {
4866 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
4867 right--;
4868 }
4869 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004870 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004871}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004873
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004874template <typename SubjectChar, typename PatternChar>
4875void FindStringIndices(Vector<const SubjectChar> subject,
4876 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004877 ZoneList<int>* indices,
4878 unsigned int limit) {
4879 ASSERT(limit > 0);
4880 // Collect indices of pattern in subject, and the end-of-string index.
4881 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004882 StringSearch<PatternChar, SubjectChar> search(pattern);
4883 int pattern_length = pattern.length();
4884 int index = 0;
4885 while (limit > 0) {
4886 index = search.Search(subject, index);
4887 if (index < 0) return;
4888 indices->Add(index);
4889 index += pattern_length;
4890 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004891 }
4892}
4893
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004894
lrn@chromium.org303ada72010-10-27 09:33:13 +00004895static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004896 ASSERT(args.length() == 3);
4897 HandleScope handle_scope;
4898 CONVERT_ARG_CHECKED(String, subject, 0);
4899 CONVERT_ARG_CHECKED(String, pattern, 1);
4900 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
4901
4902 int subject_length = subject->length();
4903 int pattern_length = pattern->length();
4904 RUNTIME_ASSERT(pattern_length > 0);
4905
4906 // The limit can be very large (0xffffffffu), but since the pattern
4907 // isn't empty, we can never create more parts than ~half the length
4908 // of the subject.
4909
4910 if (!subject->IsFlat()) FlattenString(subject);
4911
4912 static const int kMaxInitialListCapacity = 16;
4913
4914 ZoneScope scope(DELETE_ON_EXIT);
4915
4916 // Find (up to limit) indices of separator and end-of-string in subject
4917 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
4918 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004919 if (!pattern->IsFlat()) FlattenString(pattern);
4920
4921 // No allocation block.
4922 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004923 AssertNoAllocation nogc;
4924 if (subject->IsAsciiRepresentation()) {
4925 Vector<const char> subject_vector = subject->ToAsciiVector();
4926 if (pattern->IsAsciiRepresentation()) {
4927 FindStringIndices(subject_vector,
4928 pattern->ToAsciiVector(),
4929 &indices,
4930 limit);
4931 } else {
4932 FindStringIndices(subject_vector,
4933 pattern->ToUC16Vector(),
4934 &indices,
4935 limit);
4936 }
4937 } else {
4938 Vector<const uc16> subject_vector = subject->ToUC16Vector();
4939 if (pattern->IsAsciiRepresentation()) {
4940 FindStringIndices(subject_vector,
4941 pattern->ToAsciiVector(),
4942 &indices,
4943 limit);
4944 } else {
4945 FindStringIndices(subject_vector,
4946 pattern->ToUC16Vector(),
4947 &indices,
4948 limit);
4949 }
4950 }
4951 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004952
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004953 if (static_cast<uint32_t>(indices.length()) < limit) {
4954 indices.Add(subject_length);
4955 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004956
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004957 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004958
4959 // Create JSArray of substrings separated by separator.
4960 int part_count = indices.length();
4961
4962 Handle<JSArray> result = Factory::NewJSArray(part_count);
4963 result->set_length(Smi::FromInt(part_count));
4964
4965 ASSERT(result->HasFastElements());
4966
4967 if (part_count == 1 && indices.at(0) == subject_length) {
4968 FixedArray::cast(result->elements())->set(0, *subject);
4969 return *result;
4970 }
4971
4972 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
4973 int part_start = 0;
4974 for (int i = 0; i < part_count; i++) {
4975 HandleScope local_loop_handle;
4976 int part_end = indices.at(i);
4977 Handle<String> substring =
4978 Factory::NewSubString(subject, part_start, part_end);
4979 elements->set(i, *substring);
4980 part_start = part_end + pattern_length;
4981 }
4982
4983 return *result;
4984}
4985
4986
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004987// Copies ascii characters to the given fixed array looking up
4988// one-char strings in the cache. Gives up on the first char that is
4989// not in the cache and fills the remainder with smi zeros. Returns
4990// the length of the successfully copied prefix.
4991static int CopyCachedAsciiCharsToArray(const char* chars,
4992 FixedArray* elements,
4993 int length) {
4994 AssertNoAllocation nogc;
4995 FixedArray* ascii_cache = Heap::single_character_string_cache();
4996 Object* undefined = Heap::undefined_value();
4997 int i;
4998 for (i = 0; i < length; ++i) {
4999 Object* value = ascii_cache->get(chars[i]);
5000 if (value == undefined) break;
5001 ASSERT(!Heap::InNewSpace(value));
5002 elements->set(i, value, SKIP_WRITE_BARRIER);
5003 }
5004 if (i < length) {
5005 ASSERT(Smi::FromInt(0) == 0);
5006 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5007 }
5008#ifdef DEBUG
5009 for (int j = 0; j < length; ++j) {
5010 Object* element = elements->get(j);
5011 ASSERT(element == Smi::FromInt(0) ||
5012 (element->IsString() && String::cast(element)->LooksValid()));
5013 }
5014#endif
5015 return i;
5016}
5017
5018
5019// Converts a String to JSArray.
5020// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005021static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005022 HandleScope scope;
5023 ASSERT(args.length() == 1);
5024 CONVERT_ARG_CHECKED(String, s, 0);
5025
5026 s->TryFlatten();
5027 const int length = s->length();
5028
5029 Handle<FixedArray> elements;
5030 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005031 Object* obj;
5032 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5033 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5034 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005035 elements = Handle<FixedArray>(FixedArray::cast(obj));
5036
5037 Vector<const char> chars = s->ToAsciiVector();
5038 // Note, this will initialize all elements (not only the prefix)
5039 // to prevent GC from seeing partially initialized array.
5040 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5041 *elements,
5042 length);
5043
5044 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005045 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5046 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005047 }
5048 } else {
5049 elements = Factory::NewFixedArray(length);
5050 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005051 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5052 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005053 }
5054 }
5055
5056#ifdef DEBUG
5057 for (int i = 0; i < length; ++i) {
5058 ASSERT(String::cast(elements->get(i))->length() == 1);
5059 }
5060#endif
5061
5062 return *Factory::NewJSArrayWithElements(elements);
5063}
5064
5065
lrn@chromium.org303ada72010-10-27 09:33:13 +00005066static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005067 NoHandleAllocation ha;
5068 ASSERT(args.length() == 1);
5069 CONVERT_CHECKED(String, value, args[0]);
5070 return value->ToObject();
5071}
5072
5073
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005074bool Runtime::IsUpperCaseChar(uint16_t ch) {
5075 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5076 int char_length = to_upper_mapping.get(ch, 0, chars);
5077 return char_length == 0;
5078}
5079
5080
lrn@chromium.org303ada72010-10-27 09:33:13 +00005081static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005082 NoHandleAllocation ha;
5083 ASSERT(args.length() == 1);
5084
5085 Object* number = args[0];
5086 RUNTIME_ASSERT(number->IsNumber());
5087
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005088 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005089}
5090
5091
lrn@chromium.org303ada72010-10-27 09:33:13 +00005092static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005093 NoHandleAllocation ha;
5094 ASSERT(args.length() == 1);
5095
5096 Object* number = args[0];
5097 RUNTIME_ASSERT(number->IsNumber());
5098
5099 return Heap::NumberToString(number, false);
5100}
5101
5102
lrn@chromium.org303ada72010-10-27 09:33:13 +00005103static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005104 NoHandleAllocation ha;
5105 ASSERT(args.length() == 1);
5106
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005107 CONVERT_DOUBLE_CHECKED(number, args[0]);
5108
5109 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5110 if (number > 0 && number <= Smi::kMaxValue) {
5111 return Smi::FromInt(static_cast<int>(number));
5112 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005113 return Heap::NumberFromDouble(DoubleToInteger(number));
5114}
5115
5116
lrn@chromium.org303ada72010-10-27 09:33:13 +00005117static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005118 NoHandleAllocation ha;
5119 ASSERT(args.length() == 1);
5120
5121 CONVERT_DOUBLE_CHECKED(number, args[0]);
5122
5123 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5124 if (number > 0 && number <= Smi::kMaxValue) {
5125 return Smi::FromInt(static_cast<int>(number));
5126 }
5127
5128 double double_value = DoubleToInteger(number);
5129 // Map both -0 and +0 to +0.
5130 if (double_value == 0) double_value = 0;
5131
5132 return Heap::NumberFromDouble(double_value);
5133}
5134
5135
lrn@chromium.org303ada72010-10-27 09:33:13 +00005136static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005137 NoHandleAllocation ha;
5138 ASSERT(args.length() == 1);
5139
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005140 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005141 return Heap::NumberFromUint32(number);
5142}
5143
5144
lrn@chromium.org303ada72010-10-27 09:33:13 +00005145static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005146 NoHandleAllocation ha;
5147 ASSERT(args.length() == 1);
5148
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005149 CONVERT_DOUBLE_CHECKED(number, args[0]);
5150
5151 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5152 if (number > 0 && number <= Smi::kMaxValue) {
5153 return Smi::FromInt(static_cast<int>(number));
5154 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005155 return Heap::NumberFromInt32(DoubleToInt32(number));
5156}
5157
5158
ager@chromium.org870a0b62008-11-04 11:43:05 +00005159// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5160// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005161static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005162 NoHandleAllocation ha;
5163 ASSERT(args.length() == 1);
5164
5165 Object* obj = args[0];
5166 if (obj->IsSmi()) {
5167 return obj;
5168 }
5169 if (obj->IsHeapNumber()) {
5170 double value = HeapNumber::cast(obj)->value();
5171 int int_value = FastD2I(value);
5172 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5173 return Smi::FromInt(int_value);
5174 }
5175 }
5176 return Heap::nan_value();
5177}
5178
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005179
lrn@chromium.org303ada72010-10-27 09:33:13 +00005180static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181 NoHandleAllocation ha;
5182 ASSERT(args.length() == 2);
5183
5184 CONVERT_DOUBLE_CHECKED(x, args[0]);
5185 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005186 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005187}
5188
5189
lrn@chromium.org303ada72010-10-27 09:33:13 +00005190static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005191 NoHandleAllocation ha;
5192 ASSERT(args.length() == 2);
5193
5194 CONVERT_DOUBLE_CHECKED(x, args[0]);
5195 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005196 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005197}
5198
5199
lrn@chromium.org303ada72010-10-27 09:33:13 +00005200static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201 NoHandleAllocation ha;
5202 ASSERT(args.length() == 2);
5203
5204 CONVERT_DOUBLE_CHECKED(x, args[0]);
5205 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005206 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005207}
5208
5209
lrn@chromium.org303ada72010-10-27 09:33:13 +00005210static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005211 NoHandleAllocation ha;
5212 ASSERT(args.length() == 1);
5213
5214 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005215 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216}
5217
5218
lrn@chromium.org303ada72010-10-27 09:33:13 +00005219static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005220 NoHandleAllocation ha;
5221 ASSERT(args.length() == 0);
5222
5223 return Heap::NumberFromDouble(9876543210.0);
5224}
5225
5226
lrn@chromium.org303ada72010-10-27 09:33:13 +00005227static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 NoHandleAllocation ha;
5229 ASSERT(args.length() == 2);
5230
5231 CONVERT_DOUBLE_CHECKED(x, args[0]);
5232 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005233 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005234}
5235
5236
lrn@chromium.org303ada72010-10-27 09:33:13 +00005237static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005238 NoHandleAllocation ha;
5239 ASSERT(args.length() == 2);
5240
5241 CONVERT_DOUBLE_CHECKED(x, args[0]);
5242 CONVERT_DOUBLE_CHECKED(y, args[1]);
5243
ager@chromium.org3811b432009-10-28 14:53:37 +00005244 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005245 // NumberFromDouble may return a Smi instead of a Number object
5246 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005247}
5248
5249
lrn@chromium.org303ada72010-10-27 09:33:13 +00005250static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251 NoHandleAllocation ha;
5252 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005253 CONVERT_CHECKED(String, str1, args[0]);
5254 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005255 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005256 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005257}
5258
5259
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005260template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005261static inline void StringBuilderConcatHelper(String* special,
5262 sinkchar* sink,
5263 FixedArray* fixed_array,
5264 int array_length) {
5265 int position = 0;
5266 for (int i = 0; i < array_length; i++) {
5267 Object* element = fixed_array->get(i);
5268 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005269 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005270 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005271 int pos;
5272 int len;
5273 if (encoded_slice > 0) {
5274 // Position and length encoded in one smi.
5275 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5276 len = StringBuilderSubstringLength::decode(encoded_slice);
5277 } else {
5278 // Position and length encoded in two smis.
5279 Object* obj = fixed_array->get(++i);
5280 ASSERT(obj->IsSmi());
5281 pos = Smi::cast(obj)->value();
5282 len = -encoded_slice;
5283 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005284 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005285 sink + position,
5286 pos,
5287 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005288 position += len;
5289 } else {
5290 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005291 int element_length = string->length();
5292 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005293 position += element_length;
5294 }
5295 }
5296}
5297
5298
lrn@chromium.org303ada72010-10-27 09:33:13 +00005299static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005300 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005301 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005302 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005303 if (!args[1]->IsSmi()) {
5304 Top::context()->mark_out_of_memory();
5305 return Failure::OutOfMemoryException();
5306 }
5307 int array_length = Smi::cast(args[1])->value();
5308 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005309
5310 // This assumption is used by the slice encoding in one or two smis.
5311 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5312
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005313 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005314 if (!array->HasFastElements()) {
5315 return Top::Throw(Heap::illegal_argument_symbol());
5316 }
5317 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005318 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005320 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005321
5322 if (array_length == 0) {
5323 return Heap::empty_string();
5324 } else if (array_length == 1) {
5325 Object* first = fixed_array->get(0);
5326 if (first->IsString()) return first;
5327 }
5328
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005329 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005330 int position = 0;
5331 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005332 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005333 Object* elt = fixed_array->get(i);
5334 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005335 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005336 int smi_value = Smi::cast(elt)->value();
5337 int pos;
5338 int len;
5339 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005340 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005341 pos = StringBuilderSubstringPosition::decode(smi_value);
5342 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005343 } else {
5344 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005345 len = -smi_value;
5346 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005347 i++;
5348 if (i >= array_length) {
5349 return Top::Throw(Heap::illegal_argument_symbol());
5350 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005351 Object* next_smi = fixed_array->get(i);
5352 if (!next_smi->IsSmi()) {
5353 return Top::Throw(Heap::illegal_argument_symbol());
5354 }
5355 pos = Smi::cast(next_smi)->value();
5356 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005357 return Top::Throw(Heap::illegal_argument_symbol());
5358 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005359 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005360 ASSERT(pos >= 0);
5361 ASSERT(len >= 0);
5362 if (pos > special_length || len > special_length - pos) {
5363 return Top::Throw(Heap::illegal_argument_symbol());
5364 }
5365 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005366 } else if (elt->IsString()) {
5367 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005368 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005369 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005370 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005371 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005372 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005373 } else {
5374 return Top::Throw(Heap::illegal_argument_symbol());
5375 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005376 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005377 Top::context()->mark_out_of_memory();
5378 return Failure::OutOfMemoryException();
5379 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005380 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005381 }
5382
5383 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005384 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005385
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005386 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005387 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5388 if (!maybe_object->ToObject(&object)) return maybe_object;
5389 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005390 SeqAsciiString* answer = SeqAsciiString::cast(object);
5391 StringBuilderConcatHelper(special,
5392 answer->GetChars(),
5393 fixed_array,
5394 array_length);
5395 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005396 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005397 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5398 if (!maybe_object->ToObject(&object)) return maybe_object;
5399 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005400 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5401 StringBuilderConcatHelper(special,
5402 answer->GetChars(),
5403 fixed_array,
5404 array_length);
5405 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005406 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005407}
5408
5409
lrn@chromium.org303ada72010-10-27 09:33:13 +00005410static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411 NoHandleAllocation ha;
5412 ASSERT(args.length() == 2);
5413
5414 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5415 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5416 return Heap::NumberFromInt32(x | y);
5417}
5418
5419
lrn@chromium.org303ada72010-10-27 09:33:13 +00005420static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005421 NoHandleAllocation ha;
5422 ASSERT(args.length() == 2);
5423
5424 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5425 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5426 return Heap::NumberFromInt32(x & y);
5427}
5428
5429
lrn@chromium.org303ada72010-10-27 09:33:13 +00005430static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005431 NoHandleAllocation ha;
5432 ASSERT(args.length() == 2);
5433
5434 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5435 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5436 return Heap::NumberFromInt32(x ^ y);
5437}
5438
5439
lrn@chromium.org303ada72010-10-27 09:33:13 +00005440static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005441 NoHandleAllocation ha;
5442 ASSERT(args.length() == 1);
5443
5444 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5445 return Heap::NumberFromInt32(~x);
5446}
5447
5448
lrn@chromium.org303ada72010-10-27 09:33:13 +00005449static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005450 NoHandleAllocation ha;
5451 ASSERT(args.length() == 2);
5452
5453 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5454 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5455 return Heap::NumberFromInt32(x << (y & 0x1f));
5456}
5457
5458
lrn@chromium.org303ada72010-10-27 09:33:13 +00005459static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005460 NoHandleAllocation ha;
5461 ASSERT(args.length() == 2);
5462
5463 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5464 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5465 return Heap::NumberFromUint32(x >> (y & 0x1f));
5466}
5467
5468
lrn@chromium.org303ada72010-10-27 09:33:13 +00005469static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005470 NoHandleAllocation ha;
5471 ASSERT(args.length() == 2);
5472
5473 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5474 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5475 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5476}
5477
5478
lrn@chromium.org303ada72010-10-27 09:33:13 +00005479static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005480 NoHandleAllocation ha;
5481 ASSERT(args.length() == 2);
5482
5483 CONVERT_DOUBLE_CHECKED(x, args[0]);
5484 CONVERT_DOUBLE_CHECKED(y, args[1]);
5485 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5486 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5487 if (x == y) return Smi::FromInt(EQUAL);
5488 Object* result;
5489 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5490 result = Smi::FromInt(EQUAL);
5491 } else {
5492 result = Smi::FromInt(NOT_EQUAL);
5493 }
5494 return result;
5495}
5496
5497
lrn@chromium.org303ada72010-10-27 09:33:13 +00005498static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005499 NoHandleAllocation ha;
5500 ASSERT(args.length() == 2);
5501
5502 CONVERT_CHECKED(String, x, args[0]);
5503 CONVERT_CHECKED(String, y, args[1]);
5504
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005505 bool not_equal = !x->Equals(y);
5506 // This is slightly convoluted because the value that signifies
5507 // equality is 0 and inequality is 1 so we have to negate the result
5508 // from String::Equals.
5509 ASSERT(not_equal == 0 || not_equal == 1);
5510 STATIC_CHECK(EQUAL == 0);
5511 STATIC_CHECK(NOT_EQUAL == 1);
5512 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005513}
5514
5515
lrn@chromium.org303ada72010-10-27 09:33:13 +00005516static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005517 NoHandleAllocation ha;
5518 ASSERT(args.length() == 3);
5519
5520 CONVERT_DOUBLE_CHECKED(x, args[0]);
5521 CONVERT_DOUBLE_CHECKED(y, args[1]);
5522 if (isnan(x) || isnan(y)) return args[2];
5523 if (x == y) return Smi::FromInt(EQUAL);
5524 if (isless(x, y)) return Smi::FromInt(LESS);
5525 return Smi::FromInt(GREATER);
5526}
5527
5528
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005529// Compare two Smis as if they were converted to strings and then
5530// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005531static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005532 NoHandleAllocation ha;
5533 ASSERT(args.length() == 2);
5534
5535 // Arrays for the individual characters of the two Smis. Smis are
5536 // 31 bit integers and 10 decimal digits are therefore enough.
5537 static int x_elms[10];
5538 static int y_elms[10];
5539
5540 // Extract the integer values from the Smis.
5541 CONVERT_CHECKED(Smi, x, args[0]);
5542 CONVERT_CHECKED(Smi, y, args[1]);
5543 int x_value = x->value();
5544 int y_value = y->value();
5545
5546 // If the integers are equal so are the string representations.
5547 if (x_value == y_value) return Smi::FromInt(EQUAL);
5548
5549 // If one of the integers are zero the normal integer order is the
5550 // same as the lexicographic order of the string representations.
5551 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5552
ager@chromium.org32912102009-01-16 10:38:43 +00005553 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005554 // smallest because the char code of '-' is less than the char code
5555 // of any digit. Otherwise, we make both values positive.
5556 if (x_value < 0 || y_value < 0) {
5557 if (y_value >= 0) return Smi::FromInt(LESS);
5558 if (x_value >= 0) return Smi::FromInt(GREATER);
5559 x_value = -x_value;
5560 y_value = -y_value;
5561 }
5562
5563 // Convert the integers to arrays of their decimal digits.
5564 int x_index = 0;
5565 int y_index = 0;
5566 while (x_value > 0) {
5567 x_elms[x_index++] = x_value % 10;
5568 x_value /= 10;
5569 }
5570 while (y_value > 0) {
5571 y_elms[y_index++] = y_value % 10;
5572 y_value /= 10;
5573 }
5574
5575 // Loop through the arrays of decimal digits finding the first place
5576 // where they differ.
5577 while (--x_index >= 0 && --y_index >= 0) {
5578 int diff = x_elms[x_index] - y_elms[y_index];
5579 if (diff != 0) return Smi::FromInt(diff);
5580 }
5581
5582 // If one array is a suffix of the other array, the longest array is
5583 // the representation of the largest of the Smis in the
5584 // lexicographic ordering.
5585 return Smi::FromInt(x_index - y_index);
5586}
5587
5588
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005589static Object* StringInputBufferCompare(String* x, String* y) {
5590 static StringInputBuffer bufx;
5591 static StringInputBuffer bufy;
5592 bufx.Reset(x);
5593 bufy.Reset(y);
5594 while (bufx.has_more() && bufy.has_more()) {
5595 int d = bufx.GetNext() - bufy.GetNext();
5596 if (d < 0) return Smi::FromInt(LESS);
5597 else if (d > 0) return Smi::FromInt(GREATER);
5598 }
5599
5600 // x is (non-trivial) prefix of y:
5601 if (bufy.has_more()) return Smi::FromInt(LESS);
5602 // y is prefix of x:
5603 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5604}
5605
5606
5607static Object* FlatStringCompare(String* x, String* y) {
5608 ASSERT(x->IsFlat());
5609 ASSERT(y->IsFlat());
5610 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5611 int prefix_length = x->length();
5612 if (y->length() < prefix_length) {
5613 prefix_length = y->length();
5614 equal_prefix_result = Smi::FromInt(GREATER);
5615 } else if (y->length() > prefix_length) {
5616 equal_prefix_result = Smi::FromInt(LESS);
5617 }
5618 int r;
5619 if (x->IsAsciiRepresentation()) {
5620 Vector<const char> x_chars = x->ToAsciiVector();
5621 if (y->IsAsciiRepresentation()) {
5622 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005623 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005624 } else {
5625 Vector<const uc16> y_chars = y->ToUC16Vector();
5626 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5627 }
5628 } else {
5629 Vector<const uc16> x_chars = x->ToUC16Vector();
5630 if (y->IsAsciiRepresentation()) {
5631 Vector<const char> y_chars = y->ToAsciiVector();
5632 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5633 } else {
5634 Vector<const uc16> y_chars = y->ToUC16Vector();
5635 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5636 }
5637 }
5638 Object* result;
5639 if (r == 0) {
5640 result = equal_prefix_result;
5641 } else {
5642 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5643 }
5644 ASSERT(result == StringInputBufferCompare(x, y));
5645 return result;
5646}
5647
5648
lrn@chromium.org303ada72010-10-27 09:33:13 +00005649static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005650 NoHandleAllocation ha;
5651 ASSERT(args.length() == 2);
5652
5653 CONVERT_CHECKED(String, x, args[0]);
5654 CONVERT_CHECKED(String, y, args[1]);
5655
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005656 Counters::string_compare_runtime.Increment();
5657
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005658 // A few fast case tests before we flatten.
5659 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005660 if (y->length() == 0) {
5661 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005662 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005663 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664 return Smi::FromInt(LESS);
5665 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005666
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005667 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005668 if (d < 0) return Smi::FromInt(LESS);
5669 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005670
lrn@chromium.org303ada72010-10-27 09:33:13 +00005671 Object* obj;
5672 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
5673 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5674 }
5675 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
5676 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5677 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005678
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005679 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5680 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005681}
5682
5683
lrn@chromium.org303ada72010-10-27 09:33:13 +00005684static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005685 NoHandleAllocation ha;
5686 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005687 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005688
5689 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005690 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005691}
5692
5693
lrn@chromium.org303ada72010-10-27 09:33:13 +00005694static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005695 NoHandleAllocation ha;
5696 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005697 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005698
5699 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005700 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005701}
5702
5703
lrn@chromium.org303ada72010-10-27 09:33:13 +00005704static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005705 NoHandleAllocation ha;
5706 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005707 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005708
5709 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005710 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005711}
5712
5713
lrn@chromium.org303ada72010-10-27 09:33:13 +00005714static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005715 NoHandleAllocation ha;
5716 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005717 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005718
5719 CONVERT_DOUBLE_CHECKED(x, args[0]);
5720 CONVERT_DOUBLE_CHECKED(y, args[1]);
5721 double result;
5722 if (isinf(x) && isinf(y)) {
5723 // Make sure that the result in case of two infinite arguments
5724 // is a multiple of Pi / 4. The sign of the result is determined
5725 // by the first argument (x) and the sign of the second argument
5726 // determines the multiplier: one or three.
5727 static double kPiDividedBy4 = 0.78539816339744830962;
5728 int multiplier = (x < 0) ? -1 : 1;
5729 if (y < 0) multiplier *= 3;
5730 result = multiplier * kPiDividedBy4;
5731 } else {
5732 result = atan2(x, y);
5733 }
5734 return Heap::AllocateHeapNumber(result);
5735}
5736
5737
lrn@chromium.org303ada72010-10-27 09:33:13 +00005738static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005739 NoHandleAllocation ha;
5740 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005741 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005742
5743 CONVERT_DOUBLE_CHECKED(x, args[0]);
5744 return Heap::NumberFromDouble(ceiling(x));
5745}
5746
5747
lrn@chromium.org303ada72010-10-27 09:33:13 +00005748static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005749 NoHandleAllocation ha;
5750 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005751 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005752
5753 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005754 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005755}
5756
5757
lrn@chromium.org303ada72010-10-27 09:33:13 +00005758static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005759 NoHandleAllocation ha;
5760 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005761 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005762
5763 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005764 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005765}
5766
5767
lrn@chromium.org303ada72010-10-27 09:33:13 +00005768static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005769 NoHandleAllocation ha;
5770 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005771 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005772
5773 CONVERT_DOUBLE_CHECKED(x, args[0]);
5774 return Heap::NumberFromDouble(floor(x));
5775}
5776
5777
lrn@chromium.org303ada72010-10-27 09:33:13 +00005778static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005779 NoHandleAllocation ha;
5780 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005781 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005782
5783 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005784 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005785}
5786
5787
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005788// Helper function to compute x^y, where y is known to be an
5789// integer. Uses binary decomposition to limit the number of
5790// multiplications; see the discussion in "Hacker's Delight" by Henry
5791// S. Warren, Jr., figure 11-6, page 213.
5792static double powi(double x, int y) {
5793 ASSERT(y != kMinInt);
5794 unsigned n = (y < 0) ? -y : y;
5795 double m = x;
5796 double p = 1;
5797 while (true) {
5798 if ((n & 1) != 0) p *= m;
5799 n >>= 1;
5800 if (n == 0) {
5801 if (y < 0) {
5802 // Unfortunately, we have to be careful when p has reached
5803 // infinity in the computation, because sometimes the higher
5804 // internal precision in the pow() implementation would have
5805 // given us a finite p. This happens very rarely.
5806 double result = 1.0 / p;
5807 return (result == 0 && isinf(p))
5808 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
5809 : result;
5810 } else {
5811 return p;
5812 }
5813 }
5814 m *= m;
5815 }
5816}
5817
5818
lrn@chromium.org303ada72010-10-27 09:33:13 +00005819static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005820 NoHandleAllocation ha;
5821 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005822 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005823
5824 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005825
5826 // If the second argument is a smi, it is much faster to call the
5827 // custom powi() function than the generic pow().
5828 if (args[1]->IsSmi()) {
5829 int y = Smi::cast(args[1])->value();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005830 return Heap::NumberFromDouble(powi(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005831 }
5832
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005833 CONVERT_DOUBLE_CHECKED(y, args[1]);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005834
5835 if (!isinf(x)) {
5836 if (y == 0.5) {
5837 // It's not uncommon to use Math.pow(x, 0.5) to compute the
5838 // square root of a number. To speed up such computations, we
5839 // explictly check for this case and use the sqrt() function
5840 // which is faster than pow().
5841 return Heap::AllocateHeapNumber(sqrt(x));
5842 } else if (y == -0.5) {
5843 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
5844 return Heap::AllocateHeapNumber(1.0 / sqrt(x));
5845 }
5846 }
5847
5848 if (y == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005849 return Smi::FromInt(1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005850 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5851 return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005852 } else {
5853 return Heap::AllocateHeapNumber(pow(x, y));
5854 }
5855}
5856
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005857// Fast version of Math.pow if we know that y is not an integer and
5858// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005859static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005860 NoHandleAllocation ha;
5861 ASSERT(args.length() == 2);
5862 CONVERT_DOUBLE_CHECKED(x, args[0]);
5863 CONVERT_DOUBLE_CHECKED(y, args[1]);
5864 if (y == 0) {
5865 return Smi::FromInt(1);
5866 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5867 return Heap::nan_value();
5868 } else {
5869 return Heap::AllocateHeapNumber(pow(x, y));
5870 }
5871}
5872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005873
lrn@chromium.org303ada72010-10-27 09:33:13 +00005874static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005875 NoHandleAllocation ha;
5876 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005877 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005878
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005879 if (!args[0]->IsHeapNumber()) {
5880 // Must be smi. Return the argument unchanged for all the other types
5881 // to make fuzz-natives test happy.
5882 return args[0];
5883 }
5884
5885 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
5886
5887 double value = number->value();
5888 int exponent = number->get_exponent();
5889 int sign = number->get_sign();
5890
5891 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
5892 // should be rounded to 2^30, which is not smi.
5893 if (!sign && exponent <= kSmiValueSize - 3) {
5894 return Smi::FromInt(static_cast<int>(value + 0.5));
5895 }
5896
5897 // If the magnitude is big enough, there's no place for fraction part. If we
5898 // try to add 0.5 to this number, 1.0 will be added instead.
5899 if (exponent >= 52) {
5900 return number;
5901 }
5902
5903 if (sign && value >= -0.5) return Heap::minus_zero_value();
5904
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005905 // Do not call NumberFromDouble() to avoid extra checks.
5906 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005907}
5908
5909
lrn@chromium.org303ada72010-10-27 09:33:13 +00005910static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911 NoHandleAllocation ha;
5912 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005913 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914
5915 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005916 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005917}
5918
5919
lrn@chromium.org303ada72010-10-27 09:33:13 +00005920static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921 NoHandleAllocation ha;
5922 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005923 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924
5925 CONVERT_DOUBLE_CHECKED(x, args[0]);
5926 return Heap::AllocateHeapNumber(sqrt(x));
5927}
5928
5929
lrn@chromium.org303ada72010-10-27 09:33:13 +00005930static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931 NoHandleAllocation ha;
5932 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005933 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005934
5935 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005936 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005937}
5938
5939
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005940static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005941 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
5942 181, 212, 243, 273, 304, 334};
5943 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
5944 182, 213, 244, 274, 305, 335};
5945
5946 year += month / 12;
5947 month %= 12;
5948 if (month < 0) {
5949 year--;
5950 month += 12;
5951 }
5952
5953 ASSERT(month >= 0);
5954 ASSERT(month < 12);
5955
5956 // year_delta is an arbitrary number such that:
5957 // a) year_delta = -1 (mod 400)
5958 // b) year + year_delta > 0 for years in the range defined by
5959 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
5960 // Jan 1 1970. This is required so that we don't run into integer
5961 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005962 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005963 // operations.
5964 static const int year_delta = 399999;
5965 static const int base_day = 365 * (1970 + year_delta) +
5966 (1970 + year_delta) / 4 -
5967 (1970 + year_delta) / 100 +
5968 (1970 + year_delta) / 400;
5969
5970 int year1 = year + year_delta;
5971 int day_from_year = 365 * year1 +
5972 year1 / 4 -
5973 year1 / 100 +
5974 year1 / 400 -
5975 base_day;
5976
5977 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005978 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005979 }
5980
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005981 return day_from_year + day_from_month_leap[month] + day - 1;
5982}
5983
5984
lrn@chromium.org303ada72010-10-27 09:33:13 +00005985static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005986 NoHandleAllocation ha;
5987 ASSERT(args.length() == 3);
5988
5989 CONVERT_SMI_CHECKED(year, args[0]);
5990 CONVERT_SMI_CHECKED(month, args[1]);
5991 CONVERT_SMI_CHECKED(date, args[2]);
5992
5993 return Smi::FromInt(MakeDay(year, month, date));
5994}
5995
5996
5997static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
5998static const int kDaysIn4Years = 4 * 365 + 1;
5999static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6000static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6001static const int kDays1970to2000 = 30 * 365 + 7;
6002static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6003 kDays1970to2000;
6004static const int kYearsOffset = 400000;
6005
6006static const char kDayInYear[] = {
6007 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6008 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6009 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6010 22, 23, 24, 25, 26, 27, 28,
6011 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6012 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6013 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6014 22, 23, 24, 25, 26, 27, 28, 29, 30,
6015 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6016 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6017 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6018 22, 23, 24, 25, 26, 27, 28, 29, 30,
6019 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6020 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6021 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6022 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6023 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6024 22, 23, 24, 25, 26, 27, 28, 29, 30,
6025 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6026 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6027 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6028 22, 23, 24, 25, 26, 27, 28, 29, 30,
6029 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6030 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6031
6032 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6033 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6034 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6035 22, 23, 24, 25, 26, 27, 28,
6036 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6037 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6038 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6039 22, 23, 24, 25, 26, 27, 28, 29, 30,
6040 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6041 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6042 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6043 22, 23, 24, 25, 26, 27, 28, 29, 30,
6044 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6045 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6046 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6047 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6048 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6049 22, 23, 24, 25, 26, 27, 28, 29, 30,
6050 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6051 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6052 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6053 22, 23, 24, 25, 26, 27, 28, 29, 30,
6054 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6055 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6056
6057 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6058 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6059 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6060 22, 23, 24, 25, 26, 27, 28, 29,
6061 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6062 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6063 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6064 22, 23, 24, 25, 26, 27, 28, 29, 30,
6065 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6066 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6067 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6068 22, 23, 24, 25, 26, 27, 28, 29, 30,
6069 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6070 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6071 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6072 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6073 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6074 22, 23, 24, 25, 26, 27, 28, 29, 30,
6075 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6076 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6077 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6078 22, 23, 24, 25, 26, 27, 28, 29, 30,
6079 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6080 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6081
6082 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6083 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6084 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6085 22, 23, 24, 25, 26, 27, 28,
6086 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6087 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6088 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6089 22, 23, 24, 25, 26, 27, 28, 29, 30,
6090 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6091 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6092 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6093 22, 23, 24, 25, 26, 27, 28, 29, 30,
6094 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6095 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6096 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6097 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6098 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6099 22, 23, 24, 25, 26, 27, 28, 29, 30,
6100 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6101 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6102 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6103 22, 23, 24, 25, 26, 27, 28, 29, 30,
6104 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6105 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6106
6107static const char kMonthInYear[] = {
6108 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,
6109 0, 0, 0, 0, 0, 0,
6110 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,
6111 1, 1, 1,
6112 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,
6113 2, 2, 2, 2, 2, 2,
6114 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,
6115 3, 3, 3, 3, 3,
6116 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,
6117 4, 4, 4, 4, 4, 4,
6118 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,
6119 5, 5, 5, 5, 5,
6120 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,
6121 6, 6, 6, 6, 6, 6,
6122 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,
6123 7, 7, 7, 7, 7, 7,
6124 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,
6125 8, 8, 8, 8, 8,
6126 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,
6127 9, 9, 9, 9, 9, 9,
6128 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6129 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6130 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6131 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6132
6133 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,
6134 0, 0, 0, 0, 0, 0,
6135 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,
6136 1, 1, 1,
6137 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,
6138 2, 2, 2, 2, 2, 2,
6139 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,
6140 3, 3, 3, 3, 3,
6141 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,
6142 4, 4, 4, 4, 4, 4,
6143 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,
6144 5, 5, 5, 5, 5,
6145 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,
6146 6, 6, 6, 6, 6, 6,
6147 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,
6148 7, 7, 7, 7, 7, 7,
6149 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,
6150 8, 8, 8, 8, 8,
6151 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,
6152 9, 9, 9, 9, 9, 9,
6153 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6154 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6155 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6156 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6157
6158 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,
6159 0, 0, 0, 0, 0, 0,
6160 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,
6161 1, 1, 1, 1,
6162 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,
6163 2, 2, 2, 2, 2, 2,
6164 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,
6165 3, 3, 3, 3, 3,
6166 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,
6167 4, 4, 4, 4, 4, 4,
6168 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,
6169 5, 5, 5, 5, 5,
6170 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,
6171 6, 6, 6, 6, 6, 6,
6172 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,
6173 7, 7, 7, 7, 7, 7,
6174 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,
6175 8, 8, 8, 8, 8,
6176 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,
6177 9, 9, 9, 9, 9, 9,
6178 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6179 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6180 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6181 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6182
6183 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,
6184 0, 0, 0, 0, 0, 0,
6185 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,
6186 1, 1, 1,
6187 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,
6188 2, 2, 2, 2, 2, 2,
6189 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,
6190 3, 3, 3, 3, 3,
6191 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,
6192 4, 4, 4, 4, 4, 4,
6193 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,
6194 5, 5, 5, 5, 5,
6195 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,
6196 6, 6, 6, 6, 6, 6,
6197 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,
6198 7, 7, 7, 7, 7, 7,
6199 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,
6200 8, 8, 8, 8, 8,
6201 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,
6202 9, 9, 9, 9, 9, 9,
6203 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6204 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6205 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6206 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6207
6208
6209// This function works for dates from 1970 to 2099.
6210static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006211 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006212#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006213 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006214#endif
6215
6216 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6217 date %= kDaysIn4Years;
6218
6219 month = kMonthInYear[date];
6220 day = kDayInYear[date];
6221
6222 ASSERT(MakeDay(year, month, day) == save_date);
6223}
6224
6225
6226static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006227 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006228#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006229 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006230#endif
6231
6232 date += kDaysOffset;
6233 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6234 date %= kDaysIn400Years;
6235
6236 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6237
6238 date--;
6239 int yd1 = date / kDaysIn100Years;
6240 date %= kDaysIn100Years;
6241 year += 100 * yd1;
6242
6243 date++;
6244 int yd2 = date / kDaysIn4Years;
6245 date %= kDaysIn4Years;
6246 year += 4 * yd2;
6247
6248 date--;
6249 int yd3 = date / 365;
6250 date %= 365;
6251 year += yd3;
6252
6253 bool is_leap = (!yd1 || yd2) && !yd3;
6254
6255 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006256 ASSERT(is_leap || (date >= 0));
6257 ASSERT((date < 365) || (is_leap && (date < 366)));
6258 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6259 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6260 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006261
6262 if (is_leap) {
6263 day = kDayInYear[2*365 + 1 + date];
6264 month = kMonthInYear[2*365 + 1 + date];
6265 } else {
6266 day = kDayInYear[date];
6267 month = kMonthInYear[date];
6268 }
6269
6270 ASSERT(MakeDay(year, month, day) == save_date);
6271}
6272
6273
6274static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006275 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006276 if (date >= 0 && date < 32 * kDaysIn4Years) {
6277 DateYMDFromTimeAfter1970(date, year, month, day);
6278 } else {
6279 DateYMDFromTimeSlow(date, year, month, day);
6280 }
6281}
6282
6283
lrn@chromium.org303ada72010-10-27 09:33:13 +00006284static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006285 NoHandleAllocation ha;
6286 ASSERT(args.length() == 2);
6287
6288 CONVERT_DOUBLE_CHECKED(t, args[0]);
6289 CONVERT_CHECKED(JSArray, res_array, args[1]);
6290
6291 int year, month, day;
6292 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6293
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006294 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6295 FixedArray* elms = FixedArray::cast(res_array->elements());
6296 RUNTIME_ASSERT(elms->length() == 3);
6297
6298 elms->set(0, Smi::FromInt(year));
6299 elms->set(1, Smi::FromInt(month));
6300 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006301
6302 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006303}
6304
6305
lrn@chromium.org303ada72010-10-27 09:33:13 +00006306static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006307 NoHandleAllocation ha;
6308 ASSERT(args.length() == 3);
6309
6310 JSFunction* callee = JSFunction::cast(args[0]);
6311 Object** parameters = reinterpret_cast<Object**>(args[1]);
6312 const int length = Smi::cast(args[2])->value();
6313
lrn@chromium.org303ada72010-10-27 09:33:13 +00006314 Object* result;
6315 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6316 if (!maybe_result->ToObject(&result)) return maybe_result;
6317 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006318 // Allocate the elements if needed.
6319 if (length > 0) {
6320 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006321 Object* obj;
6322 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6323 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6324 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006325
6326 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006327 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6328 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006329 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006330
6331 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006332 for (int i = 0; i < length; i++) {
6333 array->set(i, *--parameters, mode);
6334 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006335 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006336 }
6337 return result;
6338}
6339
6340
lrn@chromium.org303ada72010-10-27 09:33:13 +00006341static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006342 HandleScope scope;
6343 ASSERT(args.length() == 2);
ager@chromium.org3811b432009-10-28 14:53:37 +00006344 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006345 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006346
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00006347 PretenureFlag pretenure = (context->global_context() == *context)
6348 ? TENURED // Allocate global closures in old space.
6349 : NOT_TENURED; // Allocate local closures in new space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006350 Handle<JSFunction> result =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006351 Factory::NewFunctionFromSharedFunctionInfo(shared, context, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006352 return *result;
6353}
6354
lrn@chromium.org303ada72010-10-27 09:33:13 +00006355static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006356 HandleScope scope;
6357 ASSERT(args.length() == 2);
6358 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6359 CONVERT_ARG_CHECKED(JSArray, params, 1);
6360
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006361 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006362 FixedArray* fixed = FixedArray::cast(params->elements());
6363
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006364 int fixed_length = Smi::cast(params->length())->value();
6365 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6366 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006367 Handle<Object> val = Handle<Object>(fixed->get(i));
6368 param_data[i] = val.location();
6369 }
6370
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006371 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006372 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006373 function, fixed_length, *param_data, &exception);
6374 if (exception) {
6375 return Failure::Exception();
6376 }
6377 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006378 return *result;
6379}
6380
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006381
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006382static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006383 Handle<Object> prototype = Factory::null_value();
6384 if (function->has_instance_prototype()) {
6385 prototype = Handle<Object>(function->instance_prototype());
6386 }
6387 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006388 ConstructStubCompiler compiler;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006389 MaybeObject* code = compiler.CompileConstructStub(function->shared());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006390 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006391 function->shared()->set_construct_stub(
6392 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006393 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006394 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006395}
6396
6397
lrn@chromium.org303ada72010-10-27 09:33:13 +00006398static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006399 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006400 ASSERT(args.length() == 1);
6401
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006402 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006403
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006404 // If the constructor isn't a proper function we throw a type error.
6405 if (!constructor->IsJSFunction()) {
6406 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6407 Handle<Object> type_error =
6408 Factory::NewTypeError("not_constructor", arguments);
6409 return Top::Throw(*type_error);
6410 }
6411
6412 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006413
6414 // If function should not have prototype, construction is not allowed. In this
6415 // case generated code bailouts here, since function has no initial_map.
6416 if (!function->should_have_prototype()) {
6417 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6418 Handle<Object> type_error =
6419 Factory::NewTypeError("not_constructor", arguments);
6420 return Top::Throw(*type_error);
6421 }
6422
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006423#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006424 // Handle stepping into constructors if step into is active.
6425 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006426 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006427 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006428#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006429
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006430 if (function->has_initial_map()) {
6431 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006432 // The 'Function' function ignores the receiver object when
6433 // called using 'new' and creates a new JSFunction object that
6434 // is returned. The receiver object is only used for error
6435 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006436 // JSFunction. Factory::NewJSObject() should not be used to
6437 // allocate JSFunctions since it does not properly initialize
6438 // the shared part of the function. Since the receiver is
6439 // ignored anyway, we use the global object as the receiver
6440 // instead of a new JSFunction object. This way, errors are
6441 // reported the same way whether or not 'Function' is called
6442 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006443 return Top::context()->global();
6444 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006445 }
6446
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006447 // The function should be compiled for the optimization hints to be available.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006448 Handle<SharedFunctionInfo> shared(function->shared());
6449 EnsureCompiled(shared, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006450
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006451 if (!function->has_initial_map() &&
6452 shared->IsInobjectSlackTrackingInProgress()) {
6453 // The tracking is already in progress for another function. We can only
6454 // track one initial_map at a time, so we force the completion before the
6455 // function is called as a constructor for the first time.
6456 shared->CompleteInobjectSlackTracking();
6457 TrySettingInlineConstructStub(function);
6458 }
6459
6460 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006461 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006462 // Delay setting the stub if inobject slack tracking is in progress.
6463 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6464 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006465 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006466
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006467 Counters::constructed_objects.Increment();
6468 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006469
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006470 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006471}
6472
6473
lrn@chromium.org303ada72010-10-27 09:33:13 +00006474static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006475 HandleScope scope;
6476 ASSERT(args.length() == 1);
6477
6478 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6479 function->shared()->CompleteInobjectSlackTracking();
6480 TrySettingInlineConstructStub(function);
6481
6482 return Heap::undefined_value();
6483}
6484
6485
lrn@chromium.org303ada72010-10-27 09:33:13 +00006486static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006487 HandleScope scope;
6488 ASSERT(args.length() == 1);
6489
6490 Handle<JSFunction> function = args.at<JSFunction>(0);
6491#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006492 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006493 PrintF("[lazy: ");
6494 function->shared()->name()->Print();
6495 PrintF("]\n");
6496 }
6497#endif
6498
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006499 // Compile the target function. Here we compile using CompileLazyInLoop in
6500 // order to get the optimized version. This helps code like delta-blue
6501 // that calls performance-critical routines through constructors. A
6502 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6503 // direct call. Since the in-loop tracking takes place through CallICs
6504 // this means that things called through constructors are never known to
6505 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006506 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006507 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006508 return Failure::Exception();
6509 }
6510
6511 return function->code();
6512}
6513
6514
lrn@chromium.org303ada72010-10-27 09:33:13 +00006515static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006516 HandleScope scope;
6517 ASSERT(args.length() == 1);
6518 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6519 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6520}
6521
6522
lrn@chromium.org303ada72010-10-27 09:33:13 +00006523static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006524 HandleScope scope;
6525 ASSERT(args.length() == 1);
6526 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6527 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6528}
6529
6530
lrn@chromium.org303ada72010-10-27 09:33:13 +00006531static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006532 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006533 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006534
kasper.lund7276f142008-07-30 08:49:36 +00006535 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006536 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006537 Object* result;
6538 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
6539 if (!maybe_result->ToObject(&result)) return maybe_result;
6540 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006541
6542 Top::set_context(Context::cast(result));
6543
kasper.lund7276f142008-07-30 08:49:36 +00006544 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006545}
6546
lrn@chromium.org303ada72010-10-27 09:33:13 +00006547
6548MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
6549 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006551 Object* js_object = object;
6552 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006553 MaybeObject* maybe_js_object = js_object->ToObject();
6554 if (!maybe_js_object->ToObject(&js_object)) {
6555 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
6556 return maybe_js_object;
6557 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006558 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006559 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560 Handle<Object> result =
6561 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
6562 return Top::Throw(*result);
6563 }
6564 }
6565
lrn@chromium.org303ada72010-10-27 09:33:13 +00006566 Object* result;
6567 { MaybeObject* maybe_result =
6568 Heap::AllocateWithContext(Top::context(),
6569 JSObject::cast(js_object),
6570 is_catch_context);
6571 if (!maybe_result->ToObject(&result)) return maybe_result;
6572 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006574 Context* context = Context::cast(result);
6575 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006576
kasper.lund7276f142008-07-30 08:49:36 +00006577 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006578}
6579
6580
lrn@chromium.org303ada72010-10-27 09:33:13 +00006581static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006582 NoHandleAllocation ha;
6583 ASSERT(args.length() == 1);
6584 return PushContextHelper(args[0], false);
6585}
6586
6587
lrn@chromium.org303ada72010-10-27 09:33:13 +00006588static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006589 NoHandleAllocation ha;
6590 ASSERT(args.length() == 1);
6591 return PushContextHelper(args[0], true);
6592}
6593
6594
lrn@chromium.org303ada72010-10-27 09:33:13 +00006595static MaybeObject* Runtime_LookupContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596 HandleScope scope;
6597 ASSERT(args.length() == 2);
6598
6599 CONVERT_ARG_CHECKED(Context, context, 0);
6600 CONVERT_ARG_CHECKED(String, name, 1);
6601
6602 int index;
6603 PropertyAttributes attributes;
6604 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006605 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606 context->Lookup(name, flags, &index, &attributes);
6607
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006608 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006609 ASSERT(holder->IsJSObject());
6610 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006611 }
6612
6613 // No intermediate context found. Use global object by default.
6614 return Top::context()->global();
6615}
6616
6617
ager@chromium.orga1645e22009-09-09 19:27:10 +00006618// A mechanism to return a pair of Object pointers in registers (if possible).
6619// How this is achieved is calling convention-dependent.
6620// All currently supported x86 compiles uses calling conventions that are cdecl
6621// variants where a 64-bit value is returned in two 32-bit registers
6622// (edx:eax on ia32, r1:r0 on ARM).
6623// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
6624// In Win64 calling convention, a struct of two pointers is returned in memory,
6625// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006626#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006627struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006628 MaybeObject* x;
6629 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006630};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006631
lrn@chromium.org303ada72010-10-27 09:33:13 +00006632static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006633 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006634 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
6635 // In Win64 they are assigned to a hidden first argument.
6636 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006637}
6638#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006639typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006640static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006642 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006643}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006644#endif
6645
6646
lrn@chromium.org303ada72010-10-27 09:33:13 +00006647static inline MaybeObject* Unhole(MaybeObject* x,
6648 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006649 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
6650 USE(attributes);
6651 return x->IsTheHole() ? Heap::undefined_value() : x;
6652}
6653
6654
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006655static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
6656 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006657 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006658 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006659 JSFunction* context_extension_function =
6660 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006661 // If the holder isn't a context extension object, we just return it
6662 // as the receiver. This allows arguments objects to be used as
6663 // receivers, but only if they are put in the context scope chain
6664 // explicitly via a with-statement.
6665 Object* constructor = holder->map()->constructor();
6666 if (constructor != context_extension_function) return holder;
6667 // Fall back to using the global object as the receiver if the
6668 // property turns out to be a local variable allocated in a context
6669 // extension object - introduced via eval.
6670 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006671}
6672
6673
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006674static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006676 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006678 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00006679 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006680 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006682 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006683
6684 int index;
6685 PropertyAttributes attributes;
6686 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006687 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006688 context->Lookup(name, flags, &index, &attributes);
6689
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006690 // If the index is non-negative, the slot has been found in a local
6691 // variable or a parameter. Read it from the context object or the
6692 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006694 // If the "property" we were looking for is a local variable or an
6695 // argument in a context, the receiver is the global object; see
6696 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
6697 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006698 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006699 ? Context::cast(*holder)->get(index)
6700 : JSObject::cast(*holder)->GetElement(index);
6701 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702 }
6703
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006704 // If the holder is found, we read the property from it.
6705 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006706 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006707 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006708 JSObject* receiver;
6709 if (object->IsGlobalObject()) {
6710 receiver = GlobalObject::cast(object)->global_receiver();
6711 } else if (context->is_exception_holder(*holder)) {
6712 receiver = Top::context()->global()->global_receiver();
6713 } else {
6714 receiver = ComputeReceiverForNonGlobal(object);
6715 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006716 // No need to unhole the value here. This is taken care of by the
6717 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006718 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006719 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006720 }
6721
6722 if (throw_error) {
6723 // The property doesn't exist - throw exception.
6724 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006725 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006726 return MakePair(Top::Throw(*reference_error), NULL);
6727 } else {
6728 // The property doesn't exist - return undefined
6729 return MakePair(Heap::undefined_value(), Heap::undefined_value());
6730 }
6731}
6732
6733
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006734static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 return LoadContextSlotHelper(args, true);
6736}
6737
6738
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006739static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 return LoadContextSlotHelper(args, false);
6741}
6742
6743
lrn@chromium.org303ada72010-10-27 09:33:13 +00006744static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006745 HandleScope scope;
6746 ASSERT(args.length() == 3);
6747
6748 Handle<Object> value(args[0]);
6749 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006750 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006751
6752 int index;
6753 PropertyAttributes attributes;
6754 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006755 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006756 context->Lookup(name, flags, &index, &attributes);
6757
6758 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006759 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760 // Ignore if read_only variable.
6761 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006762 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763 }
6764 } else {
6765 ASSERT((attributes & READ_ONLY) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006766 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
6767 ToObjectUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006768 }
6769 return *value;
6770 }
6771
6772 // Slow case: The property is not in a FixedArray context.
6773 // It is either in an JSObject extension context or it was not found.
6774 Handle<JSObject> context_ext;
6775
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006776 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006777 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006778 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006779 } else {
6780 // The property was not found. It needs to be stored in the global context.
6781 ASSERT(attributes == ABSENT);
6782 attributes = NONE;
6783 context_ext = Handle<JSObject>(Top::context()->global());
6784 }
6785
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006786 // Set the property, but ignore if read_only variable on the context
6787 // extension object itself.
6788 if ((attributes & READ_ONLY) == 0 ||
6789 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006790 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
6791 if (set.is_null()) {
6792 // Failure::Exception is converted to a null handle in the
6793 // handle-based methods such as SetProperty. We therefore need
6794 // to convert null handles back to exceptions.
6795 ASSERT(Top::has_pending_exception());
6796 return Failure::Exception();
6797 }
6798 }
6799 return *value;
6800}
6801
6802
lrn@chromium.org303ada72010-10-27 09:33:13 +00006803static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006804 HandleScope scope;
6805 ASSERT(args.length() == 1);
6806
6807 return Top::Throw(args[0]);
6808}
6809
6810
lrn@chromium.org303ada72010-10-27 09:33:13 +00006811static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006812 HandleScope scope;
6813 ASSERT(args.length() == 1);
6814
6815 return Top::ReThrow(args[0]);
6816}
6817
6818
lrn@chromium.org303ada72010-10-27 09:33:13 +00006819static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006820 ASSERT_EQ(0, args.length());
6821 return Top::PromoteScheduledException();
6822}
6823
6824
lrn@chromium.org303ada72010-10-27 09:33:13 +00006825static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006826 HandleScope scope;
6827 ASSERT(args.length() == 1);
6828
6829 Handle<Object> name(args[0]);
6830 Handle<Object> reference_error =
6831 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
6832 return Top::Throw(*reference_error);
6833}
6834
6835
lrn@chromium.org303ada72010-10-27 09:33:13 +00006836static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006837 NoHandleAllocation na;
6838 return Top::StackOverflow();
6839}
6840
6841
lrn@chromium.org303ada72010-10-27 09:33:13 +00006842static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006843 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006844
6845 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00006846 if (StackGuard::IsStackOverflow()) {
6847 return Runtime_StackOverflow(args);
6848 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006849
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006850 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006851}
6852
6853
6854// NOTE: These PrintXXX functions are defined for all builds (not just
6855// DEBUG builds) because we may want to be able to trace function
6856// calls in all modes.
6857static void PrintString(String* str) {
6858 // not uncommon to have empty strings
6859 if (str->length() > 0) {
6860 SmartPointer<char> s =
6861 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
6862 PrintF("%s", *s);
6863 }
6864}
6865
6866
6867static void PrintObject(Object* obj) {
6868 if (obj->IsSmi()) {
6869 PrintF("%d", Smi::cast(obj)->value());
6870 } else if (obj->IsString() || obj->IsSymbol()) {
6871 PrintString(String::cast(obj));
6872 } else if (obj->IsNumber()) {
6873 PrintF("%g", obj->Number());
6874 } else if (obj->IsFailure()) {
6875 PrintF("<failure>");
6876 } else if (obj->IsUndefined()) {
6877 PrintF("<undefined>");
6878 } else if (obj->IsNull()) {
6879 PrintF("<null>");
6880 } else if (obj->IsTrue()) {
6881 PrintF("<true>");
6882 } else if (obj->IsFalse()) {
6883 PrintF("<false>");
6884 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006885 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006886 }
6887}
6888
6889
6890static int StackSize() {
6891 int n = 0;
6892 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
6893 return n;
6894}
6895
6896
6897static void PrintTransition(Object* result) {
6898 // indentation
6899 { const int nmax = 80;
6900 int n = StackSize();
6901 if (n <= nmax)
6902 PrintF("%4d:%*s", n, n, "");
6903 else
6904 PrintF("%4d:%*s", n, nmax, "...");
6905 }
6906
6907 if (result == NULL) {
6908 // constructor calls
6909 JavaScriptFrameIterator it;
6910 JavaScriptFrame* frame = it.frame();
6911 if (frame->IsConstructor()) PrintF("new ");
6912 // function name
6913 Object* fun = frame->function();
6914 if (fun->IsJSFunction()) {
6915 PrintObject(JSFunction::cast(fun)->shared()->name());
6916 } else {
6917 PrintObject(fun);
6918 }
6919 // function arguments
6920 // (we are intentionally only printing the actually
6921 // supplied parameters, not all parameters required)
6922 PrintF("(this=");
6923 PrintObject(frame->receiver());
6924 const int length = frame->GetProvidedParametersCount();
6925 for (int i = 0; i < length; i++) {
6926 PrintF(", ");
6927 PrintObject(frame->GetParameter(i));
6928 }
6929 PrintF(") {\n");
6930
6931 } else {
6932 // function result
6933 PrintF("} -> ");
6934 PrintObject(result);
6935 PrintF("\n");
6936 }
6937}
6938
6939
lrn@chromium.org303ada72010-10-27 09:33:13 +00006940static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006941 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006942 NoHandleAllocation ha;
6943 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006944 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006945}
6946
6947
lrn@chromium.org303ada72010-10-27 09:33:13 +00006948static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006949 NoHandleAllocation ha;
6950 PrintTransition(args[0]);
6951 return args[0]; // return TOS
6952}
6953
6954
lrn@chromium.org303ada72010-10-27 09:33:13 +00006955static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006956 NoHandleAllocation ha;
6957 ASSERT(args.length() == 1);
6958
6959#ifdef DEBUG
6960 if (args[0]->IsString()) {
6961 // If we have a string, assume it's a code "marker"
6962 // and print some interesting cpu debugging info.
6963 JavaScriptFrameIterator it;
6964 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00006965 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
6966 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006967 } else {
6968 PrintF("DebugPrint: ");
6969 }
6970 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006971 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006972 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006973 HeapObject::cast(args[0])->map()->Print();
6974 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006975#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006976 // ShortPrint is available in release mode. Print is not.
6977 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006978#endif
6979 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00006980 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981
6982 return args[0]; // return TOS
6983}
6984
6985
lrn@chromium.org303ada72010-10-27 09:33:13 +00006986static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006987 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006988 NoHandleAllocation ha;
6989 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006990 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006991}
6992
6993
lrn@chromium.org303ada72010-10-27 09:33:13 +00006994static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006995 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00006996 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006997
6998 // According to ECMA-262, section 15.9.1, page 117, the precision of
6999 // the number in a Date object representing a particular instant in
7000 // time is milliseconds. Therefore, we floor the result of getting
7001 // the OS time.
7002 double millis = floor(OS::TimeCurrentMillis());
7003 return Heap::NumberFromDouble(millis);
7004}
7005
7006
lrn@chromium.org303ada72010-10-27 09:33:13 +00007007static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007008 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007009 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007010
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007011 CONVERT_ARG_CHECKED(String, str, 0);
7012 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007013
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007014 CONVERT_ARG_CHECKED(JSArray, output, 1);
7015 RUNTIME_ASSERT(output->HasFastElements());
7016
7017 AssertNoAllocation no_allocation;
7018
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007019 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007020 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7021 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007022 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007023 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007024 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007025 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007026 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7027 }
7028
7029 if (result) {
7030 return *output;
7031 } else {
7032 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007033 }
7034}
7035
7036
lrn@chromium.org303ada72010-10-27 09:33:13 +00007037static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007038 NoHandleAllocation ha;
7039 ASSERT(args.length() == 1);
7040
7041 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007042 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7044}
7045
7046
lrn@chromium.org303ada72010-10-27 09:33:13 +00007047static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007049 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050
7051 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7052}
7053
7054
lrn@chromium.org303ada72010-10-27 09:33:13 +00007055static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007056 NoHandleAllocation ha;
7057 ASSERT(args.length() == 1);
7058
7059 CONVERT_DOUBLE_CHECKED(x, args[0]);
7060 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7061}
7062
7063
lrn@chromium.org303ada72010-10-27 09:33:13 +00007064static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007065 ASSERT(args.length() == 1);
7066 Object* global = args[0];
7067 if (!global->IsJSGlobalObject()) return Heap::null_value();
7068 return JSGlobalObject::cast(global)->global_receiver();
7069}
7070
7071
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007072static MaybeObject* Runtime_ParseJson(Arguments args) {
7073 HandleScope scope;
7074 ASSERT_EQ(1, args.length());
7075 CONVERT_ARG_CHECKED(String, source, 0);
7076
7077 Handle<Object> result = JsonParser::Parse(source);
7078 if (result.is_null()) {
7079 // Syntax error or stack overflow in scanner.
7080 ASSERT(Top::has_pending_exception());
7081 return Failure::Exception();
7082 }
7083 return *result;
7084}
7085
7086
lrn@chromium.org303ada72010-10-27 09:33:13 +00007087static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007088 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007089 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007090 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007091
ager@chromium.org381abbb2009-02-25 13:23:22 +00007092 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007093 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007094 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7095 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007096 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007097 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007099 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100 return *fun;
7101}
7102
7103
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007104static ObjectPair CompileGlobalEval(Handle<String> source,
7105 Handle<Object> receiver) {
7106 // Deal with a normal eval call with a string argument. Compile it
7107 // and return the compiled function bound in the local context.
7108 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7109 source,
7110 Handle<Context>(Top::context()),
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007111 Top::context()->IsGlobalContext());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007112 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7113 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7114 shared,
7115 Handle<Context>(Top::context()),
7116 NOT_TENURED);
7117 return MakePair(*compiled, *receiver);
7118}
7119
7120
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007121static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7122 ASSERT(args.length() == 3);
7123 if (!args[0]->IsJSFunction()) {
7124 return MakePair(Top::ThrowIllegalOperation(), NULL);
7125 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007126
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007127 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007128 Handle<JSFunction> callee = args.at<JSFunction>(0);
7129 Handle<Object> receiver; // Will be overwritten.
7130
7131 // Compute the calling context.
7132 Handle<Context> context = Handle<Context>(Top::context());
7133#ifdef DEBUG
7134 // Make sure Top::context() agrees with the old code that traversed
7135 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007136 StackFrameLocator locator;
7137 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007138 ASSERT(Context::cast(frame->context()) == *context);
7139#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007140
7141 // Find where the 'eval' symbol is bound. It is unaliased only if
7142 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007143 int index = -1;
7144 PropertyAttributes attributes = ABSENT;
7145 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007146 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7147 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007148 // Stop search when eval is found or when the global context is
7149 // reached.
7150 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007151 if (context->is_function_context()) {
7152 context = Handle<Context>(Context::cast(context->closure()->context()));
7153 } else {
7154 context = Handle<Context>(context->previous());
7155 }
7156 }
7157
iposva@chromium.org245aa852009-02-10 00:49:54 +00007158 // If eval could not be resolved, it has been deleted and we need to
7159 // throw a reference error.
7160 if (attributes == ABSENT) {
7161 Handle<Object> name = Factory::eval_symbol();
7162 Handle<Object> reference_error =
7163 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007164 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007165 }
7166
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007167 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007168 // 'eval' is not bound in the global context. Just call the function
7169 // with the given arguments. This is not necessarily the global eval.
7170 if (receiver->IsContext()) {
7171 context = Handle<Context>::cast(receiver);
7172 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007173 } else if (receiver->IsJSContextExtensionObject()) {
7174 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007175 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007176 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007177 }
7178
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007179 // 'eval' is bound in the global context, but it may have been overwritten.
7180 // Compare it to the builtin 'GlobalEval' function to make sure.
7181 if (*callee != Top::global_context()->global_eval_fun() ||
7182 !args[1]->IsString()) {
7183 return MakePair(*callee, Top::context()->global()->global_receiver());
7184 }
7185
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007186 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7187}
7188
7189
7190static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7191 ASSERT(args.length() == 3);
7192 if (!args[0]->IsJSFunction()) {
7193 return MakePair(Top::ThrowIllegalOperation(), NULL);
7194 }
7195
7196 HandleScope scope;
7197 Handle<JSFunction> callee = args.at<JSFunction>(0);
7198
7199 // 'eval' is bound in the global context, but it may have been overwritten.
7200 // Compare it to the builtin 'GlobalEval' function to make sure.
7201 if (*callee != Top::global_context()->global_eval_fun() ||
7202 !args[1]->IsString()) {
7203 return MakePair(*callee, Top::context()->global()->global_receiver());
7204 }
7205
7206 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007207}
7208
7209
lrn@chromium.org303ada72010-10-27 09:33:13 +00007210static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007211 // This utility adjusts the property attributes for newly created Function
7212 // object ("new Function(...)") by changing the map.
7213 // All it does is changing the prototype property to enumerable
7214 // as specified in ECMA262, 15.3.5.2.
7215 HandleScope scope;
7216 ASSERT(args.length() == 1);
7217 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7218 ASSERT(func->map()->instance_type() ==
7219 Top::function_instance_map()->instance_type());
7220 ASSERT(func->map()->instance_size() ==
7221 Top::function_instance_map()->instance_size());
7222 func->set_map(*Top::function_instance_map());
7223 return *func;
7224}
7225
7226
lrn@chromium.org303ada72010-10-27 09:33:13 +00007227static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007228 // Allocate a block of memory in NewSpace (filled with a filler).
7229 // Use as fallback for allocation in generated code when NewSpace
7230 // is full.
7231 ASSERT(args.length() == 1);
7232 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7233 int size = size_smi->value();
7234 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7235 RUNTIME_ASSERT(size > 0);
7236 static const int kMinFreeNewSpaceAfterGC =
7237 Heap::InitialSemiSpaceSize() * 3/4;
7238 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007239 Object* allocation;
7240 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7241 if (maybe_allocation->ToObject(&allocation)) {
7242 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7243 }
7244 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007245 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007246}
7247
7248
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007249// Push an array unto an array of arrays if it is not already in the
7250// array. Returns true if the element was pushed on the stack and
7251// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007252static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007253 ASSERT(args.length() == 2);
7254 CONVERT_CHECKED(JSArray, array, args[0]);
7255 CONVERT_CHECKED(JSArray, element, args[1]);
7256 RUNTIME_ASSERT(array->HasFastElements());
7257 int length = Smi::cast(array->length())->value();
7258 FixedArray* elements = FixedArray::cast(array->elements());
7259 for (int i = 0; i < length; i++) {
7260 if (elements->get(i) == element) return Heap::false_value();
7261 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007262 Object* obj;
7263 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7264 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7265 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007266 return Heap::true_value();
7267}
7268
7269
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007270/**
7271 * A simple visitor visits every element of Array's.
7272 * The backend storage can be a fixed array for fast elements case,
7273 * or a dictionary for sparse array. Since Dictionary is a subtype
7274 * of FixedArray, the class can be used by both fast and slow cases.
7275 * The second parameter of the constructor, fast_elements, specifies
7276 * whether the storage is a FixedArray or Dictionary.
7277 *
7278 * An index limit is used to deal with the situation that a result array
7279 * length overflows 32-bit non-negative integer.
7280 */
7281class ArrayConcatVisitor {
7282 public:
7283 ArrayConcatVisitor(Handle<FixedArray> storage,
7284 uint32_t index_limit,
7285 bool fast_elements) :
7286 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007287 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007288
7289 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007290 if (i >= index_limit_ - index_offset_) return;
7291 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007292
7293 if (fast_elements_) {
7294 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7295 storage_->set(index, *elm);
7296
7297 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007298 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7299 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007300 Factory::DictionaryAtNumberPut(dict, index, elm);
7301 if (!result.is_identical_to(dict))
7302 storage_ = result;
7303 }
7304 }
7305
7306 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007307 if (index_limit_ - index_offset_ < delta) {
7308 index_offset_ = index_limit_;
7309 } else {
7310 index_offset_ += delta;
7311 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007312 }
7313
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007314 Handle<FixedArray> storage() { return storage_; }
7315
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007316 private:
7317 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007318 // Limit on the accepted indices. Elements with indices larger than the
7319 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007320 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007321 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007322 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007323 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007324};
7325
7326
ager@chromium.org3811b432009-10-28 14:53:37 +00007327template<class ExternalArrayClass, class ElementType>
7328static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7329 bool elements_are_ints,
7330 bool elements_are_guaranteed_smis,
7331 uint32_t range,
7332 ArrayConcatVisitor* visitor) {
7333 Handle<ExternalArrayClass> array(
7334 ExternalArrayClass::cast(receiver->elements()));
7335 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7336
7337 if (visitor != NULL) {
7338 if (elements_are_ints) {
7339 if (elements_are_guaranteed_smis) {
7340 for (uint32_t j = 0; j < len; j++) {
7341 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7342 visitor->visit(j, e);
7343 }
7344 } else {
7345 for (uint32_t j = 0; j < len; j++) {
7346 int64_t val = static_cast<int64_t>(array->get(j));
7347 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7348 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7349 visitor->visit(j, e);
7350 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007351 Handle<Object> e =
7352 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007353 visitor->visit(j, e);
7354 }
7355 }
7356 }
7357 } else {
7358 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007359 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007360 visitor->visit(j, e);
7361 }
7362 }
7363 }
7364
7365 return len;
7366}
7367
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007368/**
7369 * A helper function that visits elements of a JSObject. Only elements
7370 * whose index between 0 and range (exclusive) are visited.
7371 *
7372 * If the third parameter, visitor, is not NULL, the visitor is called
7373 * with parameters, 'visitor_index_offset + element index' and the element.
7374 *
7375 * It returns the number of visisted elements.
7376 */
7377static uint32_t IterateElements(Handle<JSObject> receiver,
7378 uint32_t range,
7379 ArrayConcatVisitor* visitor) {
7380 uint32_t num_of_elements = 0;
7381
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007382 switch (receiver->GetElementsKind()) {
7383 case JSObject::FAST_ELEMENTS: {
7384 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7385 uint32_t len = elements->length();
7386 if (range < len) {
7387 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007388 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007389
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007390 for (uint32_t j = 0; j < len; j++) {
7391 Handle<Object> e(elements->get(j));
7392 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007393 num_of_elements++;
7394 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007395 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007396 }
7397 }
7398 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007399 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007400 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007401 case JSObject::PIXEL_ELEMENTS: {
7402 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7403 uint32_t len = pixels->length();
7404 if (range < len) {
7405 len = range;
7406 }
7407
7408 for (uint32_t j = 0; j < len; j++) {
7409 num_of_elements++;
7410 if (visitor != NULL) {
7411 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7412 visitor->visit(j, e);
7413 }
7414 }
7415 break;
7416 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007417 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7418 num_of_elements =
7419 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7420 receiver, true, true, range, visitor);
7421 break;
7422 }
7423 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7424 num_of_elements =
7425 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7426 receiver, true, true, range, visitor);
7427 break;
7428 }
7429 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7430 num_of_elements =
7431 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7432 receiver, true, true, range, visitor);
7433 break;
7434 }
7435 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7436 num_of_elements =
7437 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7438 receiver, true, true, range, visitor);
7439 break;
7440 }
7441 case JSObject::EXTERNAL_INT_ELEMENTS: {
7442 num_of_elements =
7443 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7444 receiver, true, false, range, visitor);
7445 break;
7446 }
7447 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7448 num_of_elements =
7449 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7450 receiver, true, false, range, visitor);
7451 break;
7452 }
7453 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7454 num_of_elements =
7455 IterateExternalArrayElements<ExternalFloatArray, float>(
7456 receiver, false, false, range, visitor);
7457 break;
7458 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007459 case JSObject::DICTIONARY_ELEMENTS: {
7460 Handle<NumberDictionary> dict(receiver->element_dictionary());
7461 uint32_t capacity = dict->Capacity();
7462 for (uint32_t j = 0; j < capacity; j++) {
7463 Handle<Object> k(dict->KeyAt(j));
7464 if (dict->IsKey(*k)) {
7465 ASSERT(k->IsNumber());
7466 uint32_t index = static_cast<uint32_t>(k->Number());
7467 if (index < range) {
7468 num_of_elements++;
7469 if (visitor) {
7470 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7471 }
7472 }
7473 }
7474 }
7475 break;
7476 }
7477 default:
7478 UNREACHABLE();
7479 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007480 }
7481
7482 return num_of_elements;
7483}
7484
7485
7486/**
7487 * A helper function that visits elements of an Array object, and elements
7488 * on its prototypes.
7489 *
7490 * Elements on prototypes are visited first, and only elements whose indices
7491 * less than Array length are visited.
7492 *
7493 * If a ArrayConcatVisitor object is given, the visitor is called with
7494 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007495 *
7496 * The returned number of elements is an upper bound on the actual number
7497 * of elements added. If the same element occurs in more than one object
7498 * in the array's prototype chain, it will be counted more than once, but
7499 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007500 */
7501static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7502 ArrayConcatVisitor* visitor) {
7503 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7504 Handle<Object> obj = array;
7505
7506 static const int kEstimatedPrototypes = 3;
7507 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7508
7509 // Visit prototype first. If an element on the prototype is shadowed by
7510 // the inheritor using the same index, the ArrayConcatVisitor visits
7511 // the prototype element before the shadowing element.
7512 // The visitor can simply overwrite the old value by new value using
7513 // the same index. This follows Array::concat semantics.
7514 while (!obj->IsNull()) {
7515 objects.Add(Handle<JSObject>::cast(obj));
7516 obj = Handle<Object>(obj->GetPrototype());
7517 }
7518
7519 uint32_t nof_elements = 0;
7520 for (int i = objects.length() - 1; i >= 0; i--) {
7521 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007522 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007523 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007524
7525 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7526 nof_elements = JSObject::kMaxElementCount;
7527 } else {
7528 nof_elements += encountered_elements;
7529 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007530 }
7531
7532 return nof_elements;
7533}
7534
7535
7536/**
7537 * A helper function of Runtime_ArrayConcat.
7538 *
7539 * The first argument is an Array of arrays and objects. It is the
7540 * same as the arguments array of Array::concat JS function.
7541 *
7542 * If an argument is an Array object, the function visits array
7543 * elements. If an argument is not an Array object, the function
7544 * visits the object as if it is an one-element array.
7545 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007546 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007547 * non-negative number is used as new length. For example, if one
7548 * array length is 2^32 - 1, second array length is 1, the
7549 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007550 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
7551 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007552 */
7553static uint32_t IterateArguments(Handle<JSArray> arguments,
7554 ArrayConcatVisitor* visitor) {
7555 uint32_t visited_elements = 0;
7556 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7557
7558 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007559 Object *element;
7560 MaybeObject* maybe_element = arguments->GetElement(i);
7561 // This if() is not expected to fail, but we have the check in the
7562 // interest of hardening the runtime calls.
7563 if (maybe_element->ToObject(&element)) {
7564 Handle<Object> obj(element);
7565 if (obj->IsJSArray()) {
7566 Handle<JSArray> array = Handle<JSArray>::cast(obj);
7567 uint32_t len = static_cast<uint32_t>(array->length()->Number());
7568 uint32_t nof_elements =
7569 IterateArrayAndPrototypeElements(array, visitor);
7570 // Total elements of array and its prototype chain can be more than
7571 // the array length, but ArrayConcat can only concatenate at most
7572 // the array length number of elements. We use the length as an estimate
7573 // for the actual number of elements added.
7574 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
7575 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
7576 visited_elements = JSArray::kMaxElementCount;
7577 } else {
7578 visited_elements += added_elements;
7579 }
7580 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007581 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007582 if (visitor) {
7583 visitor->visit(0, obj);
7584 visitor->increase_index_offset(1);
7585 }
7586 if (visited_elements < JSArray::kMaxElementCount) {
7587 visited_elements++;
7588 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007589 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007590 }
7591 }
7592 return visited_elements;
7593}
7594
7595
7596/**
7597 * Array::concat implementation.
7598 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007599 * TODO(lrn): Fix non-compliance for very large concatenations and update to
7600 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007601 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00007602static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007603 ASSERT(args.length() == 1);
7604 HandleScope handle_scope;
7605
7606 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
7607 Handle<JSArray> arguments(arg_arrays);
7608
7609 // Pass 1: estimate the number of elements of the result
7610 // (it could be more than real numbers if prototype has elements).
7611 uint32_t result_length = 0;
7612 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7613
7614 { AssertNoAllocation nogc;
7615 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007616 Object* obj;
7617 MaybeObject* maybe_object = arguments->GetElement(i);
7618 // This if() is not expected to fail, but we have the check in the
7619 // interest of hardening the runtime calls.
7620 if (maybe_object->ToObject(&obj)) {
7621 uint32_t length_estimate;
7622 if (obj->IsJSArray()) {
7623 length_estimate =
7624 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
7625 } else {
7626 length_estimate = 1;
7627 }
7628 if (JSObject::kMaxElementCount - result_length < length_estimate) {
7629 result_length = JSObject::kMaxElementCount;
7630 break;
7631 }
7632 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007633 }
7634 }
7635 }
7636
7637 // Allocate an empty array, will set length and content later.
7638 Handle<JSArray> result = Factory::NewJSArray(0);
7639
7640 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
7641 // If estimated number of elements is more than half of length, a
7642 // fixed array (fast case) is more time and space-efficient than a
7643 // dictionary.
7644 bool fast_case = (estimate_nof_elements * 2) >= result_length;
7645
7646 Handle<FixedArray> storage;
7647 if (fast_case) {
7648 // The backing storage array must have non-existing elements to
7649 // preserve holes across concat operations.
7650 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007651 Handle<Map> fast_map =
7652 Factory::GetFastElementsMap(Handle<Map>(result->map()));
7653 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007654 } else {
7655 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
7656 uint32_t at_least_space_for = estimate_nof_elements +
7657 (estimate_nof_elements >> 2);
7658 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007659 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007660 Handle<Map> slow_map =
7661 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
7662 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007663 }
7664
7665 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
7666
7667 ArrayConcatVisitor visitor(storage, result_length, fast_case);
7668
7669 IterateArguments(arguments, &visitor);
7670
7671 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007672 // Please note the storage might have changed in the visitor.
7673 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007674
7675 return *result;
7676}
7677
7678
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007679// This will not allocate (flatten the string), but it may run
7680// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007681static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007682 NoHandleAllocation ha;
7683 ASSERT(args.length() == 1);
7684
7685 CONVERT_CHECKED(String, string, args[0]);
7686 StringInputBuffer buffer(string);
7687 while (buffer.has_more()) {
7688 uint16_t character = buffer.GetNext();
7689 PrintF("%c", character);
7690 }
7691 return string;
7692}
7693
ager@chromium.org5ec48922009-05-05 07:25:34 +00007694// Moves all own elements of an object, that are below a limit, to positions
7695// starting at zero. All undefined values are placed after non-undefined values,
7696// and are followed by non-existing element. Does not change the length
7697// property.
7698// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007699static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007700 ASSERT(args.length() == 2);
7701 CONVERT_CHECKED(JSObject, object, args[0]);
7702 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
7703 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007704}
7705
7706
7707// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00007708static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007709 ASSERT(args.length() == 2);
7710 CONVERT_CHECKED(JSArray, from, args[0]);
7711 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007712 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007713 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007714 if (new_elements->map() == Heap::fixed_array_map() ||
7715 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007716 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007717 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007718 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007719 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007720 Object* new_map;
7721 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007722 to->set_map(Map::cast(new_map));
7723 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007724 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007725 Object* obj;
7726 { MaybeObject* maybe_obj = from->ResetElements();
7727 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7728 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007729 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007730 return to;
7731}
7732
7733
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007734// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00007735static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007736 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007737 CONVERT_CHECKED(JSObject, object, args[0]);
7738 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007739 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007740 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007741 } else if (object->IsJSArray()) {
7742 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007743 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007744 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007745 }
7746}
7747
7748
lrn@chromium.org303ada72010-10-27 09:33:13 +00007749static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007750 HandleScope handle_scope;
7751
7752 ASSERT_EQ(3, args.length());
7753
ager@chromium.orgac091b72010-05-05 07:34:42 +00007754 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007755 Handle<Object> key1 = args.at<Object>(1);
7756 Handle<Object> key2 = args.at<Object>(2);
7757
7758 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007759 if (!key1->ToArrayIndex(&index1)
7760 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00007761 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007762 }
7763
ager@chromium.orgac091b72010-05-05 07:34:42 +00007764 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
7765 Handle<Object> tmp1 = GetElement(jsobject, index1);
7766 Handle<Object> tmp2 = GetElement(jsobject, index2);
7767
7768 SetElement(jsobject, index1, tmp2);
7769 SetElement(jsobject, index2, tmp1);
7770
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007771 return Heap::undefined_value();
7772}
7773
7774
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007775// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007776// might have elements. Can either return keys (positive integers) or
7777// intervals (pair of a negative integer (-start-1) followed by a
7778// positive (length)) or undefined values.
7779// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007780static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007781 ASSERT(args.length() == 2);
7782 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007783 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007784 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007785 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007786 // Create an array and get all the keys into it, then remove all the
7787 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007788 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007789 int keys_length = keys->length();
7790 for (int i = 0; i < keys_length; i++) {
7791 Object* key = keys->get(i);
7792 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007793 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007794 // Zap invalid keys.
7795 keys->set_undefined(i);
7796 }
7797 }
7798 return *Factory::NewJSArrayWithElements(keys);
7799 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007800 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007801 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
7802 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007803 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007804 uint32_t actual_length =
7805 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00007806 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007807 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00007808 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007809 single_interval->set(1, *length_object);
7810 return *Factory::NewJSArrayWithElements(single_interval);
7811 }
7812}
7813
7814
7815// DefineAccessor takes an optional final argument which is the
7816// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
7817// to the way accessors are implemented, it is set for both the getter
7818// and setter on the first call to DefineAccessor and ignored on
7819// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007820static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007821 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
7822 // Compute attributes.
7823 PropertyAttributes attributes = NONE;
7824 if (args.length() == 5) {
7825 CONVERT_CHECKED(Smi, attrs, args[4]);
7826 int value = attrs->value();
7827 // Only attribute bits should be set.
7828 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
7829 attributes = static_cast<PropertyAttributes>(value);
7830 }
7831
7832 CONVERT_CHECKED(JSObject, obj, args[0]);
7833 CONVERT_CHECKED(String, name, args[1]);
7834 CONVERT_CHECKED(Smi, flag, args[2]);
7835 CONVERT_CHECKED(JSFunction, fun, args[3]);
7836 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
7837}
7838
7839
lrn@chromium.org303ada72010-10-27 09:33:13 +00007840static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007841 ASSERT(args.length() == 3);
7842 CONVERT_CHECKED(JSObject, obj, args[0]);
7843 CONVERT_CHECKED(String, name, args[1]);
7844 CONVERT_CHECKED(Smi, flag, args[2]);
7845 return obj->LookupAccessor(name, flag->value() == 0);
7846}
7847
7848
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007849#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00007850static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007851 ASSERT(args.length() == 0);
7852 return Execution::DebugBreakHelper();
7853}
7854
7855
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007856// Helper functions for wrapping and unwrapping stack frame ids.
7857static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007858 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007859 return Smi::FromInt(id >> 2);
7860}
7861
7862
7863static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
7864 return static_cast<StackFrame::Id>(wrapped->value() << 2);
7865}
7866
7867
7868// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00007869// args[0]: debug event listener function to set or null or undefined for
7870// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007871// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00007872static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007873 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007874 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
7875 args[0]->IsUndefined() ||
7876 args[0]->IsNull());
7877 Handle<Object> callback = args.at<Object>(0);
7878 Handle<Object> data = args.at<Object>(1);
7879 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007880
7881 return Heap::undefined_value();
7882}
7883
7884
lrn@chromium.org303ada72010-10-27 09:33:13 +00007885static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00007886 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007887 StackGuard::DebugBreak();
7888 return Heap::undefined_value();
7889}
7890
7891
lrn@chromium.org303ada72010-10-27 09:33:13 +00007892static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
7893 LookupResult* result,
7894 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007895 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007896 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007897 case NORMAL:
7898 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007899 if (value->IsTheHole()) {
7900 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007901 }
7902 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007903 case FIELD:
7904 value =
7905 JSObject::cast(
7906 result->holder())->FastPropertyAt(result->GetFieldIndex());
7907 if (value->IsTheHole()) {
7908 return Heap::undefined_value();
7909 }
7910 return value;
7911 case CONSTANT_FUNCTION:
7912 return result->GetConstantFunction();
7913 case CALLBACKS: {
7914 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007915 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007916 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007917 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007918 if (!maybe_value->ToObject(&value)) {
7919 ASSERT(maybe_value->IsException());
7920 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007921 Top::clear_pending_exception();
7922 if (caught_exception != NULL) {
7923 *caught_exception = true;
7924 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007925 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007926 }
7927 return value;
7928 } else {
7929 return Heap::undefined_value();
7930 }
7931 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007932 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007933 case MAP_TRANSITION:
7934 case CONSTANT_TRANSITION:
7935 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007936 return Heap::undefined_value();
7937 default:
7938 UNREACHABLE();
7939 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007940 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007941 return Heap::undefined_value();
7942}
7943
7944
ager@chromium.org32912102009-01-16 10:38:43 +00007945// Get debugger related details for an object property.
7946// args[0]: object holding property
7947// args[1]: name of the property
7948//
7949// The array returned contains the following information:
7950// 0: Property value
7951// 1: Property details
7952// 2: Property value is exception
7953// 3: Getter function if defined
7954// 4: Setter function if defined
7955// Items 2-4 are only filled if the property has either a getter or a setter
7956// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007957static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007958 HandleScope scope;
7959
7960 ASSERT(args.length() == 2);
7961
7962 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7963 CONVERT_ARG_CHECKED(String, name, 1);
7964
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007965 // Make sure to set the current context to the context before the debugger was
7966 // entered (if the debugger is entered). The reason for switching context here
7967 // is that for some property lookups (accessors and interceptors) callbacks
7968 // into the embedding application can occour, and the embedding application
7969 // could have the assumption that its own global context is the current
7970 // context and not some internal debugger context.
7971 SaveContext save;
7972 if (Debug::InDebugger()) {
7973 Top::set_context(*Debug::debugger_entry()->GetContext());
7974 }
7975
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007976 // Skip the global proxy as it has no properties and always delegates to the
7977 // real global object.
7978 if (obj->IsJSGlobalProxy()) {
7979 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
7980 }
7981
7982
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007983 // Check if the name is trivially convertible to an index and get the element
7984 // if so.
7985 uint32_t index;
7986 if (name->AsArrayIndex(&index)) {
7987 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007988 Object* element_or_char;
7989 { MaybeObject* maybe_element_or_char =
7990 Runtime::GetElementOrCharAt(obj, index);
7991 if (!maybe_element_or_char->ToObject(&element_or_char)) {
7992 return maybe_element_or_char;
7993 }
7994 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007995 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007996 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
7997 return *Factory::NewJSArrayWithElements(details);
7998 }
7999
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008000 // Find the number of objects making up this.
8001 int length = LocalPrototypeChainLength(*obj);
8002
8003 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008004 Handle<JSObject> jsproto = obj;
8005 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008006 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008007 jsproto->LocalLookup(*name, &result);
8008 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008009 // LookupResult is not GC safe as it holds raw object pointers.
8010 // GC can happen later in this code so put the required fields into
8011 // local variables using handles when required for later use.
8012 PropertyType result_type = result.type();
8013 Handle<Object> result_callback_obj;
8014 if (result_type == CALLBACKS) {
8015 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8016 }
8017 Smi* property_details = result.GetPropertyDetails().AsSmi();
8018 // DebugLookupResultValue can cause GC so details from LookupResult needs
8019 // to be copied to handles before this.
8020 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008021 Object* raw_value;
8022 { MaybeObject* maybe_raw_value =
8023 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8024 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8025 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008026 Handle<Object> value(raw_value);
8027
8028 // If the callback object is a fixed array then it contains JavaScript
8029 // getter and/or setter.
8030 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8031 result_callback_obj->IsFixedArray();
8032 Handle<FixedArray> details =
8033 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8034 details->set(0, *value);
8035 details->set(1, property_details);
8036 if (hasJavaScriptAccessors) {
8037 details->set(2,
8038 caught_exception ? Heap::true_value()
8039 : Heap::false_value());
8040 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8041 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8042 }
8043
8044 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008045 }
8046 if (i < length - 1) {
8047 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8048 }
8049 }
8050
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008051 return Heap::undefined_value();
8052}
8053
8054
lrn@chromium.org303ada72010-10-27 09:33:13 +00008055static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008056 HandleScope scope;
8057
8058 ASSERT(args.length() == 2);
8059
8060 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8061 CONVERT_ARG_CHECKED(String, name, 1);
8062
8063 LookupResult result;
8064 obj->Lookup(*name, &result);
8065 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008066 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008067 }
8068 return Heap::undefined_value();
8069}
8070
8071
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072// Return the property type calculated from the property details.
8073// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008074static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008075 ASSERT(args.length() == 1);
8076 CONVERT_CHECKED(Smi, details, args[0]);
8077 PropertyType type = PropertyDetails(details).type();
8078 return Smi::FromInt(static_cast<int>(type));
8079}
8080
8081
8082// Return the property attribute calculated from the property details.
8083// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008084static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008085 ASSERT(args.length() == 1);
8086 CONVERT_CHECKED(Smi, details, args[0]);
8087 PropertyAttributes attributes = PropertyDetails(details).attributes();
8088 return Smi::FromInt(static_cast<int>(attributes));
8089}
8090
8091
8092// Return the property insertion index calculated from the property details.
8093// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008094static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008095 ASSERT(args.length() == 1);
8096 CONVERT_CHECKED(Smi, details, args[0]);
8097 int index = PropertyDetails(details).index();
8098 return Smi::FromInt(index);
8099}
8100
8101
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008102// Return property value from named interceptor.
8103// args[0]: object
8104// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008105static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008106 HandleScope scope;
8107 ASSERT(args.length() == 2);
8108 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8109 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8110 CONVERT_ARG_CHECKED(String, name, 1);
8111
8112 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008113 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008114}
8115
8116
8117// Return element value from indexed interceptor.
8118// args[0]: object
8119// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008120static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8121 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008122 HandleScope scope;
8123 ASSERT(args.length() == 2);
8124 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8125 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8126 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8127
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008128 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008129}
8130
8131
lrn@chromium.org303ada72010-10-27 09:33:13 +00008132static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008133 ASSERT(args.length() >= 1);
8134 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008135 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008136 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008137 return Top::Throw(Heap::illegal_execution_state_symbol());
8138 }
8139
8140 return Heap::true_value();
8141}
8142
8143
lrn@chromium.org303ada72010-10-27 09:33:13 +00008144static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008145 HandleScope scope;
8146 ASSERT(args.length() == 1);
8147
8148 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008149 Object* result;
8150 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8151 if (!maybe_result->ToObject(&result)) return maybe_result;
8152 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008153
8154 // Count all frames which are relevant to debugging stack trace.
8155 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008156 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008157 if (id == StackFrame::NO_ID) {
8158 // If there is no JavaScript stack frame count is 0.
8159 return Smi::FromInt(0);
8160 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008161 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8162 return Smi::FromInt(n);
8163}
8164
8165
8166static const int kFrameDetailsFrameIdIndex = 0;
8167static const int kFrameDetailsReceiverIndex = 1;
8168static const int kFrameDetailsFunctionIndex = 2;
8169static const int kFrameDetailsArgumentCountIndex = 3;
8170static const int kFrameDetailsLocalCountIndex = 4;
8171static const int kFrameDetailsSourcePositionIndex = 5;
8172static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008173static const int kFrameDetailsAtReturnIndex = 7;
8174static const int kFrameDetailsDebuggerFrameIndex = 8;
8175static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008176
8177// Return an array with frame details
8178// args[0]: number: break id
8179// args[1]: number: frame index
8180//
8181// The array returned contains the following information:
8182// 0: Frame id
8183// 1: Receiver
8184// 2: Function
8185// 3: Argument count
8186// 4: Local count
8187// 5: Source position
8188// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008189// 7: Is at return
8190// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008191// Arguments name, value
8192// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008193// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008194static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008195 HandleScope scope;
8196 ASSERT(args.length() == 2);
8197
8198 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008199 Object* check;
8200 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8201 if (!maybe_check->ToObject(&check)) return maybe_check;
8202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008203 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8204
8205 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008206 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008207 if (id == StackFrame::NO_ID) {
8208 // If there are no JavaScript stack frames return undefined.
8209 return Heap::undefined_value();
8210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008211 int count = 0;
8212 JavaScriptFrameIterator it(id);
8213 for (; !it.done(); it.Advance()) {
8214 if (count == index) break;
8215 count++;
8216 }
8217 if (it.done()) return Heap::undefined_value();
8218
8219 // Traverse the saved contexts chain to find the active context for the
8220 // selected frame.
8221 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008222 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008223 save = save->prev();
8224 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008225 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008226
8227 // Get the frame id.
8228 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8229
8230 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008231 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232
8233 // Check for constructor frame.
8234 bool constructor = it.frame()->IsConstructor();
8235
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008236 // Get scope info and read from it for local variable information.
8237 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008238 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008239 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008240
8241 // Get the context.
8242 Handle<Context> context(Context::cast(it.frame()->context()));
8243
8244 // Get the locals names and values into a temporary array.
8245 //
8246 // TODO(1240907): Hide compiler-introduced stack variables
8247 // (e.g. .result)? For users of the debugger, they will probably be
8248 // confusing.
8249 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
8250 for (int i = 0; i < info.NumberOfLocals(); i++) {
8251 // Name of the local.
8252 locals->set(i * 2, *info.LocalName(i));
8253
8254 // Fetch the value of the local - either from the stack or from a
8255 // heap-allocated context.
8256 if (i < info.number_of_stack_slots()) {
8257 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8258 } else {
8259 Handle<String> name = info.LocalName(i);
8260 // Traverse the context chain to the function context as all local
8261 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008262 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263 context = Handle<Context>(context->previous());
8264 }
8265 ASSERT(context->is_function_context());
8266 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008267 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008268 }
8269 }
8270
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008271 // Check whether this frame is positioned at return.
8272 int at_return = (index == 0) ? Debug::IsBreakAtReturn(it.frame()) : false;
8273
8274 // If positioned just before return find the value to be returned and add it
8275 // to the frame information.
8276 Handle<Object> return_value = Factory::undefined_value();
8277 if (at_return) {
8278 StackFrameIterator it2;
8279 Address internal_frame_sp = NULL;
8280 while (!it2.done()) {
8281 if (it2.frame()->is_internal()) {
8282 internal_frame_sp = it2.frame()->sp();
8283 } else {
8284 if (it2.frame()->is_java_script()) {
8285 if (it2.frame()->id() == it.frame()->id()) {
8286 // The internal frame just before the JavaScript frame contains the
8287 // value to return on top. A debug break at return will create an
8288 // internal frame to store the return value (eax/rax/r0) before
8289 // entering the debug break exit frame.
8290 if (internal_frame_sp != NULL) {
8291 return_value =
8292 Handle<Object>(Memory::Object_at(internal_frame_sp));
8293 break;
8294 }
8295 }
8296 }
8297
8298 // Indicate that the previous frame was not an internal frame.
8299 internal_frame_sp = NULL;
8300 }
8301 it2.Advance();
8302 }
8303 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008304
8305 // Now advance to the arguments adapter frame (if any). It contains all
8306 // the provided parameters whereas the function frame always have the number
8307 // of arguments matching the functions parameters. The rest of the
8308 // information (except for what is collected above) is the same.
8309 it.AdvanceToArgumentsFrame();
8310
8311 // Find the number of arguments to fill. At least fill the number of
8312 // parameters for the function and fill more if more parameters are provided.
8313 int argument_count = info.number_of_parameters();
8314 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8315 argument_count = it.frame()->GetProvidedParametersCount();
8316 }
8317
8318 // Calculate the size of the result.
8319 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008320 2 * (argument_count + info.NumberOfLocals()) +
8321 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8323
8324 // Add the frame id.
8325 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8326
8327 // Add the function (same as in function frame).
8328 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8329
8330 // Add the arguments count.
8331 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8332
8333 // Add the locals count
8334 details->set(kFrameDetailsLocalCountIndex,
8335 Smi::FromInt(info.NumberOfLocals()));
8336
8337 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008338 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008339 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8340 } else {
8341 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8342 }
8343
8344 // Add the constructor information.
8345 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8346
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008347 // Add the at return information.
8348 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8349
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008350 // Add information on whether this frame is invoked in the debugger context.
8351 details->set(kFrameDetailsDebuggerFrameIndex,
8352 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8353
8354 // Fill the dynamic part.
8355 int details_index = kFrameDetailsFirstDynamicIndex;
8356
8357 // Add arguments name and value.
8358 for (int i = 0; i < argument_count; i++) {
8359 // Name of the argument.
8360 if (i < info.number_of_parameters()) {
8361 details->set(details_index++, *info.parameter_name(i));
8362 } else {
8363 details->set(details_index++, Heap::undefined_value());
8364 }
8365
8366 // Parameter value.
8367 if (i < it.frame()->GetProvidedParametersCount()) {
8368 details->set(details_index++, it.frame()->GetParameter(i));
8369 } else {
8370 details->set(details_index++, Heap::undefined_value());
8371 }
8372 }
8373
8374 // Add locals name and value from the temporary copy from the function frame.
8375 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8376 details->set(details_index++, locals->get(i));
8377 }
8378
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008379 // Add the value being returned.
8380 if (at_return) {
8381 details->set(details_index++, *return_value);
8382 }
8383
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008384 // Add the receiver (same as in function frame).
8385 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8386 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8387 Handle<Object> receiver(it.frame()->receiver());
8388 if (!receiver->IsJSObject()) {
8389 // If the receiver is NOT a JSObject we have hit an optimization
8390 // where a value object is not converted into a wrapped JS objects.
8391 // To hide this optimization from the debugger, we wrap the receiver
8392 // by creating correct wrapper object based on the calling frame's
8393 // global context.
8394 it.Advance();
8395 Handle<Context> calling_frames_global_context(
8396 Context::cast(Context::cast(it.frame()->context())->global_context()));
8397 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8398 }
8399 details->set(kFrameDetailsReceiverIndex, *receiver);
8400
8401 ASSERT_EQ(details_size, details_index);
8402 return *Factory::NewJSArrayWithElements(details);
8403}
8404
8405
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008406// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008407static void CopyContextLocalsToScopeObject(
8408 Handle<SerializedScopeInfo> serialized_scope_info,
8409 ScopeInfo<>& scope_info,
8410 Handle<Context> context,
8411 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008412 // Fill all context locals to the context extension.
8413 for (int i = Context::MIN_CONTEXT_SLOTS;
8414 i < scope_info.number_of_context_slots();
8415 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008416 int context_index = serialized_scope_info->ContextSlotIndex(
8417 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008418
8419 // Don't include the arguments shadow (.arguments) context variable.
8420 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8421 SetProperty(scope_object,
8422 scope_info.context_slot_name(i),
8423 Handle<Object>(context->get(context_index)), NONE);
8424 }
8425 }
8426}
8427
8428
8429// Create a plain JSObject which materializes the local scope for the specified
8430// frame.
8431static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8432 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008433 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008434 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8435 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008436
8437 // Allocate and initialize a JSObject with all the arguments, stack locals
8438 // heap locals and extension properties of the debugged function.
8439 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8440
8441 // First fill all parameters.
8442 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8443 SetProperty(local_scope,
8444 scope_info.parameter_name(i),
8445 Handle<Object>(frame->GetParameter(i)), NONE);
8446 }
8447
8448 // Second fill all stack locals.
8449 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8450 SetProperty(local_scope,
8451 scope_info.stack_slot_name(i),
8452 Handle<Object>(frame->GetExpression(i)), NONE);
8453 }
8454
8455 // Third fill all context locals.
8456 Handle<Context> frame_context(Context::cast(frame->context()));
8457 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008458 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008459 function_context, local_scope);
8460
8461 // Finally copy any properties from the function context extension. This will
8462 // be variables introduced by eval.
8463 if (function_context->closure() == *function) {
8464 if (function_context->has_extension() &&
8465 !function_context->IsGlobalContext()) {
8466 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008467 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008468 for (int i = 0; i < keys->length(); i++) {
8469 // Names of variables introduced by eval are strings.
8470 ASSERT(keys->get(i)->IsString());
8471 Handle<String> key(String::cast(keys->get(i)));
8472 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8473 }
8474 }
8475 }
8476 return local_scope;
8477}
8478
8479
8480// Create a plain JSObject which materializes the closure content for the
8481// context.
8482static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8483 ASSERT(context->is_function_context());
8484
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008485 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008486 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8487 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008488
8489 // Allocate and initialize a JSObject with all the content of theis function
8490 // closure.
8491 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8492
8493 // Check whether the arguments shadow object exists.
8494 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008495 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8496 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008497 if (arguments_shadow_index >= 0) {
8498 // In this case all the arguments are available in the arguments shadow
8499 // object.
8500 Handle<JSObject> arguments_shadow(
8501 JSObject::cast(context->get(arguments_shadow_index)));
8502 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008503 // We don't expect exception-throwing getters on the arguments shadow.
8504 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008505 SetProperty(closure_scope,
8506 scope_info.parameter_name(i),
lrn@chromium.org303ada72010-10-27 09:33:13 +00008507 Handle<Object>(element),
8508 NONE);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008509 }
8510 }
8511
8512 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008513 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8514 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008515
8516 // Finally copy any properties from the function context extension. This will
8517 // be variables introduced by eval.
8518 if (context->has_extension()) {
8519 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008520 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008521 for (int i = 0; i < keys->length(); i++) {
8522 // Names of variables introduced by eval are strings.
8523 ASSERT(keys->get(i)->IsString());
8524 Handle<String> key(String::cast(keys->get(i)));
8525 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
8526 }
8527 }
8528
8529 return closure_scope;
8530}
8531
8532
8533// Iterate over the actual scopes visible from a stack frame. All scopes are
8534// backed by an actual context except the local scope, which is inserted
8535// "artifically" in the context chain.
8536class ScopeIterator {
8537 public:
8538 enum ScopeType {
8539 ScopeTypeGlobal = 0,
8540 ScopeTypeLocal,
8541 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00008542 ScopeTypeClosure,
8543 // Every catch block contains an implicit with block (its parameter is
8544 // a JSContextExtensionObject) that extends current scope with a variable
8545 // holding exception object. Such with blocks are treated as scopes of their
8546 // own type.
8547 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008548 };
8549
8550 explicit ScopeIterator(JavaScriptFrame* frame)
8551 : frame_(frame),
8552 function_(JSFunction::cast(frame->function())),
8553 context_(Context::cast(frame->context())),
8554 local_done_(false),
8555 at_local_(false) {
8556
8557 // Check whether the first scope is actually a local scope.
8558 if (context_->IsGlobalContext()) {
8559 // If there is a stack slot for .result then this local scope has been
8560 // created for evaluating top level code and it is not a real local scope.
8561 // Checking for the existence of .result seems fragile, but the scope info
8562 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008563 int index = function_->shared()->scope_info()->
8564 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008565 at_local_ = index < 0;
8566 } else if (context_->is_function_context()) {
8567 at_local_ = true;
8568 }
8569 }
8570
8571 // More scopes?
8572 bool Done() { return context_.is_null(); }
8573
8574 // Move to the next scope.
8575 void Next() {
8576 // If at a local scope mark the local scope as passed.
8577 if (at_local_) {
8578 at_local_ = false;
8579 local_done_ = true;
8580
8581 // If the current context is not associated with the local scope the
8582 // current context is the next real scope, so don't move to the next
8583 // context in this case.
8584 if (context_->closure() != *function_) {
8585 return;
8586 }
8587 }
8588
8589 // The global scope is always the last in the chain.
8590 if (context_->IsGlobalContext()) {
8591 context_ = Handle<Context>();
8592 return;
8593 }
8594
8595 // Move to the next context.
8596 if (context_->is_function_context()) {
8597 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
8598 } else {
8599 context_ = Handle<Context>(context_->previous());
8600 }
8601
8602 // If passing the local scope indicate that the current scope is now the
8603 // local scope.
8604 if (!local_done_ &&
8605 (context_->IsGlobalContext() || (context_->is_function_context()))) {
8606 at_local_ = true;
8607 }
8608 }
8609
8610 // Return the type of the current scope.
8611 int Type() {
8612 if (at_local_) {
8613 return ScopeTypeLocal;
8614 }
8615 if (context_->IsGlobalContext()) {
8616 ASSERT(context_->global()->IsGlobalObject());
8617 return ScopeTypeGlobal;
8618 }
8619 if (context_->is_function_context()) {
8620 return ScopeTypeClosure;
8621 }
8622 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00008623 // Current scope is either an explicit with statement or a with statement
8624 // implicitely generated for a catch block.
8625 // If the extension object here is a JSContextExtensionObject then
8626 // current with statement is one frome a catch block otherwise it's a
8627 // regular with statement.
8628 if (context_->extension()->IsJSContextExtensionObject()) {
8629 return ScopeTypeCatch;
8630 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008631 return ScopeTypeWith;
8632 }
8633
8634 // Return the JavaScript object with the content of the current scope.
8635 Handle<JSObject> ScopeObject() {
8636 switch (Type()) {
8637 case ScopeIterator::ScopeTypeGlobal:
8638 return Handle<JSObject>(CurrentContext()->global());
8639 break;
8640 case ScopeIterator::ScopeTypeLocal:
8641 // Materialize the content of the local scope into a JSObject.
8642 return MaterializeLocalScope(frame_);
8643 break;
8644 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00008645 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008646 // Return the with object.
8647 return Handle<JSObject>(CurrentContext()->extension());
8648 break;
8649 case ScopeIterator::ScopeTypeClosure:
8650 // Materialize the content of the closure scope into a JSObject.
8651 return MaterializeClosure(CurrentContext());
8652 break;
8653 }
8654 UNREACHABLE();
8655 return Handle<JSObject>();
8656 }
8657
8658 // Return the context for this scope. For the local context there might not
8659 // be an actual context.
8660 Handle<Context> CurrentContext() {
8661 if (at_local_ && context_->closure() != *function_) {
8662 return Handle<Context>();
8663 }
8664 return context_;
8665 }
8666
8667#ifdef DEBUG
8668 // Debug print of the content of the current scope.
8669 void DebugPrint() {
8670 switch (Type()) {
8671 case ScopeIterator::ScopeTypeGlobal:
8672 PrintF("Global:\n");
8673 CurrentContext()->Print();
8674 break;
8675
8676 case ScopeIterator::ScopeTypeLocal: {
8677 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008678 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008679 scope_info.Print();
8680 if (!CurrentContext().is_null()) {
8681 CurrentContext()->Print();
8682 if (CurrentContext()->has_extension()) {
8683 Handle<JSObject> extension =
8684 Handle<JSObject>(CurrentContext()->extension());
8685 if (extension->IsJSContextExtensionObject()) {
8686 extension->Print();
8687 }
8688 }
8689 }
8690 break;
8691 }
8692
8693 case ScopeIterator::ScopeTypeWith: {
8694 PrintF("With:\n");
8695 Handle<JSObject> extension =
8696 Handle<JSObject>(CurrentContext()->extension());
8697 extension->Print();
8698 break;
8699 }
8700
ager@chromium.orga1645e22009-09-09 19:27:10 +00008701 case ScopeIterator::ScopeTypeCatch: {
8702 PrintF("Catch:\n");
8703 Handle<JSObject> extension =
8704 Handle<JSObject>(CurrentContext()->extension());
8705 extension->Print();
8706 break;
8707 }
8708
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008709 case ScopeIterator::ScopeTypeClosure: {
8710 PrintF("Closure:\n");
8711 CurrentContext()->Print();
8712 if (CurrentContext()->has_extension()) {
8713 Handle<JSObject> extension =
8714 Handle<JSObject>(CurrentContext()->extension());
8715 if (extension->IsJSContextExtensionObject()) {
8716 extension->Print();
8717 }
8718 }
8719 break;
8720 }
8721
8722 default:
8723 UNREACHABLE();
8724 }
8725 PrintF("\n");
8726 }
8727#endif
8728
8729 private:
8730 JavaScriptFrame* frame_;
8731 Handle<JSFunction> function_;
8732 Handle<Context> context_;
8733 bool local_done_;
8734 bool at_local_;
8735
8736 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
8737};
8738
8739
lrn@chromium.org303ada72010-10-27 09:33:13 +00008740static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008741 HandleScope scope;
8742 ASSERT(args.length() == 2);
8743
8744 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008745 Object* check;
8746 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8747 if (!maybe_check->ToObject(&check)) return maybe_check;
8748 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008749 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8750
8751 // Get the frame where the debugging is performed.
8752 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8753 JavaScriptFrameIterator it(id);
8754 JavaScriptFrame* frame = it.frame();
8755
8756 // Count the visible scopes.
8757 int n = 0;
8758 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8759 n++;
8760 }
8761
8762 return Smi::FromInt(n);
8763}
8764
8765
8766static const int kScopeDetailsTypeIndex = 0;
8767static const int kScopeDetailsObjectIndex = 1;
8768static const int kScopeDetailsSize = 2;
8769
8770// Return an array with scope details
8771// args[0]: number: break id
8772// args[1]: number: frame index
8773// args[2]: number: scope index
8774//
8775// The array returned contains the following information:
8776// 0: Scope type
8777// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00008778static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008779 HandleScope scope;
8780 ASSERT(args.length() == 3);
8781
8782 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008783 Object* check;
8784 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8785 if (!maybe_check->ToObject(&check)) return maybe_check;
8786 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008787 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8788 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
8789
8790 // Get the frame where the debugging is performed.
8791 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8792 JavaScriptFrameIterator frame_it(id);
8793 JavaScriptFrame* frame = frame_it.frame();
8794
8795 // Find the requested scope.
8796 int n = 0;
8797 ScopeIterator it(frame);
8798 for (; !it.Done() && n < index; it.Next()) {
8799 n++;
8800 }
8801 if (it.Done()) {
8802 return Heap::undefined_value();
8803 }
8804
8805 // Calculate the size of the result.
8806 int details_size = kScopeDetailsSize;
8807 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8808
8809 // Fill in scope details.
8810 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008811 Handle<JSObject> scope_object = it.ScopeObject();
8812 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008813
8814 return *Factory::NewJSArrayWithElements(details);
8815}
8816
8817
lrn@chromium.org303ada72010-10-27 09:33:13 +00008818static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008819 HandleScope scope;
8820 ASSERT(args.length() == 0);
8821
8822#ifdef DEBUG
8823 // Print the scopes for the top frame.
8824 StackFrameLocator locator;
8825 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
8826 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8827 it.DebugPrint();
8828 }
8829#endif
8830 return Heap::undefined_value();
8831}
8832
8833
lrn@chromium.org303ada72010-10-27 09:33:13 +00008834static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008835 HandleScope scope;
8836 ASSERT(args.length() == 1);
8837
8838 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008839 Object* result;
8840 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8841 if (!maybe_result->ToObject(&result)) return maybe_result;
8842 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008843
8844 // Count all archived V8 threads.
8845 int n = 0;
8846 for (ThreadState* thread = ThreadState::FirstInUse();
8847 thread != NULL;
8848 thread = thread->Next()) {
8849 n++;
8850 }
8851
8852 // Total number of threads is current thread and archived threads.
8853 return Smi::FromInt(n + 1);
8854}
8855
8856
8857static const int kThreadDetailsCurrentThreadIndex = 0;
8858static const int kThreadDetailsThreadIdIndex = 1;
8859static const int kThreadDetailsSize = 2;
8860
8861// Return an array with thread details
8862// args[0]: number: break id
8863// args[1]: number: thread index
8864//
8865// The array returned contains the following information:
8866// 0: Is current thread?
8867// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00008868static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008869 HandleScope scope;
8870 ASSERT(args.length() == 2);
8871
8872 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008873 Object* check;
8874 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8875 if (!maybe_check->ToObject(&check)) return maybe_check;
8876 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008877 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8878
8879 // Allocate array for result.
8880 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
8881
8882 // Thread index 0 is current thread.
8883 if (index == 0) {
8884 // Fill the details.
8885 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
8886 details->set(kThreadDetailsThreadIdIndex,
8887 Smi::FromInt(ThreadManager::CurrentId()));
8888 } else {
8889 // Find the thread with the requested index.
8890 int n = 1;
8891 ThreadState* thread = ThreadState::FirstInUse();
8892 while (index != n && thread != NULL) {
8893 thread = thread->Next();
8894 n++;
8895 }
8896 if (thread == NULL) {
8897 return Heap::undefined_value();
8898 }
8899
8900 // Fill the details.
8901 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
8902 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
8903 }
8904
8905 // Convert to JS array and return.
8906 return *Factory::NewJSArrayWithElements(details);
8907}
8908
8909
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008910// Sets the disable break state
8911// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00008912static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008913 HandleScope scope;
8914 ASSERT(args.length() == 1);
8915 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
8916 Debug::set_disable_break(disable_break);
8917 return Heap::undefined_value();
8918}
8919
8920
lrn@chromium.org303ada72010-10-27 09:33:13 +00008921static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922 HandleScope scope;
8923 ASSERT(args.length() == 1);
8924
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008925 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8926 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008927 // Find the number of break points
8928 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
8929 if (break_locations->IsUndefined()) return Heap::undefined_value();
8930 // Return array as JS array
8931 return *Factory::NewJSArrayWithElements(
8932 Handle<FixedArray>::cast(break_locations));
8933}
8934
8935
8936// Set a break point in a function
8937// args[0]: function
8938// args[1]: number: break source position (within the function source)
8939// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00008940static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008941 HandleScope scope;
8942 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008943 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8944 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008945 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
8946 RUNTIME_ASSERT(source_position >= 0);
8947 Handle<Object> break_point_object_arg = args.at<Object>(2);
8948
8949 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008950 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008951
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008952 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008953}
8954
8955
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00008956Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
8957 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008958 // Iterate the heap looking for SharedFunctionInfo generated from the
8959 // script. The inner most SharedFunctionInfo containing the source position
8960 // for the requested break point is found.
8961 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
8962 // which is found is not compiled it is compiled and the heap is iterated
8963 // again as the compilation might create inner functions from the newly
8964 // compiled function and the actual requested break point might be in one of
8965 // these functions.
8966 bool done = false;
8967 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00008968 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008969 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008970 while (!done) {
8971 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008972 for (HeapObject* obj = iterator.next();
8973 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008974 if (obj->IsSharedFunctionInfo()) {
8975 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
8976 if (shared->script() == *script) {
8977 // If the SharedFunctionInfo found has the requested script data and
8978 // contains the source position it is a candidate.
8979 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00008980 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 start_position = shared->start_position();
8982 }
8983 if (start_position <= position &&
8984 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00008985 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008986 // candidate this is the new candidate.
8987 if (target.is_null()) {
8988 target_start_position = start_position;
8989 target = shared;
8990 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00008991 if (target_start_position == start_position &&
8992 shared->end_position() == target->end_position()) {
8993 // If a top-level function contain only one function
8994 // declartion the source for the top-level and the function is
8995 // the same. In that case prefer the non top-level function.
8996 if (!shared->is_toplevel()) {
8997 target_start_position = start_position;
8998 target = shared;
8999 }
9000 } else if (target_start_position <= start_position &&
9001 shared->end_position() <= target->end_position()) {
9002 // This containment check includes equality as a function inside
9003 // a top-level function can share either start or end position
9004 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009005 target_start_position = start_position;
9006 target = shared;
9007 }
9008 }
9009 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009010 }
9011 }
9012 }
9013
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009015 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009016 }
9017
9018 // If the candidate found is compiled we are done. NOTE: when lazy
9019 // compilation of inner functions is introduced some additional checking
9020 // needs to be done here to compile inner functions.
9021 done = target->is_compiled();
9022 if (!done) {
9023 // If the candidate is not compiled compile it to reveal any inner
9024 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009025 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009026 }
9027 }
9028
9029 return *target;
9030}
9031
9032
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009033// Changes the state of a break point in a script and returns source position
9034// where break point was set. NOTE: Regarding performance see the NOTE for
9035// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009036// args[0]: script to set break point in
9037// args[1]: number: break source position (within the script source)
9038// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009039static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009040 HandleScope scope;
9041 ASSERT(args.length() == 3);
9042 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9043 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9044 RUNTIME_ASSERT(source_position >= 0);
9045 Handle<Object> break_point_object_arg = args.at<Object>(2);
9046
9047 // Get the script from the script wrapper.
9048 RUNTIME_ASSERT(wrapper->value()->IsScript());
9049 Handle<Script> script(Script::cast(wrapper->value()));
9050
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009051 Object* result = Runtime::FindSharedFunctionInfoInScript(
9052 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053 if (!result->IsUndefined()) {
9054 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9055 // Find position within function. The script position might be before the
9056 // source position of the first function.
9057 int position;
9058 if (shared->start_position() > source_position) {
9059 position = 0;
9060 } else {
9061 position = source_position - shared->start_position();
9062 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009063 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9064 position += shared->start_position();
9065 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009066 }
9067 return Heap::undefined_value();
9068}
9069
9070
9071// Clear a break point
9072// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009073static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074 HandleScope scope;
9075 ASSERT(args.length() == 1);
9076 Handle<Object> break_point_object_arg = args.at<Object>(0);
9077
9078 // Clear break point.
9079 Debug::ClearBreakPoint(break_point_object_arg);
9080
9081 return Heap::undefined_value();
9082}
9083
9084
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009085// Change the state of break on exceptions.
9086// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9087// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009088static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009089 HandleScope scope;
9090 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009091 RUNTIME_ASSERT(args[0]->IsNumber());
9092 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009093
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009094 // If the number doesn't match an enum value, the ChangeBreakOnException
9095 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009096 ExceptionBreakType type =
9097 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009098 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009099 Debug::ChangeBreakOnException(type, enable);
9100 return Heap::undefined_value();
9101}
9102
9103
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009104// Returns the state of break on exceptions
9105// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009106static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009107 HandleScope scope;
9108 ASSERT(args.length() == 1);
9109 RUNTIME_ASSERT(args[0]->IsNumber());
9110
9111 ExceptionBreakType type =
9112 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9113 bool result = Debug::IsBreakOnException(type);
9114 return Smi::FromInt(result);
9115}
9116
9117
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009118// Prepare for stepping
9119// args[0]: break id for checking execution state
9120// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009121// args[2]: number of times to perform the step, for step out it is the number
9122// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009123static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009124 HandleScope scope;
9125 ASSERT(args.length() == 3);
9126 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009127 Object* check;
9128 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9129 if (!maybe_check->ToObject(&check)) return maybe_check;
9130 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009131 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9132 return Top::Throw(Heap::illegal_argument_symbol());
9133 }
9134
9135 // Get the step action and check validity.
9136 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9137 if (step_action != StepIn &&
9138 step_action != StepNext &&
9139 step_action != StepOut &&
9140 step_action != StepInMin &&
9141 step_action != StepMin) {
9142 return Top::Throw(Heap::illegal_argument_symbol());
9143 }
9144
9145 // Get the number of steps.
9146 int step_count = NumberToInt32(args[2]);
9147 if (step_count < 1) {
9148 return Top::Throw(Heap::illegal_argument_symbol());
9149 }
9150
ager@chromium.orga1645e22009-09-09 19:27:10 +00009151 // Clear all current stepping setup.
9152 Debug::ClearStepping();
9153
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009154 // Prepare step.
9155 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9156 return Heap::undefined_value();
9157}
9158
9159
9160// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009161static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009163 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009164 Debug::ClearStepping();
9165 return Heap::undefined_value();
9166}
9167
9168
9169// Creates a copy of the with context chain. The copy of the context chain is
9170// is linked to the function context supplied.
9171static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9172 Handle<Context> function_context) {
9173 // At the bottom of the chain. Return the function context to link to.
9174 if (context_chain->is_function_context()) {
9175 return function_context;
9176 }
9177
9178 // Recursively copy the with contexts.
9179 Handle<Context> previous(context_chain->previous());
9180 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009181 Handle<Context> context = CopyWithContextChain(function_context, previous);
9182 return Factory::NewWithContext(context,
9183 extension,
9184 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185}
9186
9187
9188// Helper function to find or create the arguments object for
9189// Runtime_DebugEvaluate.
9190static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9191 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009192 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009193 const ScopeInfo<>* sinfo,
9194 Handle<Context> function_context) {
9195 // Try to find the value of 'arguments' to pass as parameter. If it is not
9196 // found (that is the debugged function does not reference 'arguments' and
9197 // does not support eval) then create an 'arguments' object.
9198 int index;
9199 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009200 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009201 if (index != -1) {
9202 return Handle<Object>(frame->GetExpression(index));
9203 }
9204 }
9205
9206 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009207 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009208 if (index != -1) {
9209 return Handle<Object>(function_context->get(index));
9210 }
9211 }
9212
9213 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009214 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9215 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009216
9217 AssertNoAllocation no_gc;
9218 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009219 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009220 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009221 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009222 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009223 return arguments;
9224}
9225
9226
9227// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009228// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009229// extension part has all the parameters and locals of the function on the
9230// stack frame. A function which calls eval with the code to evaluate is then
9231// compiled in this context and called in this context. As this context
9232// replaces the context of the function on the stack frame a new (empty)
9233// function is created as well to be used as the closure for the context.
9234// This function and the context acts as replacements for the function on the
9235// stack frame presenting the same view of the values of parameters and
9236// local variables as if the piece of JavaScript was evaluated at the point
9237// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009238static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009239 HandleScope scope;
9240
9241 // Check the execution state and decode arguments frame and source to be
9242 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009243 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009244 Object* check_result;
9245 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9246 if (!maybe_check_result->ToObject(&check_result)) {
9247 return maybe_check_result;
9248 }
9249 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009250 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9251 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009252 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
9253
9254 // Handle the processing of break.
9255 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009256
9257 // Get the frame where the debugging is performed.
9258 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9259 JavaScriptFrameIterator it(id);
9260 JavaScriptFrame* frame = it.frame();
9261 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009262 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009263 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009264
9265 // Traverse the saved contexts chain to find the active context for the
9266 // selected frame.
9267 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009268 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009269 save = save->prev();
9270 }
9271 ASSERT(save != NULL);
9272 SaveContext savex;
9273 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009274
9275 // Create the (empty) function replacing the function on the stack frame for
9276 // the purpose of evaluating in the context created below. It is important
9277 // that this function does not describe any parameters and local variables
9278 // in the context. If it does then this will cause problems with the lookup
9279 // in Context::Lookup, where context slots for parameters and local variables
9280 // are looked at before the extension object.
9281 Handle<JSFunction> go_between =
9282 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9283 go_between->set_context(function->context());
9284#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009285 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009286 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9287 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9288#endif
9289
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009290 // Materialize the content of the local scope into a JSObject.
9291 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009292
9293 // Allocate a new context for the debug evaluation and set the extension
9294 // object build.
9295 Handle<Context> context =
9296 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009297 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009299 Handle<Context> frame_context(Context::cast(frame->context()));
9300 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009301 context = CopyWithContextChain(frame_context, context);
9302
9303 // Wrap the evaluation statement in a new function compiled in the newly
9304 // created context. The function has one parameter which has to be called
9305 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009306 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009307 // function(arguments,__source__) {return eval(__source__);}
9308 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009309 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009310 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009311 Handle<String> function_source =
9312 Factory::NewStringFromAscii(Vector<const char>(source_str,
9313 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009314 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009315 Compiler::CompileEval(function_source,
9316 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009317 context->IsGlobalContext());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009318 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009319 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009320 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009321
9322 // Invoke the result of the compilation to get the evaluation function.
9323 bool has_pending_exception;
9324 Handle<Object> receiver(frame->receiver());
9325 Handle<Object> evaluation_function =
9326 Execution::Call(compiled_function, receiver, 0, NULL,
9327 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009328 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009329
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009330 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9331 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332
9333 // Invoke the evaluation function and return the result.
9334 const int argc = 2;
9335 Object** argv[argc] = { arguments.location(),
9336 Handle<Object>::cast(source).location() };
9337 Handle<Object> result =
9338 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9339 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009340 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009341
9342 // Skip the global proxy as it has no properties and always delegates to the
9343 // real global object.
9344 if (result->IsJSGlobalProxy()) {
9345 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9346 }
9347
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009348 return *result;
9349}
9350
9351
lrn@chromium.org303ada72010-10-27 09:33:13 +00009352static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009353 HandleScope scope;
9354
9355 // Check the execution state and decode arguments frame and source to be
9356 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009357 ASSERT(args.length() == 3);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009358 Object* check_result;
9359 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9360 if (!maybe_check_result->ToObject(&check_result)) {
9361 return maybe_check_result;
9362 }
9363 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009364 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009365 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
9366
9367 // Handle the processing of break.
9368 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009369
9370 // Enter the top context from before the debugger was invoked.
9371 SaveContext save;
9372 SaveContext* top = &save;
9373 while (top != NULL && *top->context() == *Debug::debug_context()) {
9374 top = top->prev();
9375 }
9376 if (top != NULL) {
9377 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009378 }
9379
9380 // Get the global context now set to the top context from before the
9381 // debugger was invoked.
9382 Handle<Context> context = Top::global_context();
9383
9384 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009385 Handle<SharedFunctionInfo> shared =
9386 Compiler::CompileEval(source,
9387 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009388 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009389 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009390 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009391 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9392 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009393
9394 // Invoke the result of the compilation to get the evaluation function.
9395 bool has_pending_exception;
9396 Handle<Object> receiver = Top::global();
9397 Handle<Object> result =
9398 Execution::Call(compiled_function, receiver, 0, NULL,
9399 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009400 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401 return *result;
9402}
9403
9404
lrn@chromium.org303ada72010-10-27 09:33:13 +00009405static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009406 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009407 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009408
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009409 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009410 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009411
9412 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009413 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009414 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9415 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9416 // because using
9417 // instances->set(i, *GetScriptWrapper(script))
9418 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9419 // already have deferenced the instances handle.
9420 Handle<JSValue> wrapper = GetScriptWrapper(script);
9421 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009422 }
9423
9424 // Return result as a JS array.
9425 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9426 Handle<JSArray>::cast(result)->SetContent(*instances);
9427 return *result;
9428}
9429
9430
9431// Helper function used by Runtime_DebugReferencedBy below.
9432static int DebugReferencedBy(JSObject* target,
9433 Object* instance_filter, int max_references,
9434 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009435 JSFunction* arguments_function) {
9436 NoHandleAllocation ha;
9437 AssertNoAllocation no_alloc;
9438
9439 // Iterate the heap.
9440 int count = 0;
9441 JSObject* last = NULL;
9442 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009443 HeapObject* heap_obj = NULL;
9444 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009445 (max_references == 0 || count < max_references)) {
9446 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009447 if (heap_obj->IsJSObject()) {
9448 // Skip context extension objects and argument arrays as these are
9449 // checked in the context of functions using them.
9450 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009451 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009452 obj->map()->constructor() == arguments_function) {
9453 continue;
9454 }
9455
9456 // Check if the JS object has a reference to the object looked for.
9457 if (obj->ReferencesObject(target)) {
9458 // Check instance filter if supplied. This is normally used to avoid
9459 // references from mirror objects (see Runtime_IsInPrototypeChain).
9460 if (!instance_filter->IsUndefined()) {
9461 Object* V = obj;
9462 while (true) {
9463 Object* prototype = V->GetPrototype();
9464 if (prototype->IsNull()) {
9465 break;
9466 }
9467 if (instance_filter == prototype) {
9468 obj = NULL; // Don't add this object.
9469 break;
9470 }
9471 V = prototype;
9472 }
9473 }
9474
9475 if (obj != NULL) {
9476 // Valid reference found add to instance array if supplied an update
9477 // count.
9478 if (instances != NULL && count < instances_size) {
9479 instances->set(count, obj);
9480 }
9481 last = obj;
9482 count++;
9483 }
9484 }
9485 }
9486 }
9487
9488 // Check for circular reference only. This can happen when the object is only
9489 // referenced from mirrors and has a circular reference in which case the
9490 // object is not really alive and would have been garbage collected if not
9491 // referenced from the mirror.
9492 if (count == 1 && last == target) {
9493 count = 0;
9494 }
9495
9496 // Return the number of referencing objects found.
9497 return count;
9498}
9499
9500
9501// Scan the heap for objects with direct references to an object
9502// args[0]: the object to find references to
9503// args[1]: constructor function for instances to exclude (Mirror)
9504// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +00009505static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009506 ASSERT(args.length() == 3);
9507
9508 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009509 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009510
9511 // Check parameters.
9512 CONVERT_CHECKED(JSObject, target, args[0]);
9513 Object* instance_filter = args[1];
9514 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
9515 instance_filter->IsJSObject());
9516 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
9517 RUNTIME_ASSERT(max_references >= 0);
9518
9519 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009520 JSObject* arguments_boilerplate =
9521 Top::context()->global_context()->arguments_boilerplate();
9522 JSFunction* arguments_function =
9523 JSFunction::cast(arguments_boilerplate->map()->constructor());
9524
9525 // Get the number of referencing objects.
9526 int count;
9527 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009528 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009529
9530 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009531 Object* object;
9532 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9533 if (!maybe_object->ToObject(&object)) return maybe_object;
9534 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009535 FixedArray* instances = FixedArray::cast(object);
9536
9537 // Fill the referencing objects.
9538 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009539 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009540
9541 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009542 Object* result;
9543 { MaybeObject* maybe_result = Heap::AllocateJSObject(
9544 Top::context()->global_context()->array_function());
9545 if (!maybe_result->ToObject(&result)) return maybe_result;
9546 }
9547 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009548 return result;
9549}
9550
9551
9552// Helper function used by Runtime_DebugConstructedBy below.
9553static int DebugConstructedBy(JSFunction* constructor, int max_references,
9554 FixedArray* instances, int instances_size) {
9555 AssertNoAllocation no_alloc;
9556
9557 // Iterate the heap.
9558 int count = 0;
9559 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009560 HeapObject* heap_obj = NULL;
9561 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009562 (max_references == 0 || count < max_references)) {
9563 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009564 if (heap_obj->IsJSObject()) {
9565 JSObject* obj = JSObject::cast(heap_obj);
9566 if (obj->map()->constructor() == constructor) {
9567 // Valid reference found add to instance array if supplied an update
9568 // count.
9569 if (instances != NULL && count < instances_size) {
9570 instances->set(count, obj);
9571 }
9572 count++;
9573 }
9574 }
9575 }
9576
9577 // Return the number of referencing objects found.
9578 return count;
9579}
9580
9581
9582// Scan the heap for objects constructed by a specific function.
9583// args[0]: the constructor to find instances of
9584// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +00009585static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009586 ASSERT(args.length() == 2);
9587
9588 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009589 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009590
9591 // Check parameters.
9592 CONVERT_CHECKED(JSFunction, constructor, args[0]);
9593 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
9594 RUNTIME_ASSERT(max_references >= 0);
9595
9596 // Get the number of referencing objects.
9597 int count;
9598 count = DebugConstructedBy(constructor, max_references, NULL, 0);
9599
9600 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009601 Object* object;
9602 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9603 if (!maybe_object->ToObject(&object)) return maybe_object;
9604 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009605 FixedArray* instances = FixedArray::cast(object);
9606
9607 // Fill the referencing objects.
9608 count = DebugConstructedBy(constructor, max_references, instances, count);
9609
9610 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009611 Object* result;
9612 { MaybeObject* maybe_result = Heap::AllocateJSObject(
9613 Top::context()->global_context()->array_function());
9614 if (!maybe_result->ToObject(&result)) return maybe_result;
9615 }
9616 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009617 return result;
9618}
9619
9620
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009621// Find the effective prototype object as returned by __proto__.
9622// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009623static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009624 ASSERT(args.length() == 1);
9625
9626 CONVERT_CHECKED(JSObject, obj, args[0]);
9627
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009628 // Use the __proto__ accessor.
9629 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009630}
9631
9632
lrn@chromium.org303ada72010-10-27 09:33:13 +00009633static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00009634 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009635 CPU::DebugBreak();
9636 return Heap::undefined_value();
9637}
9638
9639
lrn@chromium.org303ada72010-10-27 09:33:13 +00009640static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009641#ifdef DEBUG
9642 HandleScope scope;
9643 ASSERT(args.length() == 1);
9644 // Get the function and make sure it is compiled.
9645 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009646 Handle<SharedFunctionInfo> shared(func->shared());
9647 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009648 return Failure::Exception();
9649 }
9650 func->code()->PrintLn();
9651#endif // DEBUG
9652 return Heap::undefined_value();
9653}
ager@chromium.org9085a012009-05-11 19:22:57 +00009654
9655
lrn@chromium.org303ada72010-10-27 09:33:13 +00009656static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009657#ifdef DEBUG
9658 HandleScope scope;
9659 ASSERT(args.length() == 1);
9660 // Get the function and make sure it is compiled.
9661 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009662 Handle<SharedFunctionInfo> shared(func->shared());
9663 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009664 return Failure::Exception();
9665 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009666 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009667#endif // DEBUG
9668 return Heap::undefined_value();
9669}
9670
9671
lrn@chromium.org303ada72010-10-27 09:33:13 +00009672static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +00009673 NoHandleAllocation ha;
9674 ASSERT(args.length() == 1);
9675
9676 CONVERT_CHECKED(JSFunction, f, args[0]);
9677 return f->shared()->inferred_name();
9678}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009679
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009680
9681static int FindSharedFunctionInfosForScript(Script* script,
9682 FixedArray* buffer) {
9683 AssertNoAllocation no_allocations;
9684
9685 int counter = 0;
9686 int buffer_size = buffer->length();
9687 HeapIterator iterator;
9688 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
9689 ASSERT(obj != NULL);
9690 if (!obj->IsSharedFunctionInfo()) {
9691 continue;
9692 }
9693 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
9694 if (shared->script() != script) {
9695 continue;
9696 }
9697 if (counter < buffer_size) {
9698 buffer->set(counter, shared);
9699 }
9700 counter++;
9701 }
9702 return counter;
9703}
9704
9705// For a script finds all SharedFunctionInfo's in the heap that points
9706// to this script. Returns JSArray of SharedFunctionInfo wrapped
9707// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009708static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009709 Arguments args) {
9710 ASSERT(args.length() == 1);
9711 HandleScope scope;
9712 CONVERT_CHECKED(JSValue, script_value, args[0]);
9713
9714 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
9715
9716 const int kBufferSize = 32;
9717
9718 Handle<FixedArray> array;
9719 array = Factory::NewFixedArray(kBufferSize);
9720 int number = FindSharedFunctionInfosForScript(*script, *array);
9721 if (number > kBufferSize) {
9722 array = Factory::NewFixedArray(number);
9723 FindSharedFunctionInfosForScript(*script, *array);
9724 }
9725
9726 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
9727 result->set_length(Smi::FromInt(number));
9728
9729 LiveEdit::WrapSharedFunctionInfos(result);
9730
9731 return *result;
9732}
9733
9734// For a script calculates compilation information about all its functions.
9735// The script source is explicitly specified by the second argument.
9736// The source of the actual script is not used, however it is important that
9737// all generated code keeps references to this particular instance of script.
9738// Returns a JSArray of compilation infos. The array is ordered so that
9739// each function with all its descendant is always stored in a continues range
9740// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009741static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009742 ASSERT(args.length() == 2);
9743 HandleScope scope;
9744 CONVERT_CHECKED(JSValue, script, args[0]);
9745 CONVERT_ARG_CHECKED(String, source, 1);
9746 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
9747
9748 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
9749
9750 if (Top::has_pending_exception()) {
9751 return Failure::Exception();
9752 }
9753
9754 return result;
9755}
9756
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009757// Changes the source of the script to a new_source.
9758// If old_script_name is provided (i.e. is a String), also creates a copy of
9759// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009760static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009761 ASSERT(args.length() == 3);
9762 HandleScope scope;
9763 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
9764 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009765 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009766
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009767 CONVERT_CHECKED(Script, original_script_pointer,
9768 original_script_value->value());
9769 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009770
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009771 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
9772 new_source,
9773 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009774
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009775 if (old_script->IsScript()) {
9776 Handle<Script> script_handle(Script::cast(old_script));
9777 return *(GetScriptWrapper(script_handle));
9778 } else {
9779 return Heap::null_value();
9780 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009781}
9782
9783// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009784static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009785 ASSERT(args.length() == 2);
9786 HandleScope scope;
9787 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
9788 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
9789
ager@chromium.orgac091b72010-05-05 07:34:42 +00009790 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009791}
9792
9793// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009794static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009795 ASSERT(args.length() == 2);
9796 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009797 Handle<Object> function_object(args[0]);
9798 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009799
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009800 if (function_object->IsJSValue()) {
9801 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
9802 if (script_object->IsJSValue()) {
9803 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
9804 script_object = Handle<Object>(script);
9805 }
9806
9807 LiveEdit::SetFunctionScript(function_wrapper, script_object);
9808 } else {
9809 // Just ignore this. We may not have a SharedFunctionInfo for some functions
9810 // and we check it in this function.
9811 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009812
9813 return Heap::undefined_value();
9814}
9815
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009816
9817// In a code of a parent function replaces original function as embedded object
9818// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009819static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009820 ASSERT(args.length() == 3);
9821 HandleScope scope;
9822
9823 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
9824 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
9825 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
9826
9827 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
9828 subst_wrapper);
9829
9830 return Heap::undefined_value();
9831}
9832
9833
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009834// Updates positions of a shared function info (first parameter) according
9835// to script source change. Text change is described in second parameter as
9836// array of groups of 3 numbers:
9837// (change_begin, change_end, change_end_new_position).
9838// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009839static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009840 ASSERT(args.length() == 2);
9841 HandleScope scope;
9842 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
9843 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
9844
ager@chromium.orgac091b72010-05-05 07:34:42 +00009845 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009846}
9847
9848
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009849// For array of SharedFunctionInfo's (each wrapped in JSValue)
9850// checks that none of them have activations on stacks (of any thread).
9851// Returns array of the same length with corresponding results of
9852// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009853static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00009854 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009855 HandleScope scope;
9856 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +00009857 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009858
ager@chromium.org357bf652010-04-12 11:30:10 +00009859 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009860}
9861
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009862// Compares 2 strings line-by-line and returns diff in form of JSArray of
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00009863// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009864static MaybeObject* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009865 ASSERT(args.length() == 2);
9866 HandleScope scope;
9867 CONVERT_ARG_CHECKED(String, s1, 0);
9868 CONVERT_ARG_CHECKED(String, s2, 1);
9869
9870 return *LiveEdit::CompareStringsLinewise(s1, s2);
9871}
9872
9873
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009874
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009875// A testing entry. Returns statement position which is the closest to
9876// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009877static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009878 ASSERT(args.length() == 2);
9879 HandleScope scope;
9880 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9881 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9882
9883 Handle<Code> code(function->code());
9884
9885 RelocIterator it(*code, 1 << RelocInfo::STATEMENT_POSITION);
9886 int closest_pc = 0;
9887 int distance = kMaxInt;
9888 while (!it.done()) {
9889 int statement_position = static_cast<int>(it.rinfo()->data());
9890 // Check if this break point is closer that what was previously found.
9891 if (source_position <= statement_position &&
9892 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00009893 closest_pc =
9894 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009895 distance = statement_position - source_position;
9896 // Check whether we can't get any closer.
9897 if (distance == 0) break;
9898 }
9899 it.next();
9900 }
9901
9902 return Smi::FromInt(closest_pc);
9903}
9904
9905
ager@chromium.org357bf652010-04-12 11:30:10 +00009906// Calls specified function with or without entering the debugger.
9907// This is used in unit tests to run code as if debugger is entered or simply
9908// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009909static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00009910 ASSERT(args.length() == 2);
9911 HandleScope scope;
9912 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9913 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
9914
9915 Handle<Object> result;
9916 bool pending_exception;
9917 {
9918 if (without_debugger) {
9919 result = Execution::Call(function, Top::global(), 0, NULL,
9920 &pending_exception);
9921 } else {
9922 EnterDebugger enter_debugger;
9923 result = Execution::Call(function, Top::global(), 0, NULL,
9924 &pending_exception);
9925 }
9926 }
9927 if (!pending_exception) {
9928 return *result;
9929 } else {
9930 return Failure::Exception();
9931 }
9932}
9933
9934
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009935#endif // ENABLE_DEBUGGER_SUPPORT
9936
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009937#ifdef ENABLE_LOGGING_AND_PROFILING
9938
lrn@chromium.org303ada72010-10-27 09:33:13 +00009939static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009940 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009941 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009942
9943 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009944 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9945 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009946 return Heap::undefined_value();
9947}
9948
9949
lrn@chromium.org303ada72010-10-27 09:33:13 +00009950static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009951 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009952 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009953
9954 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009955 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9956 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009957 return Heap::undefined_value();
9958}
9959
9960#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009961
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962// Finds the script object from the script data. NOTE: This operation uses
9963// heap traversal to find the function generated for the source position
9964// for the requested break point. For lazily compiled functions several heap
9965// traversals might be required rendering this operation as a rather slow
9966// operation. However for setting break points which is normally done through
9967// some kind of user interaction the performance is not crucial.
9968static Handle<Object> Runtime_GetScriptFromScriptName(
9969 Handle<String> script_name) {
9970 // Scan the heap for Script objects to find the script with the requested
9971 // script data.
9972 Handle<Script> script;
9973 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009974 HeapObject* obj = NULL;
9975 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009976 // If a script is found check if it has the script data requested.
9977 if (obj->IsScript()) {
9978 if (Script::cast(obj)->name()->IsString()) {
9979 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
9980 script = Handle<Script>(Script::cast(obj));
9981 }
9982 }
9983 }
9984 }
9985
9986 // If no script with the requested script data is found return undefined.
9987 if (script.is_null()) return Factory::undefined_value();
9988
9989 // Return the script found.
9990 return GetScriptWrapper(script);
9991}
9992
9993
9994// Get the script object from script data. NOTE: Regarding performance
9995// see the NOTE for GetScriptFromScriptData.
9996// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +00009997static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009998 HandleScope scope;
9999
10000 ASSERT(args.length() == 1);
10001
10002 CONVERT_CHECKED(String, script_name, args[0]);
10003
10004 // Find the requested script.
10005 Handle<Object> result =
10006 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10007 return *result;
10008}
10009
10010
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010011// Determines whether the given stack frame should be displayed in
10012// a stack trace. The caller is the error constructor that asked
10013// for the stack trace to be collected. The first time a construct
10014// call to this function is encountered it is skipped. The seen_caller
10015// in/out parameter is used to remember if the caller has been seen
10016// yet.
10017static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10018 bool* seen_caller) {
10019 // Only display JS frames.
10020 if (!raw_frame->is_java_script())
10021 return false;
10022 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10023 Object* raw_fun = frame->function();
10024 // Not sure when this can happen but skip it just in case.
10025 if (!raw_fun->IsJSFunction())
10026 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010027 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010028 *seen_caller = true;
10029 return false;
10030 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010031 // Skip all frames until we've seen the caller. Also, skip the most
10032 // obvious builtin calls. Some builtin calls (such as Number.ADD
10033 // which is invoked using 'call') are very difficult to recognize
10034 // so we're leaving them in for now.
10035 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010036}
10037
10038
10039// Collect the raw data for a stack trace. Returns an array of three
10040// element segments each containing a receiver, function and native
10041// code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010042static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010043 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010044 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010045 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10046
10047 HandleScope scope;
10048
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010049 limit = Max(limit, 0); // Ensure that limit is not negative.
10050 int initial_size = Min(limit, 10);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010051 Handle<JSArray> result = Factory::NewJSArray(initial_size * 3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010052
10053 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010054 // If the caller parameter is a function we skip frames until we're
10055 // under it before starting to collect.
10056 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010057 int cursor = 0;
10058 int frames_seen = 0;
10059 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010060 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010061 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010062 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010063 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010064 Object* recv = frame->receiver();
10065 Object* fun = frame->function();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010066 Address pc = frame->pc();
10067 Address start = frame->code()->address();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010068 Smi* offset = Smi::FromInt(static_cast<int>(pc - start));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010069 FixedArray* elements = FixedArray::cast(result->elements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010070 if (cursor + 2 < elements->length()) {
10071 elements->set(cursor++, recv);
10072 elements->set(cursor++, fun);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010073 elements->set(cursor++, offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010074 } else {
10075 HandleScope scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010076 Handle<Object> recv_handle(recv);
10077 Handle<Object> fun_handle(fun);
10078 SetElement(result, cursor++, recv_handle);
10079 SetElement(result, cursor++, fun_handle);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010080 SetElement(result, cursor++, Handle<Smi>(offset));
10081 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010082 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010083 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010084 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010085
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010086 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010087 return *result;
10088}
10089
10090
ager@chromium.org3811b432009-10-28 14:53:37 +000010091// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010092static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010093 ASSERT_EQ(args.length(), 0);
10094
10095 NoHandleAllocation ha;
10096
10097 const char* version_string = v8::V8::GetVersion();
10098
10099 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10100}
10101
10102
lrn@chromium.org303ada72010-10-27 09:33:13 +000010103static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010104 ASSERT(args.length() == 2);
10105 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10106 Smi::cast(args[1])->value());
10107 Top::PrintStack();
10108 OS::Abort();
10109 UNREACHABLE();
10110 return NULL;
10111}
10112
10113
lrn@chromium.org303ada72010-10-27 09:33:13 +000010114MUST_USE_RESULT static MaybeObject* CacheMiss(FixedArray* cache_obj,
10115 int index,
10116 Object* key_obj) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010117 ASSERT(index % 2 == 0); // index of the key
10118 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10119 ASSERT(index < cache_obj->length());
10120
10121 HandleScope scope;
10122
10123 Handle<FixedArray> cache(cache_obj);
10124 Handle<Object> key(key_obj);
10125 Handle<JSFunction> factory(JSFunction::cast(
10126 cache->get(JSFunctionResultCache::kFactoryIndex)));
10127 // TODO(antonm): consider passing a receiver when constructing a cache.
10128 Handle<Object> receiver(Top::global_context()->global());
10129
10130 Handle<Object> value;
10131 {
10132 // This handle is nor shared, nor used later, so it's safe.
10133 Object** argv[] = { key.location() };
10134 bool pending_exception = false;
10135 value = Execution::Call(factory,
10136 receiver,
10137 1,
10138 argv,
10139 &pending_exception);
10140 if (pending_exception) return Failure::Exception();
10141 }
10142
10143 cache->set(index, *key);
10144 cache->set(index + 1, *value);
10145 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index));
10146
10147 return *value;
10148}
10149
10150
lrn@chromium.org303ada72010-10-27 09:33:13 +000010151static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010152 // This is only called from codegen, so checks might be more lax.
10153 CONVERT_CHECKED(FixedArray, cache, args[0]);
10154 Object* key = args[1];
10155
10156 const int finger_index =
10157 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value();
10158
10159 Object* o = cache->get(finger_index);
10160 if (o == key) {
10161 // The fastest case: hit the same place again.
10162 return cache->get(finger_index + 1);
10163 }
10164
10165 for (int i = finger_index - 2;
10166 i >= JSFunctionResultCache::kEntriesIndex;
10167 i -= 2) {
10168 o = cache->get(i);
10169 if (o == key) {
10170 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10171 return cache->get(i + 1);
10172 }
10173 }
10174
10175 const int size =
10176 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value();
10177 ASSERT(size <= cache->length());
10178
10179 for (int i = size - 2; i > finger_index; i -= 2) {
10180 o = cache->get(i);
10181 if (o == key) {
10182 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10183 return cache->get(i + 1);
10184 }
10185 }
10186
10187 // Cache miss. If we have spare room, put new data into it, otherwise
10188 // evict post finger entry which must be least recently used.
10189 if (size < cache->length()) {
10190 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2));
10191 return CacheMiss(cache, size, key);
10192 } else {
antonm@chromium.org397e23c2010-04-21 12:00:05 +000010193 int target_index = finger_index + JSFunctionResultCache::kEntrySize;
10194 if (target_index == cache->length()) {
10195 target_index = JSFunctionResultCache::kEntriesIndex;
10196 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010197 return CacheMiss(cache, target_index, key);
10198 }
10199}
10200
kasper.lund44510672008-07-25 07:37:58 +000010201#ifdef DEBUG
10202// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10203// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010204static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010205 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010206 HandleScope scope;
10207 Handle<JSArray> result = Factory::NewJSArray(0);
10208 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010209 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010210#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010211 { \
10212 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010213 Handle<String> name; \
10214 /* Inline runtime functions have an underscore in front of the name. */ \
10215 if (inline_runtime_functions) { \
10216 name = Factory::NewStringFromAscii( \
10217 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10218 } else { \
10219 name = Factory::NewStringFromAscii( \
10220 Vector<const char>(#Name, StrLength(#Name))); \
10221 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010222 Handle<JSArray> pair = Factory::NewJSArray(0); \
10223 SetElement(pair, 0, name); \
10224 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10225 SetElement(result, index++, pair); \
10226 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010227 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010228 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010229 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010230 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010231 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010232#undef ADD_ENTRY
10233 return *result;
10234}
kasper.lund44510672008-07-25 07:37:58 +000010235#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010236
10237
lrn@chromium.org303ada72010-10-27 09:33:13 +000010238static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010239 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010240 CONVERT_CHECKED(String, format, args[0]);
10241 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010242 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010243 Logger::LogRuntime(chars, elms);
10244 return Heap::undefined_value();
10245}
10246
10247
lrn@chromium.org303ada72010-10-27 09:33:13 +000010248static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249 UNREACHABLE(); // implemented as macro in the parser
10250 return NULL;
10251}
10252
10253
10254// ----------------------------------------------------------------------------
10255// Implementation of Runtime
10256
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010257#define F(name, number_of_args, result_size) \
10258 { Runtime::k##name, Runtime::RUNTIME, #name, \
10259 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010260
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010261
10262#define I(name, number_of_args, result_size) \
10263 { Runtime::kInline##name, Runtime::INLINE, \
10264 "_" #name, NULL, number_of_args, result_size },
10265
10266Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010268 INLINE_FUNCTION_LIST(I)
10269 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010270};
10271
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272
lrn@chromium.org303ada72010-10-27 09:33:13 +000010273MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010274 ASSERT(dictionary != NULL);
10275 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10276 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010277 Object* name_symbol;
10278 { MaybeObject* maybe_name_symbol =
10279 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10280 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
10281 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010282 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010283 { MaybeObject* maybe_dictionary = string_dictionary->Add(
10284 String::cast(name_symbol),
10285 Smi::FromInt(i),
10286 PropertyDetails(NONE, NORMAL));
10287 if (!maybe_dictionary->ToObject(&dictionary)) {
10288 // Non-recoverable failure. Calling code must restart heap
10289 // initialization.
10290 return maybe_dictionary;
10291 }
10292 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010293 }
10294 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010295}
10296
10297
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010298Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10299 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10300 if (entry != kNotFound) {
10301 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10302 int function_index = Smi::cast(smi_index)->value();
10303 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010304 }
10305 return NULL;
10306}
10307
10308
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010309Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10310 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10311}
10312
10313
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010314void Runtime::PerformGC(Object* result) {
10315 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010316 if (failure->IsRetryAfterGC()) {
10317 // Try to do a garbage collection; ignore it if it fails. The C
10318 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010319 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010320 } else {
10321 // Handle last resort GC and make sure to allow future allocations
10322 // to grow the heap without causing GCs (if possible).
10323 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010324 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010325 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010326}
10327
10328
10329} } // namespace v8::internal