blob: c43a1ab327c5e4952f454b2bb5d20f070e1fcb30 [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;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005023 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005024 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005025 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005026
5027 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005028 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005029
5030 Handle<FixedArray> elements;
5031 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005032 Object* obj;
5033 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5034 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5035 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005036 elements = Handle<FixedArray>(FixedArray::cast(obj));
5037
5038 Vector<const char> chars = s->ToAsciiVector();
5039 // Note, this will initialize all elements (not only the prefix)
5040 // to prevent GC from seeing partially initialized array.
5041 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5042 *elements,
5043 length);
5044
5045 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005046 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5047 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005048 }
5049 } else {
5050 elements = Factory::NewFixedArray(length);
5051 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005052 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5053 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005054 }
5055 }
5056
5057#ifdef DEBUG
5058 for (int i = 0; i < length; ++i) {
5059 ASSERT(String::cast(elements->get(i))->length() == 1);
5060 }
5061#endif
5062
5063 return *Factory::NewJSArrayWithElements(elements);
5064}
5065
5066
lrn@chromium.org303ada72010-10-27 09:33:13 +00005067static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005068 NoHandleAllocation ha;
5069 ASSERT(args.length() == 1);
5070 CONVERT_CHECKED(String, value, args[0]);
5071 return value->ToObject();
5072}
5073
5074
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005075bool Runtime::IsUpperCaseChar(uint16_t ch) {
5076 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5077 int char_length = to_upper_mapping.get(ch, 0, chars);
5078 return char_length == 0;
5079}
5080
5081
lrn@chromium.org303ada72010-10-27 09:33:13 +00005082static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005083 NoHandleAllocation ha;
5084 ASSERT(args.length() == 1);
5085
5086 Object* number = args[0];
5087 RUNTIME_ASSERT(number->IsNumber());
5088
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005089 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005090}
5091
5092
lrn@chromium.org303ada72010-10-27 09:33:13 +00005093static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005094 NoHandleAllocation ha;
5095 ASSERT(args.length() == 1);
5096
5097 Object* number = args[0];
5098 RUNTIME_ASSERT(number->IsNumber());
5099
5100 return Heap::NumberToString(number, false);
5101}
5102
5103
lrn@chromium.org303ada72010-10-27 09:33:13 +00005104static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005105 NoHandleAllocation ha;
5106 ASSERT(args.length() == 1);
5107
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005108 CONVERT_DOUBLE_CHECKED(number, args[0]);
5109
5110 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5111 if (number > 0 && number <= Smi::kMaxValue) {
5112 return Smi::FromInt(static_cast<int>(number));
5113 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005114 return Heap::NumberFromDouble(DoubleToInteger(number));
5115}
5116
5117
lrn@chromium.org303ada72010-10-27 09:33:13 +00005118static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005119 NoHandleAllocation ha;
5120 ASSERT(args.length() == 1);
5121
5122 CONVERT_DOUBLE_CHECKED(number, args[0]);
5123
5124 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5125 if (number > 0 && number <= Smi::kMaxValue) {
5126 return Smi::FromInt(static_cast<int>(number));
5127 }
5128
5129 double double_value = DoubleToInteger(number);
5130 // Map both -0 and +0 to +0.
5131 if (double_value == 0) double_value = 0;
5132
5133 return Heap::NumberFromDouble(double_value);
5134}
5135
5136
lrn@chromium.org303ada72010-10-27 09:33:13 +00005137static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005138 NoHandleAllocation ha;
5139 ASSERT(args.length() == 1);
5140
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005141 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005142 return Heap::NumberFromUint32(number);
5143}
5144
5145
lrn@chromium.org303ada72010-10-27 09:33:13 +00005146static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005147 NoHandleAllocation ha;
5148 ASSERT(args.length() == 1);
5149
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005150 CONVERT_DOUBLE_CHECKED(number, args[0]);
5151
5152 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5153 if (number > 0 && number <= Smi::kMaxValue) {
5154 return Smi::FromInt(static_cast<int>(number));
5155 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005156 return Heap::NumberFromInt32(DoubleToInt32(number));
5157}
5158
5159
ager@chromium.org870a0b62008-11-04 11:43:05 +00005160// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5161// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005162static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005163 NoHandleAllocation ha;
5164 ASSERT(args.length() == 1);
5165
5166 Object* obj = args[0];
5167 if (obj->IsSmi()) {
5168 return obj;
5169 }
5170 if (obj->IsHeapNumber()) {
5171 double value = HeapNumber::cast(obj)->value();
5172 int int_value = FastD2I(value);
5173 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5174 return Smi::FromInt(int_value);
5175 }
5176 }
5177 return Heap::nan_value();
5178}
5179
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005180
lrn@chromium.org303ada72010-10-27 09:33:13 +00005181static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005182 NoHandleAllocation ha;
5183 ASSERT(args.length() == 2);
5184
5185 CONVERT_DOUBLE_CHECKED(x, args[0]);
5186 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005187 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005188}
5189
5190
lrn@chromium.org303ada72010-10-27 09:33:13 +00005191static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005192 NoHandleAllocation ha;
5193 ASSERT(args.length() == 2);
5194
5195 CONVERT_DOUBLE_CHECKED(x, args[0]);
5196 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005197 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198}
5199
5200
lrn@chromium.org303ada72010-10-27 09:33:13 +00005201static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202 NoHandleAllocation ha;
5203 ASSERT(args.length() == 2);
5204
5205 CONVERT_DOUBLE_CHECKED(x, args[0]);
5206 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005207 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208}
5209
5210
lrn@chromium.org303ada72010-10-27 09:33:13 +00005211static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005212 NoHandleAllocation ha;
5213 ASSERT(args.length() == 1);
5214
5215 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005216 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005217}
5218
5219
lrn@chromium.org303ada72010-10-27 09:33:13 +00005220static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005221 NoHandleAllocation ha;
5222 ASSERT(args.length() == 0);
5223
5224 return Heap::NumberFromDouble(9876543210.0);
5225}
5226
5227
lrn@chromium.org303ada72010-10-27 09:33:13 +00005228static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005229 NoHandleAllocation ha;
5230 ASSERT(args.length() == 2);
5231
5232 CONVERT_DOUBLE_CHECKED(x, args[0]);
5233 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005234 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005235}
5236
5237
lrn@chromium.org303ada72010-10-27 09:33:13 +00005238static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005239 NoHandleAllocation ha;
5240 ASSERT(args.length() == 2);
5241
5242 CONVERT_DOUBLE_CHECKED(x, args[0]);
5243 CONVERT_DOUBLE_CHECKED(y, args[1]);
5244
ager@chromium.org3811b432009-10-28 14:53:37 +00005245 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005246 // NumberFromDouble may return a Smi instead of a Number object
5247 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248}
5249
5250
lrn@chromium.org303ada72010-10-27 09:33:13 +00005251static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005252 NoHandleAllocation ha;
5253 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005254 CONVERT_CHECKED(String, str1, args[0]);
5255 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005256 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005257 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005258}
5259
5260
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005261template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005262static inline void StringBuilderConcatHelper(String* special,
5263 sinkchar* sink,
5264 FixedArray* fixed_array,
5265 int array_length) {
5266 int position = 0;
5267 for (int i = 0; i < array_length; i++) {
5268 Object* element = fixed_array->get(i);
5269 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005270 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005271 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005272 int pos;
5273 int len;
5274 if (encoded_slice > 0) {
5275 // Position and length encoded in one smi.
5276 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5277 len = StringBuilderSubstringLength::decode(encoded_slice);
5278 } else {
5279 // Position and length encoded in two smis.
5280 Object* obj = fixed_array->get(++i);
5281 ASSERT(obj->IsSmi());
5282 pos = Smi::cast(obj)->value();
5283 len = -encoded_slice;
5284 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005285 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005286 sink + position,
5287 pos,
5288 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005289 position += len;
5290 } else {
5291 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005292 int element_length = string->length();
5293 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005294 position += element_length;
5295 }
5296 }
5297}
5298
5299
lrn@chromium.org303ada72010-10-27 09:33:13 +00005300static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005301 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005302 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005303 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005304 if (!args[1]->IsSmi()) {
5305 Top::context()->mark_out_of_memory();
5306 return Failure::OutOfMemoryException();
5307 }
5308 int array_length = Smi::cast(args[1])->value();
5309 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005310
5311 // This assumption is used by the slice encoding in one or two smis.
5312 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5313
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005314 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315 if (!array->HasFastElements()) {
5316 return Top::Throw(Heap::illegal_argument_symbol());
5317 }
5318 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005319 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005320 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005321 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005322
5323 if (array_length == 0) {
5324 return Heap::empty_string();
5325 } else if (array_length == 1) {
5326 Object* first = fixed_array->get(0);
5327 if (first->IsString()) return first;
5328 }
5329
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005330 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005331 int position = 0;
5332 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005333 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005334 Object* elt = fixed_array->get(i);
5335 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005336 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005337 int smi_value = Smi::cast(elt)->value();
5338 int pos;
5339 int len;
5340 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005341 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005342 pos = StringBuilderSubstringPosition::decode(smi_value);
5343 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005344 } else {
5345 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005346 len = -smi_value;
5347 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005348 i++;
5349 if (i >= array_length) {
5350 return Top::Throw(Heap::illegal_argument_symbol());
5351 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005352 Object* next_smi = fixed_array->get(i);
5353 if (!next_smi->IsSmi()) {
5354 return Top::Throw(Heap::illegal_argument_symbol());
5355 }
5356 pos = Smi::cast(next_smi)->value();
5357 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005358 return Top::Throw(Heap::illegal_argument_symbol());
5359 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005360 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005361 ASSERT(pos >= 0);
5362 ASSERT(len >= 0);
5363 if (pos > special_length || len > special_length - pos) {
5364 return Top::Throw(Heap::illegal_argument_symbol());
5365 }
5366 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005367 } else if (elt->IsString()) {
5368 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005369 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005370 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005371 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005372 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005373 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005374 } else {
5375 return Top::Throw(Heap::illegal_argument_symbol());
5376 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005377 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005378 Top::context()->mark_out_of_memory();
5379 return Failure::OutOfMemoryException();
5380 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005381 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005382 }
5383
5384 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005385 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005386
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005387 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005388 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5389 if (!maybe_object->ToObject(&object)) return maybe_object;
5390 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005391 SeqAsciiString* answer = SeqAsciiString::cast(object);
5392 StringBuilderConcatHelper(special,
5393 answer->GetChars(),
5394 fixed_array,
5395 array_length);
5396 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005398 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5399 if (!maybe_object->ToObject(&object)) return maybe_object;
5400 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005401 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5402 StringBuilderConcatHelper(special,
5403 answer->GetChars(),
5404 fixed_array,
5405 array_length);
5406 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005408}
5409
5410
lrn@chromium.org303ada72010-10-27 09:33:13 +00005411static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412 NoHandleAllocation ha;
5413 ASSERT(args.length() == 2);
5414
5415 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5416 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5417 return Heap::NumberFromInt32(x | y);
5418}
5419
5420
lrn@chromium.org303ada72010-10-27 09:33:13 +00005421static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005422 NoHandleAllocation ha;
5423 ASSERT(args.length() == 2);
5424
5425 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5426 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5427 return Heap::NumberFromInt32(x & y);
5428}
5429
5430
lrn@chromium.org303ada72010-10-27 09:33:13 +00005431static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005432 NoHandleAllocation ha;
5433 ASSERT(args.length() == 2);
5434
5435 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5436 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5437 return Heap::NumberFromInt32(x ^ y);
5438}
5439
5440
lrn@chromium.org303ada72010-10-27 09:33:13 +00005441static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005442 NoHandleAllocation ha;
5443 ASSERT(args.length() == 1);
5444
5445 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5446 return Heap::NumberFromInt32(~x);
5447}
5448
5449
lrn@chromium.org303ada72010-10-27 09:33:13 +00005450static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005451 NoHandleAllocation ha;
5452 ASSERT(args.length() == 2);
5453
5454 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5455 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5456 return Heap::NumberFromInt32(x << (y & 0x1f));
5457}
5458
5459
lrn@chromium.org303ada72010-10-27 09:33:13 +00005460static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461 NoHandleAllocation ha;
5462 ASSERT(args.length() == 2);
5463
5464 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5465 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5466 return Heap::NumberFromUint32(x >> (y & 0x1f));
5467}
5468
5469
lrn@chromium.org303ada72010-10-27 09:33:13 +00005470static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005471 NoHandleAllocation ha;
5472 ASSERT(args.length() == 2);
5473
5474 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5475 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5476 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5477}
5478
5479
lrn@chromium.org303ada72010-10-27 09:33:13 +00005480static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005481 NoHandleAllocation ha;
5482 ASSERT(args.length() == 2);
5483
5484 CONVERT_DOUBLE_CHECKED(x, args[0]);
5485 CONVERT_DOUBLE_CHECKED(y, args[1]);
5486 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5487 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5488 if (x == y) return Smi::FromInt(EQUAL);
5489 Object* result;
5490 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5491 result = Smi::FromInt(EQUAL);
5492 } else {
5493 result = Smi::FromInt(NOT_EQUAL);
5494 }
5495 return result;
5496}
5497
5498
lrn@chromium.org303ada72010-10-27 09:33:13 +00005499static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005500 NoHandleAllocation ha;
5501 ASSERT(args.length() == 2);
5502
5503 CONVERT_CHECKED(String, x, args[0]);
5504 CONVERT_CHECKED(String, y, args[1]);
5505
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005506 bool not_equal = !x->Equals(y);
5507 // This is slightly convoluted because the value that signifies
5508 // equality is 0 and inequality is 1 so we have to negate the result
5509 // from String::Equals.
5510 ASSERT(not_equal == 0 || not_equal == 1);
5511 STATIC_CHECK(EQUAL == 0);
5512 STATIC_CHECK(NOT_EQUAL == 1);
5513 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005514}
5515
5516
lrn@chromium.org303ada72010-10-27 09:33:13 +00005517static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005518 NoHandleAllocation ha;
5519 ASSERT(args.length() == 3);
5520
5521 CONVERT_DOUBLE_CHECKED(x, args[0]);
5522 CONVERT_DOUBLE_CHECKED(y, args[1]);
5523 if (isnan(x) || isnan(y)) return args[2];
5524 if (x == y) return Smi::FromInt(EQUAL);
5525 if (isless(x, y)) return Smi::FromInt(LESS);
5526 return Smi::FromInt(GREATER);
5527}
5528
5529
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005530// Compare two Smis as if they were converted to strings and then
5531// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005532static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005533 NoHandleAllocation ha;
5534 ASSERT(args.length() == 2);
5535
5536 // Arrays for the individual characters of the two Smis. Smis are
5537 // 31 bit integers and 10 decimal digits are therefore enough.
5538 static int x_elms[10];
5539 static int y_elms[10];
5540
5541 // Extract the integer values from the Smis.
5542 CONVERT_CHECKED(Smi, x, args[0]);
5543 CONVERT_CHECKED(Smi, y, args[1]);
5544 int x_value = x->value();
5545 int y_value = y->value();
5546
5547 // If the integers are equal so are the string representations.
5548 if (x_value == y_value) return Smi::FromInt(EQUAL);
5549
5550 // If one of the integers are zero the normal integer order is the
5551 // same as the lexicographic order of the string representations.
5552 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5553
ager@chromium.org32912102009-01-16 10:38:43 +00005554 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005555 // smallest because the char code of '-' is less than the char code
5556 // of any digit. Otherwise, we make both values positive.
5557 if (x_value < 0 || y_value < 0) {
5558 if (y_value >= 0) return Smi::FromInt(LESS);
5559 if (x_value >= 0) return Smi::FromInt(GREATER);
5560 x_value = -x_value;
5561 y_value = -y_value;
5562 }
5563
5564 // Convert the integers to arrays of their decimal digits.
5565 int x_index = 0;
5566 int y_index = 0;
5567 while (x_value > 0) {
5568 x_elms[x_index++] = x_value % 10;
5569 x_value /= 10;
5570 }
5571 while (y_value > 0) {
5572 y_elms[y_index++] = y_value % 10;
5573 y_value /= 10;
5574 }
5575
5576 // Loop through the arrays of decimal digits finding the first place
5577 // where they differ.
5578 while (--x_index >= 0 && --y_index >= 0) {
5579 int diff = x_elms[x_index] - y_elms[y_index];
5580 if (diff != 0) return Smi::FromInt(diff);
5581 }
5582
5583 // If one array is a suffix of the other array, the longest array is
5584 // the representation of the largest of the Smis in the
5585 // lexicographic ordering.
5586 return Smi::FromInt(x_index - y_index);
5587}
5588
5589
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005590static Object* StringInputBufferCompare(String* x, String* y) {
5591 static StringInputBuffer bufx;
5592 static StringInputBuffer bufy;
5593 bufx.Reset(x);
5594 bufy.Reset(y);
5595 while (bufx.has_more() && bufy.has_more()) {
5596 int d = bufx.GetNext() - bufy.GetNext();
5597 if (d < 0) return Smi::FromInt(LESS);
5598 else if (d > 0) return Smi::FromInt(GREATER);
5599 }
5600
5601 // x is (non-trivial) prefix of y:
5602 if (bufy.has_more()) return Smi::FromInt(LESS);
5603 // y is prefix of x:
5604 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5605}
5606
5607
5608static Object* FlatStringCompare(String* x, String* y) {
5609 ASSERT(x->IsFlat());
5610 ASSERT(y->IsFlat());
5611 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5612 int prefix_length = x->length();
5613 if (y->length() < prefix_length) {
5614 prefix_length = y->length();
5615 equal_prefix_result = Smi::FromInt(GREATER);
5616 } else if (y->length() > prefix_length) {
5617 equal_prefix_result = Smi::FromInt(LESS);
5618 }
5619 int r;
5620 if (x->IsAsciiRepresentation()) {
5621 Vector<const char> x_chars = x->ToAsciiVector();
5622 if (y->IsAsciiRepresentation()) {
5623 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005624 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005625 } else {
5626 Vector<const uc16> y_chars = y->ToUC16Vector();
5627 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5628 }
5629 } else {
5630 Vector<const uc16> x_chars = x->ToUC16Vector();
5631 if (y->IsAsciiRepresentation()) {
5632 Vector<const char> y_chars = y->ToAsciiVector();
5633 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5634 } else {
5635 Vector<const uc16> y_chars = y->ToUC16Vector();
5636 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5637 }
5638 }
5639 Object* result;
5640 if (r == 0) {
5641 result = equal_prefix_result;
5642 } else {
5643 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5644 }
5645 ASSERT(result == StringInputBufferCompare(x, y));
5646 return result;
5647}
5648
5649
lrn@chromium.org303ada72010-10-27 09:33:13 +00005650static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005651 NoHandleAllocation ha;
5652 ASSERT(args.length() == 2);
5653
5654 CONVERT_CHECKED(String, x, args[0]);
5655 CONVERT_CHECKED(String, y, args[1]);
5656
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005657 Counters::string_compare_runtime.Increment();
5658
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005659 // A few fast case tests before we flatten.
5660 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005661 if (y->length() == 0) {
5662 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005663 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005664 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005665 return Smi::FromInt(LESS);
5666 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005667
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005668 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005669 if (d < 0) return Smi::FromInt(LESS);
5670 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005671
lrn@chromium.org303ada72010-10-27 09:33:13 +00005672 Object* obj;
5673 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
5674 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5675 }
5676 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
5677 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5678 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005679
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005680 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5681 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005682}
5683
5684
lrn@chromium.org303ada72010-10-27 09:33:13 +00005685static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005686 NoHandleAllocation ha;
5687 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005688 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005689
5690 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005691 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005692}
5693
5694
lrn@chromium.org303ada72010-10-27 09:33:13 +00005695static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005696 NoHandleAllocation ha;
5697 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005698 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005699
5700 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005701 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005702}
5703
5704
lrn@chromium.org303ada72010-10-27 09:33:13 +00005705static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005706 NoHandleAllocation ha;
5707 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005708 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005709
5710 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005711 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005712}
5713
5714
lrn@chromium.org303ada72010-10-27 09:33:13 +00005715static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005716 NoHandleAllocation ha;
5717 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005718 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005719
5720 CONVERT_DOUBLE_CHECKED(x, args[0]);
5721 CONVERT_DOUBLE_CHECKED(y, args[1]);
5722 double result;
5723 if (isinf(x) && isinf(y)) {
5724 // Make sure that the result in case of two infinite arguments
5725 // is a multiple of Pi / 4. The sign of the result is determined
5726 // by the first argument (x) and the sign of the second argument
5727 // determines the multiplier: one or three.
5728 static double kPiDividedBy4 = 0.78539816339744830962;
5729 int multiplier = (x < 0) ? -1 : 1;
5730 if (y < 0) multiplier *= 3;
5731 result = multiplier * kPiDividedBy4;
5732 } else {
5733 result = atan2(x, y);
5734 }
5735 return Heap::AllocateHeapNumber(result);
5736}
5737
5738
lrn@chromium.org303ada72010-10-27 09:33:13 +00005739static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005740 NoHandleAllocation ha;
5741 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005742 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005743
5744 CONVERT_DOUBLE_CHECKED(x, args[0]);
5745 return Heap::NumberFromDouble(ceiling(x));
5746}
5747
5748
lrn@chromium.org303ada72010-10-27 09:33:13 +00005749static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005750 NoHandleAllocation ha;
5751 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005752 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005753
5754 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005755 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005756}
5757
5758
lrn@chromium.org303ada72010-10-27 09:33:13 +00005759static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005760 NoHandleAllocation ha;
5761 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005762 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005763
5764 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005765 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005766}
5767
5768
lrn@chromium.org303ada72010-10-27 09:33:13 +00005769static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005770 NoHandleAllocation ha;
5771 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005772 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005773
5774 CONVERT_DOUBLE_CHECKED(x, args[0]);
5775 return Heap::NumberFromDouble(floor(x));
5776}
5777
5778
lrn@chromium.org303ada72010-10-27 09:33:13 +00005779static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005780 NoHandleAllocation ha;
5781 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005782 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005783
5784 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005785 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005786}
5787
5788
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005789// Helper function to compute x^y, where y is known to be an
5790// integer. Uses binary decomposition to limit the number of
5791// multiplications; see the discussion in "Hacker's Delight" by Henry
5792// S. Warren, Jr., figure 11-6, page 213.
5793static double powi(double x, int y) {
5794 ASSERT(y != kMinInt);
5795 unsigned n = (y < 0) ? -y : y;
5796 double m = x;
5797 double p = 1;
5798 while (true) {
5799 if ((n & 1) != 0) p *= m;
5800 n >>= 1;
5801 if (n == 0) {
5802 if (y < 0) {
5803 // Unfortunately, we have to be careful when p has reached
5804 // infinity in the computation, because sometimes the higher
5805 // internal precision in the pow() implementation would have
5806 // given us a finite p. This happens very rarely.
5807 double result = 1.0 / p;
5808 return (result == 0 && isinf(p))
5809 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
5810 : result;
5811 } else {
5812 return p;
5813 }
5814 }
5815 m *= m;
5816 }
5817}
5818
5819
lrn@chromium.org303ada72010-10-27 09:33:13 +00005820static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005821 NoHandleAllocation ha;
5822 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005823 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005824
5825 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005826
5827 // If the second argument is a smi, it is much faster to call the
5828 // custom powi() function than the generic pow().
5829 if (args[1]->IsSmi()) {
5830 int y = Smi::cast(args[1])->value();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005831 return Heap::NumberFromDouble(powi(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005832 }
5833
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005834 CONVERT_DOUBLE_CHECKED(y, args[1]);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005835
5836 if (!isinf(x)) {
5837 if (y == 0.5) {
5838 // It's not uncommon to use Math.pow(x, 0.5) to compute the
5839 // square root of a number. To speed up such computations, we
5840 // explictly check for this case and use the sqrt() function
5841 // which is faster than pow().
5842 return Heap::AllocateHeapNumber(sqrt(x));
5843 } else if (y == -0.5) {
5844 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
5845 return Heap::AllocateHeapNumber(1.0 / sqrt(x));
5846 }
5847 }
5848
5849 if (y == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005850 return Smi::FromInt(1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005851 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5852 return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005853 } else {
5854 return Heap::AllocateHeapNumber(pow(x, y));
5855 }
5856}
5857
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005858// Fast version of Math.pow if we know that y is not an integer and
5859// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005860static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005861 NoHandleAllocation ha;
5862 ASSERT(args.length() == 2);
5863 CONVERT_DOUBLE_CHECKED(x, args[0]);
5864 CONVERT_DOUBLE_CHECKED(y, args[1]);
5865 if (y == 0) {
5866 return Smi::FromInt(1);
5867 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5868 return Heap::nan_value();
5869 } else {
5870 return Heap::AllocateHeapNumber(pow(x, y));
5871 }
5872}
5873
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005874
lrn@chromium.org303ada72010-10-27 09:33:13 +00005875static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005876 NoHandleAllocation ha;
5877 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005878 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005879
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005880 if (!args[0]->IsHeapNumber()) {
5881 // Must be smi. Return the argument unchanged for all the other types
5882 // to make fuzz-natives test happy.
5883 return args[0];
5884 }
5885
5886 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
5887
5888 double value = number->value();
5889 int exponent = number->get_exponent();
5890 int sign = number->get_sign();
5891
5892 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
5893 // should be rounded to 2^30, which is not smi.
5894 if (!sign && exponent <= kSmiValueSize - 3) {
5895 return Smi::FromInt(static_cast<int>(value + 0.5));
5896 }
5897
5898 // If the magnitude is big enough, there's no place for fraction part. If we
5899 // try to add 0.5 to this number, 1.0 will be added instead.
5900 if (exponent >= 52) {
5901 return number;
5902 }
5903
5904 if (sign && value >= -0.5) return Heap::minus_zero_value();
5905
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005906 // Do not call NumberFromDouble() to avoid extra checks.
5907 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005908}
5909
5910
lrn@chromium.org303ada72010-10-27 09:33:13 +00005911static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005912 NoHandleAllocation ha;
5913 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005914 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005915
5916 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005917 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918}
5919
5920
lrn@chromium.org303ada72010-10-27 09:33:13 +00005921static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922 NoHandleAllocation ha;
5923 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005924 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005925
5926 CONVERT_DOUBLE_CHECKED(x, args[0]);
5927 return Heap::AllocateHeapNumber(sqrt(x));
5928}
5929
5930
lrn@chromium.org303ada72010-10-27 09:33:13 +00005931static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005932 NoHandleAllocation ha;
5933 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005934 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005935
5936 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005937 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938}
5939
5940
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005941static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005942 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
5943 181, 212, 243, 273, 304, 334};
5944 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
5945 182, 213, 244, 274, 305, 335};
5946
5947 year += month / 12;
5948 month %= 12;
5949 if (month < 0) {
5950 year--;
5951 month += 12;
5952 }
5953
5954 ASSERT(month >= 0);
5955 ASSERT(month < 12);
5956
5957 // year_delta is an arbitrary number such that:
5958 // a) year_delta = -1 (mod 400)
5959 // b) year + year_delta > 0 for years in the range defined by
5960 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
5961 // Jan 1 1970. This is required so that we don't run into integer
5962 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005963 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005964 // operations.
5965 static const int year_delta = 399999;
5966 static const int base_day = 365 * (1970 + year_delta) +
5967 (1970 + year_delta) / 4 -
5968 (1970 + year_delta) / 100 +
5969 (1970 + year_delta) / 400;
5970
5971 int year1 = year + year_delta;
5972 int day_from_year = 365 * year1 +
5973 year1 / 4 -
5974 year1 / 100 +
5975 year1 / 400 -
5976 base_day;
5977
5978 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005979 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005980 }
5981
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005982 return day_from_year + day_from_month_leap[month] + day - 1;
5983}
5984
5985
lrn@chromium.org303ada72010-10-27 09:33:13 +00005986static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005987 NoHandleAllocation ha;
5988 ASSERT(args.length() == 3);
5989
5990 CONVERT_SMI_CHECKED(year, args[0]);
5991 CONVERT_SMI_CHECKED(month, args[1]);
5992 CONVERT_SMI_CHECKED(date, args[2]);
5993
5994 return Smi::FromInt(MakeDay(year, month, date));
5995}
5996
5997
5998static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
5999static const int kDaysIn4Years = 4 * 365 + 1;
6000static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6001static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6002static const int kDays1970to2000 = 30 * 365 + 7;
6003static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6004 kDays1970to2000;
6005static const int kYearsOffset = 400000;
6006
6007static const char kDayInYear[] = {
6008 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6009 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6010 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6011 22, 23, 24, 25, 26, 27, 28,
6012 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6013 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6014 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6015 22, 23, 24, 25, 26, 27, 28, 29, 30,
6016 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6017 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6018 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6019 22, 23, 24, 25, 26, 27, 28, 29, 30,
6020 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6021 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6022 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6023 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6024 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6025 22, 23, 24, 25, 26, 27, 28, 29, 30,
6026 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6027 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6028 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6029 22, 23, 24, 25, 26, 27, 28, 29, 30,
6030 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6031 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6032
6033 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6034 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6035 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6036 22, 23, 24, 25, 26, 27, 28,
6037 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6038 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6039 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6040 22, 23, 24, 25, 26, 27, 28, 29, 30,
6041 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6042 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6043 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6044 22, 23, 24, 25, 26, 27, 28, 29, 30,
6045 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6046 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6047 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6048 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6049 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6050 22, 23, 24, 25, 26, 27, 28, 29, 30,
6051 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6052 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6053 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6054 22, 23, 24, 25, 26, 27, 28, 29, 30,
6055 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6056 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6057
6058 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6059 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6060 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6061 22, 23, 24, 25, 26, 27, 28, 29,
6062 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6063 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6064 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6065 22, 23, 24, 25, 26, 27, 28, 29, 30,
6066 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6067 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6068 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6069 22, 23, 24, 25, 26, 27, 28, 29, 30,
6070 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6071 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6072 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6073 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6074 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6075 22, 23, 24, 25, 26, 27, 28, 29, 30,
6076 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6077 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6078 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6079 22, 23, 24, 25, 26, 27, 28, 29, 30,
6080 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6081 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6082
6083 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6084 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6085 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6086 22, 23, 24, 25, 26, 27, 28,
6087 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6088 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6089 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6090 22, 23, 24, 25, 26, 27, 28, 29, 30,
6091 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6092 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6093 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6094 22, 23, 24, 25, 26, 27, 28, 29, 30,
6095 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6096 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6097 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6098 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6099 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6100 22, 23, 24, 25, 26, 27, 28, 29, 30,
6101 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6102 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6103 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6104 22, 23, 24, 25, 26, 27, 28, 29, 30,
6105 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6106 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6107
6108static const char kMonthInYear[] = {
6109 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,
6110 0, 0, 0, 0, 0, 0,
6111 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,
6112 1, 1, 1,
6113 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,
6114 2, 2, 2, 2, 2, 2,
6115 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,
6116 3, 3, 3, 3, 3,
6117 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,
6118 4, 4, 4, 4, 4, 4,
6119 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,
6120 5, 5, 5, 5, 5,
6121 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,
6122 6, 6, 6, 6, 6, 6,
6123 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,
6124 7, 7, 7, 7, 7, 7,
6125 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,
6126 8, 8, 8, 8, 8,
6127 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,
6128 9, 9, 9, 9, 9, 9,
6129 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6130 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6131 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6132 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6133
6134 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,
6135 0, 0, 0, 0, 0, 0,
6136 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,
6137 1, 1, 1,
6138 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,
6139 2, 2, 2, 2, 2, 2,
6140 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,
6141 3, 3, 3, 3, 3,
6142 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,
6143 4, 4, 4, 4, 4, 4,
6144 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,
6145 5, 5, 5, 5, 5,
6146 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,
6147 6, 6, 6, 6, 6, 6,
6148 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,
6149 7, 7, 7, 7, 7, 7,
6150 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,
6151 8, 8, 8, 8, 8,
6152 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,
6153 9, 9, 9, 9, 9, 9,
6154 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6155 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6156 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6157 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6158
6159 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,
6160 0, 0, 0, 0, 0, 0,
6161 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,
6162 1, 1, 1, 1,
6163 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,
6164 2, 2, 2, 2, 2, 2,
6165 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,
6166 3, 3, 3, 3, 3,
6167 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,
6168 4, 4, 4, 4, 4, 4,
6169 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,
6170 5, 5, 5, 5, 5,
6171 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,
6172 6, 6, 6, 6, 6, 6,
6173 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,
6174 7, 7, 7, 7, 7, 7,
6175 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,
6176 8, 8, 8, 8, 8,
6177 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,
6178 9, 9, 9, 9, 9, 9,
6179 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6180 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6181 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6182 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6183
6184 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,
6185 0, 0, 0, 0, 0, 0,
6186 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,
6187 1, 1, 1,
6188 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,
6189 2, 2, 2, 2, 2, 2,
6190 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,
6191 3, 3, 3, 3, 3,
6192 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,
6193 4, 4, 4, 4, 4, 4,
6194 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,
6195 5, 5, 5, 5, 5,
6196 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,
6197 6, 6, 6, 6, 6, 6,
6198 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,
6199 7, 7, 7, 7, 7, 7,
6200 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,
6201 8, 8, 8, 8, 8,
6202 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,
6203 9, 9, 9, 9, 9, 9,
6204 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6205 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6206 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6207 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6208
6209
6210// This function works for dates from 1970 to 2099.
6211static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006212 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006213#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006214 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006215#endif
6216
6217 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6218 date %= kDaysIn4Years;
6219
6220 month = kMonthInYear[date];
6221 day = kDayInYear[date];
6222
6223 ASSERT(MakeDay(year, month, day) == save_date);
6224}
6225
6226
6227static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006228 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006229#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006230 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006231#endif
6232
6233 date += kDaysOffset;
6234 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6235 date %= kDaysIn400Years;
6236
6237 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6238
6239 date--;
6240 int yd1 = date / kDaysIn100Years;
6241 date %= kDaysIn100Years;
6242 year += 100 * yd1;
6243
6244 date++;
6245 int yd2 = date / kDaysIn4Years;
6246 date %= kDaysIn4Years;
6247 year += 4 * yd2;
6248
6249 date--;
6250 int yd3 = date / 365;
6251 date %= 365;
6252 year += yd3;
6253
6254 bool is_leap = (!yd1 || yd2) && !yd3;
6255
6256 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006257 ASSERT(is_leap || (date >= 0));
6258 ASSERT((date < 365) || (is_leap && (date < 366)));
6259 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6260 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6261 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006262
6263 if (is_leap) {
6264 day = kDayInYear[2*365 + 1 + date];
6265 month = kMonthInYear[2*365 + 1 + date];
6266 } else {
6267 day = kDayInYear[date];
6268 month = kMonthInYear[date];
6269 }
6270
6271 ASSERT(MakeDay(year, month, day) == save_date);
6272}
6273
6274
6275static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006276 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006277 if (date >= 0 && date < 32 * kDaysIn4Years) {
6278 DateYMDFromTimeAfter1970(date, year, month, day);
6279 } else {
6280 DateYMDFromTimeSlow(date, year, month, day);
6281 }
6282}
6283
6284
lrn@chromium.org303ada72010-10-27 09:33:13 +00006285static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006286 NoHandleAllocation ha;
6287 ASSERT(args.length() == 2);
6288
6289 CONVERT_DOUBLE_CHECKED(t, args[0]);
6290 CONVERT_CHECKED(JSArray, res_array, args[1]);
6291
6292 int year, month, day;
6293 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6294
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006295 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6296 FixedArray* elms = FixedArray::cast(res_array->elements());
6297 RUNTIME_ASSERT(elms->length() == 3);
6298
6299 elms->set(0, Smi::FromInt(year));
6300 elms->set(1, Smi::FromInt(month));
6301 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006302
6303 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006304}
6305
6306
lrn@chromium.org303ada72010-10-27 09:33:13 +00006307static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006308 NoHandleAllocation ha;
6309 ASSERT(args.length() == 3);
6310
6311 JSFunction* callee = JSFunction::cast(args[0]);
6312 Object** parameters = reinterpret_cast<Object**>(args[1]);
6313 const int length = Smi::cast(args[2])->value();
6314
lrn@chromium.org303ada72010-10-27 09:33:13 +00006315 Object* result;
6316 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6317 if (!maybe_result->ToObject(&result)) return maybe_result;
6318 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006319 // Allocate the elements if needed.
6320 if (length > 0) {
6321 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006322 Object* obj;
6323 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6324 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6325 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006326
6327 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006328 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6329 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006330 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006331
6332 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006333 for (int i = 0; i < length; i++) {
6334 array->set(i, *--parameters, mode);
6335 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006336 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006337 }
6338 return result;
6339}
6340
6341
lrn@chromium.org303ada72010-10-27 09:33:13 +00006342static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006343 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006344 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006345 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006346 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006347 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006348
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006349 // Allocate global closures in old space and allocate local closures
6350 // in new space. Additionally pretenure closures that are assigned
6351 // directly to properties.
6352 pretenure = pretenure || (context->global_context() == *context);
6353 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006354 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006355 Factory::NewFunctionFromSharedFunctionInfo(shared,
6356 context,
6357 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006358 return *result;
6359}
6360
lrn@chromium.org303ada72010-10-27 09:33:13 +00006361static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006362 HandleScope scope;
6363 ASSERT(args.length() == 2);
6364 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6365 CONVERT_ARG_CHECKED(JSArray, params, 1);
6366
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006367 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006368 FixedArray* fixed = FixedArray::cast(params->elements());
6369
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006370 int fixed_length = Smi::cast(params->length())->value();
6371 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6372 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006373 Handle<Object> val = Handle<Object>(fixed->get(i));
6374 param_data[i] = val.location();
6375 }
6376
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006377 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006378 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006379 function, fixed_length, *param_data, &exception);
6380 if (exception) {
6381 return Failure::Exception();
6382 }
6383 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006384 return *result;
6385}
6386
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006387
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006388static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006389 Handle<Object> prototype = Factory::null_value();
6390 if (function->has_instance_prototype()) {
6391 prototype = Handle<Object>(function->instance_prototype());
6392 }
6393 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006394 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006395 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006396 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006397 function->shared()->set_construct_stub(
6398 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006399 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006400 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006401}
6402
6403
lrn@chromium.org303ada72010-10-27 09:33:13 +00006404static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006405 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006406 ASSERT(args.length() == 1);
6407
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006408 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006409
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006410 // If the constructor isn't a proper function we throw a type error.
6411 if (!constructor->IsJSFunction()) {
6412 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6413 Handle<Object> type_error =
6414 Factory::NewTypeError("not_constructor", arguments);
6415 return Top::Throw(*type_error);
6416 }
6417
6418 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006419
6420 // If function should not have prototype, construction is not allowed. In this
6421 // case generated code bailouts here, since function has no initial_map.
6422 if (!function->should_have_prototype()) {
6423 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6424 Handle<Object> type_error =
6425 Factory::NewTypeError("not_constructor", arguments);
6426 return Top::Throw(*type_error);
6427 }
6428
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006429#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006430 // Handle stepping into constructors if step into is active.
6431 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006432 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006433 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006434#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006435
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006436 if (function->has_initial_map()) {
6437 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006438 // The 'Function' function ignores the receiver object when
6439 // called using 'new' and creates a new JSFunction object that
6440 // is returned. The receiver object is only used for error
6441 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006442 // JSFunction. Factory::NewJSObject() should not be used to
6443 // allocate JSFunctions since it does not properly initialize
6444 // the shared part of the function. Since the receiver is
6445 // ignored anyway, we use the global object as the receiver
6446 // instead of a new JSFunction object. This way, errors are
6447 // reported the same way whether or not 'Function' is called
6448 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006449 return Top::context()->global();
6450 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006451 }
6452
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006453 // The function should be compiled for the optimization hints to be available.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006454 Handle<SharedFunctionInfo> shared(function->shared());
6455 EnsureCompiled(shared, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006456
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006457 if (!function->has_initial_map() &&
6458 shared->IsInobjectSlackTrackingInProgress()) {
6459 // The tracking is already in progress for another function. We can only
6460 // track one initial_map at a time, so we force the completion before the
6461 // function is called as a constructor for the first time.
6462 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006463 }
6464
6465 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006466 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006467 // Delay setting the stub if inobject slack tracking is in progress.
6468 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6469 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006470 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006471
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006472 Counters::constructed_objects.Increment();
6473 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006474
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006475 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006476}
6477
6478
lrn@chromium.org303ada72010-10-27 09:33:13 +00006479static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006480 HandleScope scope;
6481 ASSERT(args.length() == 1);
6482
6483 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6484 function->shared()->CompleteInobjectSlackTracking();
6485 TrySettingInlineConstructStub(function);
6486
6487 return Heap::undefined_value();
6488}
6489
6490
lrn@chromium.org303ada72010-10-27 09:33:13 +00006491static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006492 HandleScope scope;
6493 ASSERT(args.length() == 1);
6494
6495 Handle<JSFunction> function = args.at<JSFunction>(0);
6496#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006497 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006498 PrintF("[lazy: ");
6499 function->shared()->name()->Print();
6500 PrintF("]\n");
6501 }
6502#endif
6503
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006504 // Compile the target function. Here we compile using CompileLazyInLoop in
6505 // order to get the optimized version. This helps code like delta-blue
6506 // that calls performance-critical routines through constructors. A
6507 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6508 // direct call. Since the in-loop tracking takes place through CallICs
6509 // this means that things called through constructors are never known to
6510 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006511 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006512 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006513 return Failure::Exception();
6514 }
6515
6516 return function->code();
6517}
6518
6519
lrn@chromium.org303ada72010-10-27 09:33:13 +00006520static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006521 HandleScope scope;
6522 ASSERT(args.length() == 1);
6523 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6524 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6525}
6526
6527
lrn@chromium.org303ada72010-10-27 09:33:13 +00006528static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006529 HandleScope scope;
6530 ASSERT(args.length() == 1);
6531 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6532 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6533}
6534
6535
lrn@chromium.org303ada72010-10-27 09:33:13 +00006536static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006537 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006538 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006539
kasper.lund7276f142008-07-30 08:49:36 +00006540 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006541 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006542 Object* result;
6543 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
6544 if (!maybe_result->ToObject(&result)) return maybe_result;
6545 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006546
6547 Top::set_context(Context::cast(result));
6548
kasper.lund7276f142008-07-30 08:49:36 +00006549 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550}
6551
lrn@chromium.org303ada72010-10-27 09:33:13 +00006552
6553MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
6554 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006555 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006556 Object* js_object = object;
6557 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006558 MaybeObject* maybe_js_object = js_object->ToObject();
6559 if (!maybe_js_object->ToObject(&js_object)) {
6560 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
6561 return maybe_js_object;
6562 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006564 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565 Handle<Object> result =
6566 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
6567 return Top::Throw(*result);
6568 }
6569 }
6570
lrn@chromium.org303ada72010-10-27 09:33:13 +00006571 Object* result;
6572 { MaybeObject* maybe_result =
6573 Heap::AllocateWithContext(Top::context(),
6574 JSObject::cast(js_object),
6575 is_catch_context);
6576 if (!maybe_result->ToObject(&result)) return maybe_result;
6577 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006578
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006579 Context* context = Context::cast(result);
6580 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006581
kasper.lund7276f142008-07-30 08:49:36 +00006582 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583}
6584
6585
lrn@chromium.org303ada72010-10-27 09:33:13 +00006586static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006587 NoHandleAllocation ha;
6588 ASSERT(args.length() == 1);
6589 return PushContextHelper(args[0], false);
6590}
6591
6592
lrn@chromium.org303ada72010-10-27 09:33:13 +00006593static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006594 NoHandleAllocation ha;
6595 ASSERT(args.length() == 1);
6596 return PushContextHelper(args[0], true);
6597}
6598
6599
lrn@chromium.org303ada72010-10-27 09:33:13 +00006600static MaybeObject* Runtime_LookupContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601 HandleScope scope;
6602 ASSERT(args.length() == 2);
6603
6604 CONVERT_ARG_CHECKED(Context, context, 0);
6605 CONVERT_ARG_CHECKED(String, name, 1);
6606
6607 int index;
6608 PropertyAttributes attributes;
6609 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006610 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006611 context->Lookup(name, flags, &index, &attributes);
6612
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006613 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006614 ASSERT(holder->IsJSObject());
6615 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616 }
6617
6618 // No intermediate context found. Use global object by default.
6619 return Top::context()->global();
6620}
6621
6622
ager@chromium.orga1645e22009-09-09 19:27:10 +00006623// A mechanism to return a pair of Object pointers in registers (if possible).
6624// How this is achieved is calling convention-dependent.
6625// All currently supported x86 compiles uses calling conventions that are cdecl
6626// variants where a 64-bit value is returned in two 32-bit registers
6627// (edx:eax on ia32, r1:r0 on ARM).
6628// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
6629// In Win64 calling convention, a struct of two pointers is returned in memory,
6630// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006631#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006632struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006633 MaybeObject* x;
6634 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006635};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006636
lrn@chromium.org303ada72010-10-27 09:33:13 +00006637static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006638 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006639 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
6640 // In Win64 they are assigned to a hidden first argument.
6641 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006642}
6643#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006644typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006645static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006647 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006648}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006649#endif
6650
6651
lrn@chromium.org303ada72010-10-27 09:33:13 +00006652static inline MaybeObject* Unhole(MaybeObject* x,
6653 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006654 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
6655 USE(attributes);
6656 return x->IsTheHole() ? Heap::undefined_value() : x;
6657}
6658
6659
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006660static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
6661 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006662 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006663 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006664 JSFunction* context_extension_function =
6665 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006666 // If the holder isn't a context extension object, we just return it
6667 // as the receiver. This allows arguments objects to be used as
6668 // receivers, but only if they are put in the context scope chain
6669 // explicitly via a with-statement.
6670 Object* constructor = holder->map()->constructor();
6671 if (constructor != context_extension_function) return holder;
6672 // Fall back to using the global object as the receiver if the
6673 // property turns out to be a local variable allocated in a context
6674 // extension object - introduced via eval.
6675 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006676}
6677
6678
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006679static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006681 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006682
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006683 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00006684 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006685 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006687 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006688
6689 int index;
6690 PropertyAttributes attributes;
6691 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006692 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693 context->Lookup(name, flags, &index, &attributes);
6694
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006695 // If the index is non-negative, the slot has been found in a local
6696 // variable or a parameter. Read it from the context object or the
6697 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006698 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006699 // If the "property" we were looking for is a local variable or an
6700 // argument in a context, the receiver is the global object; see
6701 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
6702 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006703 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006704 ? Context::cast(*holder)->get(index)
6705 : JSObject::cast(*holder)->GetElement(index);
6706 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006707 }
6708
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006709 // If the holder is found, we read the property from it.
6710 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006711 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006712 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006713 JSObject* receiver;
6714 if (object->IsGlobalObject()) {
6715 receiver = GlobalObject::cast(object)->global_receiver();
6716 } else if (context->is_exception_holder(*holder)) {
6717 receiver = Top::context()->global()->global_receiver();
6718 } else {
6719 receiver = ComputeReceiverForNonGlobal(object);
6720 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006721 // No need to unhole the value here. This is taken care of by the
6722 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006723 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006724 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006725 }
6726
6727 if (throw_error) {
6728 // The property doesn't exist - throw exception.
6729 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006730 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006731 return MakePair(Top::Throw(*reference_error), NULL);
6732 } else {
6733 // The property doesn't exist - return undefined
6734 return MakePair(Heap::undefined_value(), Heap::undefined_value());
6735 }
6736}
6737
6738
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006739static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 return LoadContextSlotHelper(args, true);
6741}
6742
6743
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006744static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006745 return LoadContextSlotHelper(args, false);
6746}
6747
6748
lrn@chromium.org303ada72010-10-27 09:33:13 +00006749static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750 HandleScope scope;
6751 ASSERT(args.length() == 3);
6752
6753 Handle<Object> value(args[0]);
6754 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006755 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006756
6757 int index;
6758 PropertyAttributes attributes;
6759 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006760 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761 context->Lookup(name, flags, &index, &attributes);
6762
6763 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006764 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006765 // Ignore if read_only variable.
6766 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006767 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006768 }
6769 } else {
6770 ASSERT((attributes & READ_ONLY) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006771 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
6772 ToObjectUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006773 }
6774 return *value;
6775 }
6776
6777 // Slow case: The property is not in a FixedArray context.
6778 // It is either in an JSObject extension context or it was not found.
6779 Handle<JSObject> context_ext;
6780
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006781 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006782 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006783 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006784 } else {
6785 // The property was not found. It needs to be stored in the global context.
6786 ASSERT(attributes == ABSENT);
6787 attributes = NONE;
6788 context_ext = Handle<JSObject>(Top::context()->global());
6789 }
6790
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006791 // Set the property, but ignore if read_only variable on the context
6792 // extension object itself.
6793 if ((attributes & READ_ONLY) == 0 ||
6794 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
6796 if (set.is_null()) {
6797 // Failure::Exception is converted to a null handle in the
6798 // handle-based methods such as SetProperty. We therefore need
6799 // to convert null handles back to exceptions.
6800 ASSERT(Top::has_pending_exception());
6801 return Failure::Exception();
6802 }
6803 }
6804 return *value;
6805}
6806
6807
lrn@chromium.org303ada72010-10-27 09:33:13 +00006808static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006809 HandleScope scope;
6810 ASSERT(args.length() == 1);
6811
6812 return Top::Throw(args[0]);
6813}
6814
6815
lrn@chromium.org303ada72010-10-27 09:33:13 +00006816static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006817 HandleScope scope;
6818 ASSERT(args.length() == 1);
6819
6820 return Top::ReThrow(args[0]);
6821}
6822
6823
lrn@chromium.org303ada72010-10-27 09:33:13 +00006824static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006825 ASSERT_EQ(0, args.length());
6826 return Top::PromoteScheduledException();
6827}
6828
6829
lrn@chromium.org303ada72010-10-27 09:33:13 +00006830static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006831 HandleScope scope;
6832 ASSERT(args.length() == 1);
6833
6834 Handle<Object> name(args[0]);
6835 Handle<Object> reference_error =
6836 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
6837 return Top::Throw(*reference_error);
6838}
6839
6840
lrn@chromium.org303ada72010-10-27 09:33:13 +00006841static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006842 NoHandleAllocation na;
6843 return Top::StackOverflow();
6844}
6845
6846
lrn@chromium.org303ada72010-10-27 09:33:13 +00006847static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006848 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006849
6850 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00006851 if (StackGuard::IsStackOverflow()) {
6852 return Runtime_StackOverflow(args);
6853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006854
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006855 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006856}
6857
6858
6859// NOTE: These PrintXXX functions are defined for all builds (not just
6860// DEBUG builds) because we may want to be able to trace function
6861// calls in all modes.
6862static void PrintString(String* str) {
6863 // not uncommon to have empty strings
6864 if (str->length() > 0) {
6865 SmartPointer<char> s =
6866 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
6867 PrintF("%s", *s);
6868 }
6869}
6870
6871
6872static void PrintObject(Object* obj) {
6873 if (obj->IsSmi()) {
6874 PrintF("%d", Smi::cast(obj)->value());
6875 } else if (obj->IsString() || obj->IsSymbol()) {
6876 PrintString(String::cast(obj));
6877 } else if (obj->IsNumber()) {
6878 PrintF("%g", obj->Number());
6879 } else if (obj->IsFailure()) {
6880 PrintF("<failure>");
6881 } else if (obj->IsUndefined()) {
6882 PrintF("<undefined>");
6883 } else if (obj->IsNull()) {
6884 PrintF("<null>");
6885 } else if (obj->IsTrue()) {
6886 PrintF("<true>");
6887 } else if (obj->IsFalse()) {
6888 PrintF("<false>");
6889 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006890 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006891 }
6892}
6893
6894
6895static int StackSize() {
6896 int n = 0;
6897 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
6898 return n;
6899}
6900
6901
6902static void PrintTransition(Object* result) {
6903 // indentation
6904 { const int nmax = 80;
6905 int n = StackSize();
6906 if (n <= nmax)
6907 PrintF("%4d:%*s", n, n, "");
6908 else
6909 PrintF("%4d:%*s", n, nmax, "...");
6910 }
6911
6912 if (result == NULL) {
6913 // constructor calls
6914 JavaScriptFrameIterator it;
6915 JavaScriptFrame* frame = it.frame();
6916 if (frame->IsConstructor()) PrintF("new ");
6917 // function name
6918 Object* fun = frame->function();
6919 if (fun->IsJSFunction()) {
6920 PrintObject(JSFunction::cast(fun)->shared()->name());
6921 } else {
6922 PrintObject(fun);
6923 }
6924 // function arguments
6925 // (we are intentionally only printing the actually
6926 // supplied parameters, not all parameters required)
6927 PrintF("(this=");
6928 PrintObject(frame->receiver());
6929 const int length = frame->GetProvidedParametersCount();
6930 for (int i = 0; i < length; i++) {
6931 PrintF(", ");
6932 PrintObject(frame->GetParameter(i));
6933 }
6934 PrintF(") {\n");
6935
6936 } else {
6937 // function result
6938 PrintF("} -> ");
6939 PrintObject(result);
6940 PrintF("\n");
6941 }
6942}
6943
6944
lrn@chromium.org303ada72010-10-27 09:33:13 +00006945static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006946 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006947 NoHandleAllocation ha;
6948 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006949 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006950}
6951
6952
lrn@chromium.org303ada72010-10-27 09:33:13 +00006953static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006954 NoHandleAllocation ha;
6955 PrintTransition(args[0]);
6956 return args[0]; // return TOS
6957}
6958
6959
lrn@chromium.org303ada72010-10-27 09:33:13 +00006960static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006961 NoHandleAllocation ha;
6962 ASSERT(args.length() == 1);
6963
6964#ifdef DEBUG
6965 if (args[0]->IsString()) {
6966 // If we have a string, assume it's a code "marker"
6967 // and print some interesting cpu debugging info.
6968 JavaScriptFrameIterator it;
6969 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00006970 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
6971 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006972 } else {
6973 PrintF("DebugPrint: ");
6974 }
6975 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006976 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006977 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006978 HeapObject::cast(args[0])->map()->Print();
6979 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006980#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006981 // ShortPrint is available in release mode. Print is not.
6982 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006983#endif
6984 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00006985 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986
6987 return args[0]; // return TOS
6988}
6989
6990
lrn@chromium.org303ada72010-10-27 09:33:13 +00006991static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006992 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006993 NoHandleAllocation ha;
6994 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006995 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006996}
6997
6998
lrn@chromium.org303ada72010-10-27 09:33:13 +00006999static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007000 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007001 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007002
7003 // According to ECMA-262, section 15.9.1, page 117, the precision of
7004 // the number in a Date object representing a particular instant in
7005 // time is milliseconds. Therefore, we floor the result of getting
7006 // the OS time.
7007 double millis = floor(OS::TimeCurrentMillis());
7008 return Heap::NumberFromDouble(millis);
7009}
7010
7011
lrn@chromium.org303ada72010-10-27 09:33:13 +00007012static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007013 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007014 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007015
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007016 CONVERT_ARG_CHECKED(String, str, 0);
7017 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007018
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007019 CONVERT_ARG_CHECKED(JSArray, output, 1);
7020 RUNTIME_ASSERT(output->HasFastElements());
7021
7022 AssertNoAllocation no_allocation;
7023
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007024 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007025 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7026 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007027 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007028 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007030 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007031 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7032 }
7033
7034 if (result) {
7035 return *output;
7036 } else {
7037 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007038 }
7039}
7040
7041
lrn@chromium.org303ada72010-10-27 09:33:13 +00007042static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043 NoHandleAllocation ha;
7044 ASSERT(args.length() == 1);
7045
7046 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007047 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7049}
7050
7051
lrn@chromium.org303ada72010-10-27 09:33:13 +00007052static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007054 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007055
7056 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7057}
7058
7059
lrn@chromium.org303ada72010-10-27 09:33:13 +00007060static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061 NoHandleAllocation ha;
7062 ASSERT(args.length() == 1);
7063
7064 CONVERT_DOUBLE_CHECKED(x, args[0]);
7065 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7066}
7067
7068
lrn@chromium.org303ada72010-10-27 09:33:13 +00007069static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007070 ASSERT(args.length() == 1);
7071 Object* global = args[0];
7072 if (!global->IsJSGlobalObject()) return Heap::null_value();
7073 return JSGlobalObject::cast(global)->global_receiver();
7074}
7075
7076
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007077static MaybeObject* Runtime_ParseJson(Arguments args) {
7078 HandleScope scope;
7079 ASSERT_EQ(1, args.length());
7080 CONVERT_ARG_CHECKED(String, source, 0);
7081
7082 Handle<Object> result = JsonParser::Parse(source);
7083 if (result.is_null()) {
7084 // Syntax error or stack overflow in scanner.
7085 ASSERT(Top::has_pending_exception());
7086 return Failure::Exception();
7087 }
7088 return *result;
7089}
7090
7091
lrn@chromium.org303ada72010-10-27 09:33:13 +00007092static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007094 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007095 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007096
ager@chromium.org381abbb2009-02-25 13:23:22 +00007097 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007098 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007099 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7100 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007101 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007102 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007104 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007105 return *fun;
7106}
7107
7108
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007109static ObjectPair CompileGlobalEval(Handle<String> source,
7110 Handle<Object> receiver) {
7111 // Deal with a normal eval call with a string argument. Compile it
7112 // and return the compiled function bound in the local context.
7113 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7114 source,
7115 Handle<Context>(Top::context()),
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007116 Top::context()->IsGlobalContext());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007117 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7118 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7119 shared,
7120 Handle<Context>(Top::context()),
7121 NOT_TENURED);
7122 return MakePair(*compiled, *receiver);
7123}
7124
7125
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007126static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7127 ASSERT(args.length() == 3);
7128 if (!args[0]->IsJSFunction()) {
7129 return MakePair(Top::ThrowIllegalOperation(), NULL);
7130 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007131
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007132 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007133 Handle<JSFunction> callee = args.at<JSFunction>(0);
7134 Handle<Object> receiver; // Will be overwritten.
7135
7136 // Compute the calling context.
7137 Handle<Context> context = Handle<Context>(Top::context());
7138#ifdef DEBUG
7139 // Make sure Top::context() agrees with the old code that traversed
7140 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007141 StackFrameLocator locator;
7142 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007143 ASSERT(Context::cast(frame->context()) == *context);
7144#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007145
7146 // Find where the 'eval' symbol is bound. It is unaliased only if
7147 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007148 int index = -1;
7149 PropertyAttributes attributes = ABSENT;
7150 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007151 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7152 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007153 // Stop search when eval is found or when the global context is
7154 // reached.
7155 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007156 if (context->is_function_context()) {
7157 context = Handle<Context>(Context::cast(context->closure()->context()));
7158 } else {
7159 context = Handle<Context>(context->previous());
7160 }
7161 }
7162
iposva@chromium.org245aa852009-02-10 00:49:54 +00007163 // If eval could not be resolved, it has been deleted and we need to
7164 // throw a reference error.
7165 if (attributes == ABSENT) {
7166 Handle<Object> name = Factory::eval_symbol();
7167 Handle<Object> reference_error =
7168 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007169 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007170 }
7171
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007172 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007173 // 'eval' is not bound in the global context. Just call the function
7174 // with the given arguments. This is not necessarily the global eval.
7175 if (receiver->IsContext()) {
7176 context = Handle<Context>::cast(receiver);
7177 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007178 } else if (receiver->IsJSContextExtensionObject()) {
7179 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007180 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007181 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007182 }
7183
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007184 // 'eval' is bound in the global context, but it may have been overwritten.
7185 // Compare it to the builtin 'GlobalEval' function to make sure.
7186 if (*callee != Top::global_context()->global_eval_fun() ||
7187 !args[1]->IsString()) {
7188 return MakePair(*callee, Top::context()->global()->global_receiver());
7189 }
7190
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007191 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7192}
7193
7194
7195static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7196 ASSERT(args.length() == 3);
7197 if (!args[0]->IsJSFunction()) {
7198 return MakePair(Top::ThrowIllegalOperation(), NULL);
7199 }
7200
7201 HandleScope scope;
7202 Handle<JSFunction> callee = args.at<JSFunction>(0);
7203
7204 // 'eval' is bound in the global context, but it may have been overwritten.
7205 // Compare it to the builtin 'GlobalEval' function to make sure.
7206 if (*callee != Top::global_context()->global_eval_fun() ||
7207 !args[1]->IsString()) {
7208 return MakePair(*callee, Top::context()->global()->global_receiver());
7209 }
7210
7211 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007212}
7213
7214
lrn@chromium.org303ada72010-10-27 09:33:13 +00007215static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007216 // This utility adjusts the property attributes for newly created Function
7217 // object ("new Function(...)") by changing the map.
7218 // All it does is changing the prototype property to enumerable
7219 // as specified in ECMA262, 15.3.5.2.
7220 HandleScope scope;
7221 ASSERT(args.length() == 1);
7222 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7223 ASSERT(func->map()->instance_type() ==
7224 Top::function_instance_map()->instance_type());
7225 ASSERT(func->map()->instance_size() ==
7226 Top::function_instance_map()->instance_size());
7227 func->set_map(*Top::function_instance_map());
7228 return *func;
7229}
7230
7231
lrn@chromium.org303ada72010-10-27 09:33:13 +00007232static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007233 // Allocate a block of memory in NewSpace (filled with a filler).
7234 // Use as fallback for allocation in generated code when NewSpace
7235 // is full.
7236 ASSERT(args.length() == 1);
7237 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7238 int size = size_smi->value();
7239 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7240 RUNTIME_ASSERT(size > 0);
7241 static const int kMinFreeNewSpaceAfterGC =
7242 Heap::InitialSemiSpaceSize() * 3/4;
7243 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007244 Object* allocation;
7245 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7246 if (maybe_allocation->ToObject(&allocation)) {
7247 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7248 }
7249 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007250 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007251}
7252
7253
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007254// Push an array unto an array of arrays if it is not already in the
7255// array. Returns true if the element was pushed on the stack and
7256// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007257static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007258 ASSERT(args.length() == 2);
7259 CONVERT_CHECKED(JSArray, array, args[0]);
7260 CONVERT_CHECKED(JSArray, element, args[1]);
7261 RUNTIME_ASSERT(array->HasFastElements());
7262 int length = Smi::cast(array->length())->value();
7263 FixedArray* elements = FixedArray::cast(array->elements());
7264 for (int i = 0; i < length; i++) {
7265 if (elements->get(i) == element) return Heap::false_value();
7266 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007267 Object* obj;
7268 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7269 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7270 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007271 return Heap::true_value();
7272}
7273
7274
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007275/**
7276 * A simple visitor visits every element of Array's.
7277 * The backend storage can be a fixed array for fast elements case,
7278 * or a dictionary for sparse array. Since Dictionary is a subtype
7279 * of FixedArray, the class can be used by both fast and slow cases.
7280 * The second parameter of the constructor, fast_elements, specifies
7281 * whether the storage is a FixedArray or Dictionary.
7282 *
7283 * An index limit is used to deal with the situation that a result array
7284 * length overflows 32-bit non-negative integer.
7285 */
7286class ArrayConcatVisitor {
7287 public:
7288 ArrayConcatVisitor(Handle<FixedArray> storage,
7289 uint32_t index_limit,
7290 bool fast_elements) :
7291 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007292 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007293
7294 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007295 if (i >= index_limit_ - index_offset_) return;
7296 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007297
7298 if (fast_elements_) {
7299 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7300 storage_->set(index, *elm);
7301
7302 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007303 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7304 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007305 Factory::DictionaryAtNumberPut(dict, index, elm);
7306 if (!result.is_identical_to(dict))
7307 storage_ = result;
7308 }
7309 }
7310
7311 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007312 if (index_limit_ - index_offset_ < delta) {
7313 index_offset_ = index_limit_;
7314 } else {
7315 index_offset_ += delta;
7316 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007317 }
7318
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007319 Handle<FixedArray> storage() { return storage_; }
7320
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007321 private:
7322 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007323 // Limit on the accepted indices. Elements with indices larger than the
7324 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007325 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007326 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007327 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007328 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007329};
7330
7331
ager@chromium.org3811b432009-10-28 14:53:37 +00007332template<class ExternalArrayClass, class ElementType>
7333static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7334 bool elements_are_ints,
7335 bool elements_are_guaranteed_smis,
7336 uint32_t range,
7337 ArrayConcatVisitor* visitor) {
7338 Handle<ExternalArrayClass> array(
7339 ExternalArrayClass::cast(receiver->elements()));
7340 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7341
7342 if (visitor != NULL) {
7343 if (elements_are_ints) {
7344 if (elements_are_guaranteed_smis) {
7345 for (uint32_t j = 0; j < len; j++) {
7346 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7347 visitor->visit(j, e);
7348 }
7349 } else {
7350 for (uint32_t j = 0; j < len; j++) {
7351 int64_t val = static_cast<int64_t>(array->get(j));
7352 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7353 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7354 visitor->visit(j, e);
7355 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007356 Handle<Object> e =
7357 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007358 visitor->visit(j, e);
7359 }
7360 }
7361 }
7362 } else {
7363 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007364 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007365 visitor->visit(j, e);
7366 }
7367 }
7368 }
7369
7370 return len;
7371}
7372
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007373/**
7374 * A helper function that visits elements of a JSObject. Only elements
7375 * whose index between 0 and range (exclusive) are visited.
7376 *
7377 * If the third parameter, visitor, is not NULL, the visitor is called
7378 * with parameters, 'visitor_index_offset + element index' and the element.
7379 *
7380 * It returns the number of visisted elements.
7381 */
7382static uint32_t IterateElements(Handle<JSObject> receiver,
7383 uint32_t range,
7384 ArrayConcatVisitor* visitor) {
7385 uint32_t num_of_elements = 0;
7386
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007387 switch (receiver->GetElementsKind()) {
7388 case JSObject::FAST_ELEMENTS: {
7389 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7390 uint32_t len = elements->length();
7391 if (range < len) {
7392 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007393 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007394
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007395 for (uint32_t j = 0; j < len; j++) {
7396 Handle<Object> e(elements->get(j));
7397 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007398 num_of_elements++;
7399 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007400 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007401 }
7402 }
7403 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007404 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007405 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007406 case JSObject::PIXEL_ELEMENTS: {
7407 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7408 uint32_t len = pixels->length();
7409 if (range < len) {
7410 len = range;
7411 }
7412
7413 for (uint32_t j = 0; j < len; j++) {
7414 num_of_elements++;
7415 if (visitor != NULL) {
7416 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7417 visitor->visit(j, e);
7418 }
7419 }
7420 break;
7421 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007422 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7423 num_of_elements =
7424 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7425 receiver, true, true, range, visitor);
7426 break;
7427 }
7428 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7429 num_of_elements =
7430 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7431 receiver, true, true, range, visitor);
7432 break;
7433 }
7434 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7435 num_of_elements =
7436 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7437 receiver, true, true, range, visitor);
7438 break;
7439 }
7440 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7441 num_of_elements =
7442 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7443 receiver, true, true, range, visitor);
7444 break;
7445 }
7446 case JSObject::EXTERNAL_INT_ELEMENTS: {
7447 num_of_elements =
7448 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7449 receiver, true, false, range, visitor);
7450 break;
7451 }
7452 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7453 num_of_elements =
7454 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7455 receiver, true, false, range, visitor);
7456 break;
7457 }
7458 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7459 num_of_elements =
7460 IterateExternalArrayElements<ExternalFloatArray, float>(
7461 receiver, false, false, range, visitor);
7462 break;
7463 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007464 case JSObject::DICTIONARY_ELEMENTS: {
7465 Handle<NumberDictionary> dict(receiver->element_dictionary());
7466 uint32_t capacity = dict->Capacity();
7467 for (uint32_t j = 0; j < capacity; j++) {
7468 Handle<Object> k(dict->KeyAt(j));
7469 if (dict->IsKey(*k)) {
7470 ASSERT(k->IsNumber());
7471 uint32_t index = static_cast<uint32_t>(k->Number());
7472 if (index < range) {
7473 num_of_elements++;
7474 if (visitor) {
7475 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7476 }
7477 }
7478 }
7479 }
7480 break;
7481 }
7482 default:
7483 UNREACHABLE();
7484 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007485 }
7486
7487 return num_of_elements;
7488}
7489
7490
7491/**
7492 * A helper function that visits elements of an Array object, and elements
7493 * on its prototypes.
7494 *
7495 * Elements on prototypes are visited first, and only elements whose indices
7496 * less than Array length are visited.
7497 *
7498 * If a ArrayConcatVisitor object is given, the visitor is called with
7499 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007500 *
7501 * The returned number of elements is an upper bound on the actual number
7502 * of elements added. If the same element occurs in more than one object
7503 * in the array's prototype chain, it will be counted more than once, but
7504 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007505 */
7506static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7507 ArrayConcatVisitor* visitor) {
7508 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7509 Handle<Object> obj = array;
7510
7511 static const int kEstimatedPrototypes = 3;
7512 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7513
7514 // Visit prototype first. If an element on the prototype is shadowed by
7515 // the inheritor using the same index, the ArrayConcatVisitor visits
7516 // the prototype element before the shadowing element.
7517 // The visitor can simply overwrite the old value by new value using
7518 // the same index. This follows Array::concat semantics.
7519 while (!obj->IsNull()) {
7520 objects.Add(Handle<JSObject>::cast(obj));
7521 obj = Handle<Object>(obj->GetPrototype());
7522 }
7523
7524 uint32_t nof_elements = 0;
7525 for (int i = objects.length() - 1; i >= 0; i--) {
7526 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007527 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007528 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007529
7530 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7531 nof_elements = JSObject::kMaxElementCount;
7532 } else {
7533 nof_elements += encountered_elements;
7534 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007535 }
7536
7537 return nof_elements;
7538}
7539
7540
7541/**
7542 * A helper function of Runtime_ArrayConcat.
7543 *
7544 * The first argument is an Array of arrays and objects. It is the
7545 * same as the arguments array of Array::concat JS function.
7546 *
7547 * If an argument is an Array object, the function visits array
7548 * elements. If an argument is not an Array object, the function
7549 * visits the object as if it is an one-element array.
7550 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007551 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007552 * non-negative number is used as new length. For example, if one
7553 * array length is 2^32 - 1, second array length is 1, the
7554 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007555 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
7556 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007557 */
7558static uint32_t IterateArguments(Handle<JSArray> arguments,
7559 ArrayConcatVisitor* visitor) {
7560 uint32_t visited_elements = 0;
7561 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7562
7563 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007564 Object *element;
7565 MaybeObject* maybe_element = arguments->GetElement(i);
7566 // This if() is not expected to fail, but we have the check in the
7567 // interest of hardening the runtime calls.
7568 if (maybe_element->ToObject(&element)) {
7569 Handle<Object> obj(element);
7570 if (obj->IsJSArray()) {
7571 Handle<JSArray> array = Handle<JSArray>::cast(obj);
7572 uint32_t len = static_cast<uint32_t>(array->length()->Number());
7573 uint32_t nof_elements =
7574 IterateArrayAndPrototypeElements(array, visitor);
7575 // Total elements of array and its prototype chain can be more than
7576 // the array length, but ArrayConcat can only concatenate at most
7577 // the array length number of elements. We use the length as an estimate
7578 // for the actual number of elements added.
7579 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
7580 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
7581 visited_elements = JSArray::kMaxElementCount;
7582 } else {
7583 visited_elements += added_elements;
7584 }
7585 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007586 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007587 if (visitor) {
7588 visitor->visit(0, obj);
7589 visitor->increase_index_offset(1);
7590 }
7591 if (visited_elements < JSArray::kMaxElementCount) {
7592 visited_elements++;
7593 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007594 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007595 }
7596 }
7597 return visited_elements;
7598}
7599
7600
7601/**
7602 * Array::concat implementation.
7603 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007604 * TODO(lrn): Fix non-compliance for very large concatenations and update to
7605 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007606 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00007607static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007608 ASSERT(args.length() == 1);
7609 HandleScope handle_scope;
7610
7611 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
7612 Handle<JSArray> arguments(arg_arrays);
7613
7614 // Pass 1: estimate the number of elements of the result
7615 // (it could be more than real numbers if prototype has elements).
7616 uint32_t result_length = 0;
7617 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7618
7619 { AssertNoAllocation nogc;
7620 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007621 Object* obj;
7622 MaybeObject* maybe_object = arguments->GetElement(i);
7623 // This if() is not expected to fail, but we have the check in the
7624 // interest of hardening the runtime calls.
7625 if (maybe_object->ToObject(&obj)) {
7626 uint32_t length_estimate;
7627 if (obj->IsJSArray()) {
7628 length_estimate =
7629 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
7630 } else {
7631 length_estimate = 1;
7632 }
7633 if (JSObject::kMaxElementCount - result_length < length_estimate) {
7634 result_length = JSObject::kMaxElementCount;
7635 break;
7636 }
7637 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007638 }
7639 }
7640 }
7641
7642 // Allocate an empty array, will set length and content later.
7643 Handle<JSArray> result = Factory::NewJSArray(0);
7644
7645 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
7646 // If estimated number of elements is more than half of length, a
7647 // fixed array (fast case) is more time and space-efficient than a
7648 // dictionary.
7649 bool fast_case = (estimate_nof_elements * 2) >= result_length;
7650
7651 Handle<FixedArray> storage;
7652 if (fast_case) {
7653 // The backing storage array must have non-existing elements to
7654 // preserve holes across concat operations.
7655 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007656 Handle<Map> fast_map =
7657 Factory::GetFastElementsMap(Handle<Map>(result->map()));
7658 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007659 } else {
7660 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
7661 uint32_t at_least_space_for = estimate_nof_elements +
7662 (estimate_nof_elements >> 2);
7663 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007664 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007665 Handle<Map> slow_map =
7666 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
7667 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007668 }
7669
7670 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
7671
7672 ArrayConcatVisitor visitor(storage, result_length, fast_case);
7673
7674 IterateArguments(arguments, &visitor);
7675
7676 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007677 // Please note the storage might have changed in the visitor.
7678 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007679
7680 return *result;
7681}
7682
7683
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007684// This will not allocate (flatten the string), but it may run
7685// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007686static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007687 NoHandleAllocation ha;
7688 ASSERT(args.length() == 1);
7689
7690 CONVERT_CHECKED(String, string, args[0]);
7691 StringInputBuffer buffer(string);
7692 while (buffer.has_more()) {
7693 uint16_t character = buffer.GetNext();
7694 PrintF("%c", character);
7695 }
7696 return string;
7697}
7698
ager@chromium.org5ec48922009-05-05 07:25:34 +00007699// Moves all own elements of an object, that are below a limit, to positions
7700// starting at zero. All undefined values are placed after non-undefined values,
7701// and are followed by non-existing element. Does not change the length
7702// property.
7703// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007704static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007705 ASSERT(args.length() == 2);
7706 CONVERT_CHECKED(JSObject, object, args[0]);
7707 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
7708 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007709}
7710
7711
7712// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00007713static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007714 ASSERT(args.length() == 2);
7715 CONVERT_CHECKED(JSArray, from, args[0]);
7716 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007717 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007718 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007719 if (new_elements->map() == Heap::fixed_array_map() ||
7720 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007721 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007722 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007723 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007724 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007725 Object* new_map;
7726 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007727 to->set_map(Map::cast(new_map));
7728 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007729 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007730 Object* obj;
7731 { MaybeObject* maybe_obj = from->ResetElements();
7732 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7733 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007734 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007735 return to;
7736}
7737
7738
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007739// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00007740static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007741 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007742 CONVERT_CHECKED(JSObject, object, args[0]);
7743 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007744 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007745 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007746 } else if (object->IsJSArray()) {
7747 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007749 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007750 }
7751}
7752
7753
lrn@chromium.org303ada72010-10-27 09:33:13 +00007754static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007755 HandleScope handle_scope;
7756
7757 ASSERT_EQ(3, args.length());
7758
ager@chromium.orgac091b72010-05-05 07:34:42 +00007759 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007760 Handle<Object> key1 = args.at<Object>(1);
7761 Handle<Object> key2 = args.at<Object>(2);
7762
7763 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007764 if (!key1->ToArrayIndex(&index1)
7765 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00007766 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007767 }
7768
ager@chromium.orgac091b72010-05-05 07:34:42 +00007769 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
7770 Handle<Object> tmp1 = GetElement(jsobject, index1);
7771 Handle<Object> tmp2 = GetElement(jsobject, index2);
7772
7773 SetElement(jsobject, index1, tmp2);
7774 SetElement(jsobject, index2, tmp1);
7775
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007776 return Heap::undefined_value();
7777}
7778
7779
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007780// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007781// might have elements. Can either return keys (positive integers) or
7782// intervals (pair of a negative integer (-start-1) followed by a
7783// positive (length)) or undefined values.
7784// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007785static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007786 ASSERT(args.length() == 2);
7787 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007788 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007789 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007790 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007791 // Create an array and get all the keys into it, then remove all the
7792 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007793 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007794 int keys_length = keys->length();
7795 for (int i = 0; i < keys_length; i++) {
7796 Object* key = keys->get(i);
7797 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007798 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007799 // Zap invalid keys.
7800 keys->set_undefined(i);
7801 }
7802 }
7803 return *Factory::NewJSArrayWithElements(keys);
7804 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007805 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007806 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
7807 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007808 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007809 uint32_t actual_length =
7810 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00007811 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007812 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00007813 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007814 single_interval->set(1, *length_object);
7815 return *Factory::NewJSArrayWithElements(single_interval);
7816 }
7817}
7818
7819
7820// DefineAccessor takes an optional final argument which is the
7821// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
7822// to the way accessors are implemented, it is set for both the getter
7823// and setter on the first call to DefineAccessor and ignored on
7824// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007825static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007826 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
7827 // Compute attributes.
7828 PropertyAttributes attributes = NONE;
7829 if (args.length() == 5) {
7830 CONVERT_CHECKED(Smi, attrs, args[4]);
7831 int value = attrs->value();
7832 // Only attribute bits should be set.
7833 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
7834 attributes = static_cast<PropertyAttributes>(value);
7835 }
7836
7837 CONVERT_CHECKED(JSObject, obj, args[0]);
7838 CONVERT_CHECKED(String, name, args[1]);
7839 CONVERT_CHECKED(Smi, flag, args[2]);
7840 CONVERT_CHECKED(JSFunction, fun, args[3]);
7841 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
7842}
7843
7844
lrn@chromium.org303ada72010-10-27 09:33:13 +00007845static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007846 ASSERT(args.length() == 3);
7847 CONVERT_CHECKED(JSObject, obj, args[0]);
7848 CONVERT_CHECKED(String, name, args[1]);
7849 CONVERT_CHECKED(Smi, flag, args[2]);
7850 return obj->LookupAccessor(name, flag->value() == 0);
7851}
7852
7853
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007854#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00007855static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007856 ASSERT(args.length() == 0);
7857 return Execution::DebugBreakHelper();
7858}
7859
7860
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007861// Helper functions for wrapping and unwrapping stack frame ids.
7862static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007863 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007864 return Smi::FromInt(id >> 2);
7865}
7866
7867
7868static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
7869 return static_cast<StackFrame::Id>(wrapped->value() << 2);
7870}
7871
7872
7873// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00007874// args[0]: debug event listener function to set or null or undefined for
7875// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007876// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00007877static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007878 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007879 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
7880 args[0]->IsUndefined() ||
7881 args[0]->IsNull());
7882 Handle<Object> callback = args.at<Object>(0);
7883 Handle<Object> data = args.at<Object>(1);
7884 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007885
7886 return Heap::undefined_value();
7887}
7888
7889
lrn@chromium.org303ada72010-10-27 09:33:13 +00007890static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00007891 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007892 StackGuard::DebugBreak();
7893 return Heap::undefined_value();
7894}
7895
7896
lrn@chromium.org303ada72010-10-27 09:33:13 +00007897static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
7898 LookupResult* result,
7899 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007900 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007901 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007902 case NORMAL:
7903 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007904 if (value->IsTheHole()) {
7905 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007906 }
7907 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007908 case FIELD:
7909 value =
7910 JSObject::cast(
7911 result->holder())->FastPropertyAt(result->GetFieldIndex());
7912 if (value->IsTheHole()) {
7913 return Heap::undefined_value();
7914 }
7915 return value;
7916 case CONSTANT_FUNCTION:
7917 return result->GetConstantFunction();
7918 case CALLBACKS: {
7919 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007920 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007921 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007922 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007923 if (!maybe_value->ToObject(&value)) {
7924 ASSERT(maybe_value->IsException());
7925 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007926 Top::clear_pending_exception();
7927 if (caught_exception != NULL) {
7928 *caught_exception = true;
7929 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007930 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007931 }
7932 return value;
7933 } else {
7934 return Heap::undefined_value();
7935 }
7936 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007937 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007938 case MAP_TRANSITION:
7939 case CONSTANT_TRANSITION:
7940 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007941 return Heap::undefined_value();
7942 default:
7943 UNREACHABLE();
7944 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007945 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007946 return Heap::undefined_value();
7947}
7948
7949
ager@chromium.org32912102009-01-16 10:38:43 +00007950// Get debugger related details for an object property.
7951// args[0]: object holding property
7952// args[1]: name of the property
7953//
7954// The array returned contains the following information:
7955// 0: Property value
7956// 1: Property details
7957// 2: Property value is exception
7958// 3: Getter function if defined
7959// 4: Setter function if defined
7960// Items 2-4 are only filled if the property has either a getter or a setter
7961// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007962static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007963 HandleScope scope;
7964
7965 ASSERT(args.length() == 2);
7966
7967 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7968 CONVERT_ARG_CHECKED(String, name, 1);
7969
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007970 // Make sure to set the current context to the context before the debugger was
7971 // entered (if the debugger is entered). The reason for switching context here
7972 // is that for some property lookups (accessors and interceptors) callbacks
7973 // into the embedding application can occour, and the embedding application
7974 // could have the assumption that its own global context is the current
7975 // context and not some internal debugger context.
7976 SaveContext save;
7977 if (Debug::InDebugger()) {
7978 Top::set_context(*Debug::debugger_entry()->GetContext());
7979 }
7980
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007981 // Skip the global proxy as it has no properties and always delegates to the
7982 // real global object.
7983 if (obj->IsJSGlobalProxy()) {
7984 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
7985 }
7986
7987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007988 // Check if the name is trivially convertible to an index and get the element
7989 // if so.
7990 uint32_t index;
7991 if (name->AsArrayIndex(&index)) {
7992 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007993 Object* element_or_char;
7994 { MaybeObject* maybe_element_or_char =
7995 Runtime::GetElementOrCharAt(obj, index);
7996 if (!maybe_element_or_char->ToObject(&element_or_char)) {
7997 return maybe_element_or_char;
7998 }
7999 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008000 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008001 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8002 return *Factory::NewJSArrayWithElements(details);
8003 }
8004
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008005 // Find the number of objects making up this.
8006 int length = LocalPrototypeChainLength(*obj);
8007
8008 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008009 Handle<JSObject> jsproto = obj;
8010 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008011 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008012 jsproto->LocalLookup(*name, &result);
8013 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008014 // LookupResult is not GC safe as it holds raw object pointers.
8015 // GC can happen later in this code so put the required fields into
8016 // local variables using handles when required for later use.
8017 PropertyType result_type = result.type();
8018 Handle<Object> result_callback_obj;
8019 if (result_type == CALLBACKS) {
8020 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8021 }
8022 Smi* property_details = result.GetPropertyDetails().AsSmi();
8023 // DebugLookupResultValue can cause GC so details from LookupResult needs
8024 // to be copied to handles before this.
8025 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008026 Object* raw_value;
8027 { MaybeObject* maybe_raw_value =
8028 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8029 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8030 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008031 Handle<Object> value(raw_value);
8032
8033 // If the callback object is a fixed array then it contains JavaScript
8034 // getter and/or setter.
8035 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8036 result_callback_obj->IsFixedArray();
8037 Handle<FixedArray> details =
8038 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8039 details->set(0, *value);
8040 details->set(1, property_details);
8041 if (hasJavaScriptAccessors) {
8042 details->set(2,
8043 caught_exception ? Heap::true_value()
8044 : Heap::false_value());
8045 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8046 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8047 }
8048
8049 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008050 }
8051 if (i < length - 1) {
8052 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8053 }
8054 }
8055
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008056 return Heap::undefined_value();
8057}
8058
8059
lrn@chromium.org303ada72010-10-27 09:33:13 +00008060static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008061 HandleScope scope;
8062
8063 ASSERT(args.length() == 2);
8064
8065 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8066 CONVERT_ARG_CHECKED(String, name, 1);
8067
8068 LookupResult result;
8069 obj->Lookup(*name, &result);
8070 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008071 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072 }
8073 return Heap::undefined_value();
8074}
8075
8076
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008077// Return the property type calculated from the property details.
8078// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008079static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008080 ASSERT(args.length() == 1);
8081 CONVERT_CHECKED(Smi, details, args[0]);
8082 PropertyType type = PropertyDetails(details).type();
8083 return Smi::FromInt(static_cast<int>(type));
8084}
8085
8086
8087// Return the property attribute calculated from the property details.
8088// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008089static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008090 ASSERT(args.length() == 1);
8091 CONVERT_CHECKED(Smi, details, args[0]);
8092 PropertyAttributes attributes = PropertyDetails(details).attributes();
8093 return Smi::FromInt(static_cast<int>(attributes));
8094}
8095
8096
8097// Return the property insertion index calculated from the property details.
8098// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008099static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008100 ASSERT(args.length() == 1);
8101 CONVERT_CHECKED(Smi, details, args[0]);
8102 int index = PropertyDetails(details).index();
8103 return Smi::FromInt(index);
8104}
8105
8106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008107// Return property value from named interceptor.
8108// args[0]: object
8109// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008110static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008111 HandleScope scope;
8112 ASSERT(args.length() == 2);
8113 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8114 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8115 CONVERT_ARG_CHECKED(String, name, 1);
8116
8117 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008118 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008119}
8120
8121
8122// Return element value from indexed interceptor.
8123// args[0]: object
8124// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008125static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8126 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008127 HandleScope scope;
8128 ASSERT(args.length() == 2);
8129 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8130 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8131 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8132
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008133 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008134}
8135
8136
lrn@chromium.org303ada72010-10-27 09:33:13 +00008137static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008138 ASSERT(args.length() >= 1);
8139 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008140 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008141 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008142 return Top::Throw(Heap::illegal_execution_state_symbol());
8143 }
8144
8145 return Heap::true_value();
8146}
8147
8148
lrn@chromium.org303ada72010-10-27 09:33:13 +00008149static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008150 HandleScope scope;
8151 ASSERT(args.length() == 1);
8152
8153 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008154 Object* result;
8155 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8156 if (!maybe_result->ToObject(&result)) return maybe_result;
8157 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008158
8159 // Count all frames which are relevant to debugging stack trace.
8160 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008161 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008162 if (id == StackFrame::NO_ID) {
8163 // If there is no JavaScript stack frame count is 0.
8164 return Smi::FromInt(0);
8165 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008166 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8167 return Smi::FromInt(n);
8168}
8169
8170
8171static const int kFrameDetailsFrameIdIndex = 0;
8172static const int kFrameDetailsReceiverIndex = 1;
8173static const int kFrameDetailsFunctionIndex = 2;
8174static const int kFrameDetailsArgumentCountIndex = 3;
8175static const int kFrameDetailsLocalCountIndex = 4;
8176static const int kFrameDetailsSourcePositionIndex = 5;
8177static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008178static const int kFrameDetailsAtReturnIndex = 7;
8179static const int kFrameDetailsDebuggerFrameIndex = 8;
8180static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008181
8182// Return an array with frame details
8183// args[0]: number: break id
8184// args[1]: number: frame index
8185//
8186// The array returned contains the following information:
8187// 0: Frame id
8188// 1: Receiver
8189// 2: Function
8190// 3: Argument count
8191// 4: Local count
8192// 5: Source position
8193// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008194// 7: Is at return
8195// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008196// Arguments name, value
8197// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008198// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008199static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008200 HandleScope scope;
8201 ASSERT(args.length() == 2);
8202
8203 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008204 Object* check;
8205 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8206 if (!maybe_check->ToObject(&check)) return maybe_check;
8207 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008208 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8209
8210 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008211 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008212 if (id == StackFrame::NO_ID) {
8213 // If there are no JavaScript stack frames return undefined.
8214 return Heap::undefined_value();
8215 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008216 int count = 0;
8217 JavaScriptFrameIterator it(id);
8218 for (; !it.done(); it.Advance()) {
8219 if (count == index) break;
8220 count++;
8221 }
8222 if (it.done()) return Heap::undefined_value();
8223
8224 // Traverse the saved contexts chain to find the active context for the
8225 // selected frame.
8226 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008227 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008228 save = save->prev();
8229 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008230 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008231
8232 // Get the frame id.
8233 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8234
8235 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008236 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008237
8238 // Check for constructor frame.
8239 bool constructor = it.frame()->IsConstructor();
8240
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008241 // Get scope info and read from it for local variable information.
8242 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008243 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008244 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008245
8246 // Get the context.
8247 Handle<Context> context(Context::cast(it.frame()->context()));
8248
8249 // Get the locals names and values into a temporary array.
8250 //
8251 // TODO(1240907): Hide compiler-introduced stack variables
8252 // (e.g. .result)? For users of the debugger, they will probably be
8253 // confusing.
8254 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
8255 for (int i = 0; i < info.NumberOfLocals(); i++) {
8256 // Name of the local.
8257 locals->set(i * 2, *info.LocalName(i));
8258
8259 // Fetch the value of the local - either from the stack or from a
8260 // heap-allocated context.
8261 if (i < info.number_of_stack_slots()) {
8262 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8263 } else {
8264 Handle<String> name = info.LocalName(i);
8265 // Traverse the context chain to the function context as all local
8266 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008267 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008268 context = Handle<Context>(context->previous());
8269 }
8270 ASSERT(context->is_function_context());
8271 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008272 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273 }
8274 }
8275
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008276 // Check whether this frame is positioned at return.
8277 int at_return = (index == 0) ? Debug::IsBreakAtReturn(it.frame()) : false;
8278
8279 // If positioned just before return find the value to be returned and add it
8280 // to the frame information.
8281 Handle<Object> return_value = Factory::undefined_value();
8282 if (at_return) {
8283 StackFrameIterator it2;
8284 Address internal_frame_sp = NULL;
8285 while (!it2.done()) {
8286 if (it2.frame()->is_internal()) {
8287 internal_frame_sp = it2.frame()->sp();
8288 } else {
8289 if (it2.frame()->is_java_script()) {
8290 if (it2.frame()->id() == it.frame()->id()) {
8291 // The internal frame just before the JavaScript frame contains the
8292 // value to return on top. A debug break at return will create an
8293 // internal frame to store the return value (eax/rax/r0) before
8294 // entering the debug break exit frame.
8295 if (internal_frame_sp != NULL) {
8296 return_value =
8297 Handle<Object>(Memory::Object_at(internal_frame_sp));
8298 break;
8299 }
8300 }
8301 }
8302
8303 // Indicate that the previous frame was not an internal frame.
8304 internal_frame_sp = NULL;
8305 }
8306 it2.Advance();
8307 }
8308 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008309
8310 // Now advance to the arguments adapter frame (if any). It contains all
8311 // the provided parameters whereas the function frame always have the number
8312 // of arguments matching the functions parameters. The rest of the
8313 // information (except for what is collected above) is the same.
8314 it.AdvanceToArgumentsFrame();
8315
8316 // Find the number of arguments to fill. At least fill the number of
8317 // parameters for the function and fill more if more parameters are provided.
8318 int argument_count = info.number_of_parameters();
8319 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8320 argument_count = it.frame()->GetProvidedParametersCount();
8321 }
8322
8323 // Calculate the size of the result.
8324 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008325 2 * (argument_count + info.NumberOfLocals()) +
8326 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008327 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8328
8329 // Add the frame id.
8330 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8331
8332 // Add the function (same as in function frame).
8333 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8334
8335 // Add the arguments count.
8336 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8337
8338 // Add the locals count
8339 details->set(kFrameDetailsLocalCountIndex,
8340 Smi::FromInt(info.NumberOfLocals()));
8341
8342 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008343 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008344 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8345 } else {
8346 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8347 }
8348
8349 // Add the constructor information.
8350 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8351
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008352 // Add the at return information.
8353 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8354
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008355 // Add information on whether this frame is invoked in the debugger context.
8356 details->set(kFrameDetailsDebuggerFrameIndex,
8357 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8358
8359 // Fill the dynamic part.
8360 int details_index = kFrameDetailsFirstDynamicIndex;
8361
8362 // Add arguments name and value.
8363 for (int i = 0; i < argument_count; i++) {
8364 // Name of the argument.
8365 if (i < info.number_of_parameters()) {
8366 details->set(details_index++, *info.parameter_name(i));
8367 } else {
8368 details->set(details_index++, Heap::undefined_value());
8369 }
8370
8371 // Parameter value.
8372 if (i < it.frame()->GetProvidedParametersCount()) {
8373 details->set(details_index++, it.frame()->GetParameter(i));
8374 } else {
8375 details->set(details_index++, Heap::undefined_value());
8376 }
8377 }
8378
8379 // Add locals name and value from the temporary copy from the function frame.
8380 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8381 details->set(details_index++, locals->get(i));
8382 }
8383
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008384 // Add the value being returned.
8385 if (at_return) {
8386 details->set(details_index++, *return_value);
8387 }
8388
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008389 // Add the receiver (same as in function frame).
8390 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8391 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8392 Handle<Object> receiver(it.frame()->receiver());
8393 if (!receiver->IsJSObject()) {
8394 // If the receiver is NOT a JSObject we have hit an optimization
8395 // where a value object is not converted into a wrapped JS objects.
8396 // To hide this optimization from the debugger, we wrap the receiver
8397 // by creating correct wrapper object based on the calling frame's
8398 // global context.
8399 it.Advance();
8400 Handle<Context> calling_frames_global_context(
8401 Context::cast(Context::cast(it.frame()->context())->global_context()));
8402 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8403 }
8404 details->set(kFrameDetailsReceiverIndex, *receiver);
8405
8406 ASSERT_EQ(details_size, details_index);
8407 return *Factory::NewJSArrayWithElements(details);
8408}
8409
8410
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008411// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008412static void CopyContextLocalsToScopeObject(
8413 Handle<SerializedScopeInfo> serialized_scope_info,
8414 ScopeInfo<>& scope_info,
8415 Handle<Context> context,
8416 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008417 // Fill all context locals to the context extension.
8418 for (int i = Context::MIN_CONTEXT_SLOTS;
8419 i < scope_info.number_of_context_slots();
8420 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008421 int context_index = serialized_scope_info->ContextSlotIndex(
8422 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008423
8424 // Don't include the arguments shadow (.arguments) context variable.
8425 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8426 SetProperty(scope_object,
8427 scope_info.context_slot_name(i),
8428 Handle<Object>(context->get(context_index)), NONE);
8429 }
8430 }
8431}
8432
8433
8434// Create a plain JSObject which materializes the local scope for the specified
8435// frame.
8436static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8437 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008438 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008439 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8440 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008441
8442 // Allocate and initialize a JSObject with all the arguments, stack locals
8443 // heap locals and extension properties of the debugged function.
8444 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8445
8446 // First fill all parameters.
8447 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8448 SetProperty(local_scope,
8449 scope_info.parameter_name(i),
8450 Handle<Object>(frame->GetParameter(i)), NONE);
8451 }
8452
8453 // Second fill all stack locals.
8454 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8455 SetProperty(local_scope,
8456 scope_info.stack_slot_name(i),
8457 Handle<Object>(frame->GetExpression(i)), NONE);
8458 }
8459
8460 // Third fill all context locals.
8461 Handle<Context> frame_context(Context::cast(frame->context()));
8462 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008463 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008464 function_context, local_scope);
8465
8466 // Finally copy any properties from the function context extension. This will
8467 // be variables introduced by eval.
8468 if (function_context->closure() == *function) {
8469 if (function_context->has_extension() &&
8470 !function_context->IsGlobalContext()) {
8471 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008472 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008473 for (int i = 0; i < keys->length(); i++) {
8474 // Names of variables introduced by eval are strings.
8475 ASSERT(keys->get(i)->IsString());
8476 Handle<String> key(String::cast(keys->get(i)));
8477 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8478 }
8479 }
8480 }
8481 return local_scope;
8482}
8483
8484
8485// Create a plain JSObject which materializes the closure content for the
8486// context.
8487static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8488 ASSERT(context->is_function_context());
8489
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008490 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008491 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8492 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008493
8494 // Allocate and initialize a JSObject with all the content of theis function
8495 // closure.
8496 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8497
8498 // Check whether the arguments shadow object exists.
8499 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008500 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8501 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008502 if (arguments_shadow_index >= 0) {
8503 // In this case all the arguments are available in the arguments shadow
8504 // object.
8505 Handle<JSObject> arguments_shadow(
8506 JSObject::cast(context->get(arguments_shadow_index)));
8507 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008508 // We don't expect exception-throwing getters on the arguments shadow.
8509 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008510 SetProperty(closure_scope,
8511 scope_info.parameter_name(i),
lrn@chromium.org303ada72010-10-27 09:33:13 +00008512 Handle<Object>(element),
8513 NONE);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008514 }
8515 }
8516
8517 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008518 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8519 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008520
8521 // Finally copy any properties from the function context extension. This will
8522 // be variables introduced by eval.
8523 if (context->has_extension()) {
8524 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008525 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008526 for (int i = 0; i < keys->length(); i++) {
8527 // Names of variables introduced by eval are strings.
8528 ASSERT(keys->get(i)->IsString());
8529 Handle<String> key(String::cast(keys->get(i)));
8530 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
8531 }
8532 }
8533
8534 return closure_scope;
8535}
8536
8537
8538// Iterate over the actual scopes visible from a stack frame. All scopes are
8539// backed by an actual context except the local scope, which is inserted
8540// "artifically" in the context chain.
8541class ScopeIterator {
8542 public:
8543 enum ScopeType {
8544 ScopeTypeGlobal = 0,
8545 ScopeTypeLocal,
8546 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00008547 ScopeTypeClosure,
8548 // Every catch block contains an implicit with block (its parameter is
8549 // a JSContextExtensionObject) that extends current scope with a variable
8550 // holding exception object. Such with blocks are treated as scopes of their
8551 // own type.
8552 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008553 };
8554
8555 explicit ScopeIterator(JavaScriptFrame* frame)
8556 : frame_(frame),
8557 function_(JSFunction::cast(frame->function())),
8558 context_(Context::cast(frame->context())),
8559 local_done_(false),
8560 at_local_(false) {
8561
8562 // Check whether the first scope is actually a local scope.
8563 if (context_->IsGlobalContext()) {
8564 // If there is a stack slot for .result then this local scope has been
8565 // created for evaluating top level code and it is not a real local scope.
8566 // Checking for the existence of .result seems fragile, but the scope info
8567 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008568 int index = function_->shared()->scope_info()->
8569 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008570 at_local_ = index < 0;
8571 } else if (context_->is_function_context()) {
8572 at_local_ = true;
8573 }
8574 }
8575
8576 // More scopes?
8577 bool Done() { return context_.is_null(); }
8578
8579 // Move to the next scope.
8580 void Next() {
8581 // If at a local scope mark the local scope as passed.
8582 if (at_local_) {
8583 at_local_ = false;
8584 local_done_ = true;
8585
8586 // If the current context is not associated with the local scope the
8587 // current context is the next real scope, so don't move to the next
8588 // context in this case.
8589 if (context_->closure() != *function_) {
8590 return;
8591 }
8592 }
8593
8594 // The global scope is always the last in the chain.
8595 if (context_->IsGlobalContext()) {
8596 context_ = Handle<Context>();
8597 return;
8598 }
8599
8600 // Move to the next context.
8601 if (context_->is_function_context()) {
8602 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
8603 } else {
8604 context_ = Handle<Context>(context_->previous());
8605 }
8606
8607 // If passing the local scope indicate that the current scope is now the
8608 // local scope.
8609 if (!local_done_ &&
8610 (context_->IsGlobalContext() || (context_->is_function_context()))) {
8611 at_local_ = true;
8612 }
8613 }
8614
8615 // Return the type of the current scope.
8616 int Type() {
8617 if (at_local_) {
8618 return ScopeTypeLocal;
8619 }
8620 if (context_->IsGlobalContext()) {
8621 ASSERT(context_->global()->IsGlobalObject());
8622 return ScopeTypeGlobal;
8623 }
8624 if (context_->is_function_context()) {
8625 return ScopeTypeClosure;
8626 }
8627 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00008628 // Current scope is either an explicit with statement or a with statement
8629 // implicitely generated for a catch block.
8630 // If the extension object here is a JSContextExtensionObject then
8631 // current with statement is one frome a catch block otherwise it's a
8632 // regular with statement.
8633 if (context_->extension()->IsJSContextExtensionObject()) {
8634 return ScopeTypeCatch;
8635 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008636 return ScopeTypeWith;
8637 }
8638
8639 // Return the JavaScript object with the content of the current scope.
8640 Handle<JSObject> ScopeObject() {
8641 switch (Type()) {
8642 case ScopeIterator::ScopeTypeGlobal:
8643 return Handle<JSObject>(CurrentContext()->global());
8644 break;
8645 case ScopeIterator::ScopeTypeLocal:
8646 // Materialize the content of the local scope into a JSObject.
8647 return MaterializeLocalScope(frame_);
8648 break;
8649 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00008650 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008651 // Return the with object.
8652 return Handle<JSObject>(CurrentContext()->extension());
8653 break;
8654 case ScopeIterator::ScopeTypeClosure:
8655 // Materialize the content of the closure scope into a JSObject.
8656 return MaterializeClosure(CurrentContext());
8657 break;
8658 }
8659 UNREACHABLE();
8660 return Handle<JSObject>();
8661 }
8662
8663 // Return the context for this scope. For the local context there might not
8664 // be an actual context.
8665 Handle<Context> CurrentContext() {
8666 if (at_local_ && context_->closure() != *function_) {
8667 return Handle<Context>();
8668 }
8669 return context_;
8670 }
8671
8672#ifdef DEBUG
8673 // Debug print of the content of the current scope.
8674 void DebugPrint() {
8675 switch (Type()) {
8676 case ScopeIterator::ScopeTypeGlobal:
8677 PrintF("Global:\n");
8678 CurrentContext()->Print();
8679 break;
8680
8681 case ScopeIterator::ScopeTypeLocal: {
8682 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008683 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008684 scope_info.Print();
8685 if (!CurrentContext().is_null()) {
8686 CurrentContext()->Print();
8687 if (CurrentContext()->has_extension()) {
8688 Handle<JSObject> extension =
8689 Handle<JSObject>(CurrentContext()->extension());
8690 if (extension->IsJSContextExtensionObject()) {
8691 extension->Print();
8692 }
8693 }
8694 }
8695 break;
8696 }
8697
8698 case ScopeIterator::ScopeTypeWith: {
8699 PrintF("With:\n");
8700 Handle<JSObject> extension =
8701 Handle<JSObject>(CurrentContext()->extension());
8702 extension->Print();
8703 break;
8704 }
8705
ager@chromium.orga1645e22009-09-09 19:27:10 +00008706 case ScopeIterator::ScopeTypeCatch: {
8707 PrintF("Catch:\n");
8708 Handle<JSObject> extension =
8709 Handle<JSObject>(CurrentContext()->extension());
8710 extension->Print();
8711 break;
8712 }
8713
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008714 case ScopeIterator::ScopeTypeClosure: {
8715 PrintF("Closure:\n");
8716 CurrentContext()->Print();
8717 if (CurrentContext()->has_extension()) {
8718 Handle<JSObject> extension =
8719 Handle<JSObject>(CurrentContext()->extension());
8720 if (extension->IsJSContextExtensionObject()) {
8721 extension->Print();
8722 }
8723 }
8724 break;
8725 }
8726
8727 default:
8728 UNREACHABLE();
8729 }
8730 PrintF("\n");
8731 }
8732#endif
8733
8734 private:
8735 JavaScriptFrame* frame_;
8736 Handle<JSFunction> function_;
8737 Handle<Context> context_;
8738 bool local_done_;
8739 bool at_local_;
8740
8741 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
8742};
8743
8744
lrn@chromium.org303ada72010-10-27 09:33:13 +00008745static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008746 HandleScope scope;
8747 ASSERT(args.length() == 2);
8748
8749 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008750 Object* check;
8751 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8752 if (!maybe_check->ToObject(&check)) return maybe_check;
8753 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008754 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8755
8756 // Get the frame where the debugging is performed.
8757 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8758 JavaScriptFrameIterator it(id);
8759 JavaScriptFrame* frame = it.frame();
8760
8761 // Count the visible scopes.
8762 int n = 0;
8763 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8764 n++;
8765 }
8766
8767 return Smi::FromInt(n);
8768}
8769
8770
8771static const int kScopeDetailsTypeIndex = 0;
8772static const int kScopeDetailsObjectIndex = 1;
8773static const int kScopeDetailsSize = 2;
8774
8775// Return an array with scope details
8776// args[0]: number: break id
8777// args[1]: number: frame index
8778// args[2]: number: scope index
8779//
8780// The array returned contains the following information:
8781// 0: Scope type
8782// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00008783static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008784 HandleScope scope;
8785 ASSERT(args.length() == 3);
8786
8787 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008788 Object* check;
8789 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8790 if (!maybe_check->ToObject(&check)) return maybe_check;
8791 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008792 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8793 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
8794
8795 // Get the frame where the debugging is performed.
8796 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8797 JavaScriptFrameIterator frame_it(id);
8798 JavaScriptFrame* frame = frame_it.frame();
8799
8800 // Find the requested scope.
8801 int n = 0;
8802 ScopeIterator it(frame);
8803 for (; !it.Done() && n < index; it.Next()) {
8804 n++;
8805 }
8806 if (it.Done()) {
8807 return Heap::undefined_value();
8808 }
8809
8810 // Calculate the size of the result.
8811 int details_size = kScopeDetailsSize;
8812 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8813
8814 // Fill in scope details.
8815 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008816 Handle<JSObject> scope_object = it.ScopeObject();
8817 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008818
8819 return *Factory::NewJSArrayWithElements(details);
8820}
8821
8822
lrn@chromium.org303ada72010-10-27 09:33:13 +00008823static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008824 HandleScope scope;
8825 ASSERT(args.length() == 0);
8826
8827#ifdef DEBUG
8828 // Print the scopes for the top frame.
8829 StackFrameLocator locator;
8830 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
8831 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8832 it.DebugPrint();
8833 }
8834#endif
8835 return Heap::undefined_value();
8836}
8837
8838
lrn@chromium.org303ada72010-10-27 09:33:13 +00008839static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008840 HandleScope scope;
8841 ASSERT(args.length() == 1);
8842
8843 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008844 Object* result;
8845 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8846 if (!maybe_result->ToObject(&result)) return maybe_result;
8847 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008848
8849 // Count all archived V8 threads.
8850 int n = 0;
8851 for (ThreadState* thread = ThreadState::FirstInUse();
8852 thread != NULL;
8853 thread = thread->Next()) {
8854 n++;
8855 }
8856
8857 // Total number of threads is current thread and archived threads.
8858 return Smi::FromInt(n + 1);
8859}
8860
8861
8862static const int kThreadDetailsCurrentThreadIndex = 0;
8863static const int kThreadDetailsThreadIdIndex = 1;
8864static const int kThreadDetailsSize = 2;
8865
8866// Return an array with thread details
8867// args[0]: number: break id
8868// args[1]: number: thread index
8869//
8870// The array returned contains the following information:
8871// 0: Is current thread?
8872// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00008873static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008874 HandleScope scope;
8875 ASSERT(args.length() == 2);
8876
8877 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008878 Object* check;
8879 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8880 if (!maybe_check->ToObject(&check)) return maybe_check;
8881 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008882 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8883
8884 // Allocate array for result.
8885 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
8886
8887 // Thread index 0 is current thread.
8888 if (index == 0) {
8889 // Fill the details.
8890 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
8891 details->set(kThreadDetailsThreadIdIndex,
8892 Smi::FromInt(ThreadManager::CurrentId()));
8893 } else {
8894 // Find the thread with the requested index.
8895 int n = 1;
8896 ThreadState* thread = ThreadState::FirstInUse();
8897 while (index != n && thread != NULL) {
8898 thread = thread->Next();
8899 n++;
8900 }
8901 if (thread == NULL) {
8902 return Heap::undefined_value();
8903 }
8904
8905 // Fill the details.
8906 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
8907 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
8908 }
8909
8910 // Convert to JS array and return.
8911 return *Factory::NewJSArrayWithElements(details);
8912}
8913
8914
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008915// Sets the disable break state
8916// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00008917static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008918 HandleScope scope;
8919 ASSERT(args.length() == 1);
8920 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
8921 Debug::set_disable_break(disable_break);
8922 return Heap::undefined_value();
8923}
8924
8925
lrn@chromium.org303ada72010-10-27 09:33:13 +00008926static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008927 HandleScope scope;
8928 ASSERT(args.length() == 1);
8929
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008930 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8931 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008932 // Find the number of break points
8933 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
8934 if (break_locations->IsUndefined()) return Heap::undefined_value();
8935 // Return array as JS array
8936 return *Factory::NewJSArrayWithElements(
8937 Handle<FixedArray>::cast(break_locations));
8938}
8939
8940
8941// Set a break point in a function
8942// args[0]: function
8943// args[1]: number: break source position (within the function source)
8944// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00008945static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008946 HandleScope scope;
8947 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008948 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8949 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008950 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
8951 RUNTIME_ASSERT(source_position >= 0);
8952 Handle<Object> break_point_object_arg = args.at<Object>(2);
8953
8954 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008955 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008956
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008957 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008958}
8959
8960
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00008961Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
8962 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008963 // Iterate the heap looking for SharedFunctionInfo generated from the
8964 // script. The inner most SharedFunctionInfo containing the source position
8965 // for the requested break point is found.
8966 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
8967 // which is found is not compiled it is compiled and the heap is iterated
8968 // again as the compilation might create inner functions from the newly
8969 // compiled function and the actual requested break point might be in one of
8970 // these functions.
8971 bool done = false;
8972 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00008973 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008974 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008975 while (!done) {
8976 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008977 for (HeapObject* obj = iterator.next();
8978 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008979 if (obj->IsSharedFunctionInfo()) {
8980 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
8981 if (shared->script() == *script) {
8982 // If the SharedFunctionInfo found has the requested script data and
8983 // contains the source position it is a candidate.
8984 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00008985 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008986 start_position = shared->start_position();
8987 }
8988 if (start_position <= position &&
8989 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00008990 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008991 // candidate this is the new candidate.
8992 if (target.is_null()) {
8993 target_start_position = start_position;
8994 target = shared;
8995 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00008996 if (target_start_position == start_position &&
8997 shared->end_position() == target->end_position()) {
8998 // If a top-level function contain only one function
8999 // declartion the source for the top-level and the function is
9000 // the same. In that case prefer the non top-level function.
9001 if (!shared->is_toplevel()) {
9002 target_start_position = start_position;
9003 target = shared;
9004 }
9005 } else if (target_start_position <= start_position &&
9006 shared->end_position() <= target->end_position()) {
9007 // This containment check includes equality as a function inside
9008 // a top-level function can share either start or end position
9009 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009010 target_start_position = start_position;
9011 target = shared;
9012 }
9013 }
9014 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009015 }
9016 }
9017 }
9018
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009020 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009021 }
9022
9023 // If the candidate found is compiled we are done. NOTE: when lazy
9024 // compilation of inner functions is introduced some additional checking
9025 // needs to be done here to compile inner functions.
9026 done = target->is_compiled();
9027 if (!done) {
9028 // If the candidate is not compiled compile it to reveal any inner
9029 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009030 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031 }
9032 }
9033
9034 return *target;
9035}
9036
9037
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009038// Changes the state of a break point in a script and returns source position
9039// where break point was set. NOTE: Regarding performance see the NOTE for
9040// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009041// args[0]: script to set break point in
9042// args[1]: number: break source position (within the script source)
9043// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009044static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009045 HandleScope scope;
9046 ASSERT(args.length() == 3);
9047 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9048 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9049 RUNTIME_ASSERT(source_position >= 0);
9050 Handle<Object> break_point_object_arg = args.at<Object>(2);
9051
9052 // Get the script from the script wrapper.
9053 RUNTIME_ASSERT(wrapper->value()->IsScript());
9054 Handle<Script> script(Script::cast(wrapper->value()));
9055
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009056 Object* result = Runtime::FindSharedFunctionInfoInScript(
9057 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058 if (!result->IsUndefined()) {
9059 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9060 // Find position within function. The script position might be before the
9061 // source position of the first function.
9062 int position;
9063 if (shared->start_position() > source_position) {
9064 position = 0;
9065 } else {
9066 position = source_position - shared->start_position();
9067 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009068 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9069 position += shared->start_position();
9070 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071 }
9072 return Heap::undefined_value();
9073}
9074
9075
9076// Clear a break point
9077// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009078static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009079 HandleScope scope;
9080 ASSERT(args.length() == 1);
9081 Handle<Object> break_point_object_arg = args.at<Object>(0);
9082
9083 // Clear break point.
9084 Debug::ClearBreakPoint(break_point_object_arg);
9085
9086 return Heap::undefined_value();
9087}
9088
9089
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009090// Change the state of break on exceptions.
9091// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9092// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009093static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009094 HandleScope scope;
9095 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009096 RUNTIME_ASSERT(args[0]->IsNumber());
9097 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009099 // If the number doesn't match an enum value, the ChangeBreakOnException
9100 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009101 ExceptionBreakType type =
9102 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009103 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009104 Debug::ChangeBreakOnException(type, enable);
9105 return Heap::undefined_value();
9106}
9107
9108
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009109// Returns the state of break on exceptions
9110// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009111static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009112 HandleScope scope;
9113 ASSERT(args.length() == 1);
9114 RUNTIME_ASSERT(args[0]->IsNumber());
9115
9116 ExceptionBreakType type =
9117 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9118 bool result = Debug::IsBreakOnException(type);
9119 return Smi::FromInt(result);
9120}
9121
9122
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009123// Prepare for stepping
9124// args[0]: break id for checking execution state
9125// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009126// args[2]: number of times to perform the step, for step out it is the number
9127// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009128static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009129 HandleScope scope;
9130 ASSERT(args.length() == 3);
9131 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009132 Object* check;
9133 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9134 if (!maybe_check->ToObject(&check)) return maybe_check;
9135 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009136 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9137 return Top::Throw(Heap::illegal_argument_symbol());
9138 }
9139
9140 // Get the step action and check validity.
9141 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9142 if (step_action != StepIn &&
9143 step_action != StepNext &&
9144 step_action != StepOut &&
9145 step_action != StepInMin &&
9146 step_action != StepMin) {
9147 return Top::Throw(Heap::illegal_argument_symbol());
9148 }
9149
9150 // Get the number of steps.
9151 int step_count = NumberToInt32(args[2]);
9152 if (step_count < 1) {
9153 return Top::Throw(Heap::illegal_argument_symbol());
9154 }
9155
ager@chromium.orga1645e22009-09-09 19:27:10 +00009156 // Clear all current stepping setup.
9157 Debug::ClearStepping();
9158
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 // Prepare step.
9160 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9161 return Heap::undefined_value();
9162}
9163
9164
9165// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009166static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009167 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009168 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009169 Debug::ClearStepping();
9170 return Heap::undefined_value();
9171}
9172
9173
9174// Creates a copy of the with context chain. The copy of the context chain is
9175// is linked to the function context supplied.
9176static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9177 Handle<Context> function_context) {
9178 // At the bottom of the chain. Return the function context to link to.
9179 if (context_chain->is_function_context()) {
9180 return function_context;
9181 }
9182
9183 // Recursively copy the with contexts.
9184 Handle<Context> previous(context_chain->previous());
9185 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009186 Handle<Context> context = CopyWithContextChain(function_context, previous);
9187 return Factory::NewWithContext(context,
9188 extension,
9189 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009190}
9191
9192
9193// Helper function to find or create the arguments object for
9194// Runtime_DebugEvaluate.
9195static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9196 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009197 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009198 const ScopeInfo<>* sinfo,
9199 Handle<Context> function_context) {
9200 // Try to find the value of 'arguments' to pass as parameter. If it is not
9201 // found (that is the debugged function does not reference 'arguments' and
9202 // does not support eval) then create an 'arguments' object.
9203 int index;
9204 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009205 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009206 if (index != -1) {
9207 return Handle<Object>(frame->GetExpression(index));
9208 }
9209 }
9210
9211 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009212 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009213 if (index != -1) {
9214 return Handle<Object>(function_context->get(index));
9215 }
9216 }
9217
9218 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009219 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9220 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009221
9222 AssertNoAllocation no_gc;
9223 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009224 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009225 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009226 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009227 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228 return arguments;
9229}
9230
9231
9232// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009233// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234// extension part has all the parameters and locals of the function on the
9235// stack frame. A function which calls eval with the code to evaluate is then
9236// compiled in this context and called in this context. As this context
9237// replaces the context of the function on the stack frame a new (empty)
9238// function is created as well to be used as the closure for the context.
9239// This function and the context acts as replacements for the function on the
9240// stack frame presenting the same view of the values of parameters and
9241// local variables as if the piece of JavaScript was evaluated at the point
9242// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009243static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244 HandleScope scope;
9245
9246 // Check the execution state and decode arguments frame and source to be
9247 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009248 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009249 Object* check_result;
9250 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9251 if (!maybe_check_result->ToObject(&check_result)) {
9252 return maybe_check_result;
9253 }
9254 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009255 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9256 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009257 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
9258
9259 // Handle the processing of break.
9260 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009261
9262 // Get the frame where the debugging is performed.
9263 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9264 JavaScriptFrameIterator it(id);
9265 JavaScriptFrame* frame = it.frame();
9266 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009267 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009268 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009269
9270 // Traverse the saved contexts chain to find the active context for the
9271 // selected frame.
9272 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009273 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009274 save = save->prev();
9275 }
9276 ASSERT(save != NULL);
9277 SaveContext savex;
9278 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009279
9280 // Create the (empty) function replacing the function on the stack frame for
9281 // the purpose of evaluating in the context created below. It is important
9282 // that this function does not describe any parameters and local variables
9283 // in the context. If it does then this will cause problems with the lookup
9284 // in Context::Lookup, where context slots for parameters and local variables
9285 // are looked at before the extension object.
9286 Handle<JSFunction> go_between =
9287 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9288 go_between->set_context(function->context());
9289#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009290 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009291 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9292 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9293#endif
9294
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009295 // Materialize the content of the local scope into a JSObject.
9296 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009297
9298 // Allocate a new context for the debug evaluation and set the extension
9299 // object build.
9300 Handle<Context> context =
9301 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009302 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009303 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009304 Handle<Context> frame_context(Context::cast(frame->context()));
9305 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009306 context = CopyWithContextChain(frame_context, context);
9307
9308 // Wrap the evaluation statement in a new function compiled in the newly
9309 // created context. The function has one parameter which has to be called
9310 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009311 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312 // function(arguments,__source__) {return eval(__source__);}
9313 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009314 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009315 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009316 Handle<String> function_source =
9317 Factory::NewStringFromAscii(Vector<const char>(source_str,
9318 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009319 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009320 Compiler::CompileEval(function_source,
9321 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009322 context->IsGlobalContext());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009323 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009324 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009325 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009326
9327 // Invoke the result of the compilation to get the evaluation function.
9328 bool has_pending_exception;
9329 Handle<Object> receiver(frame->receiver());
9330 Handle<Object> evaluation_function =
9331 Execution::Call(compiled_function, receiver, 0, NULL,
9332 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009333 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009334
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009335 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9336 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009337
9338 // Invoke the evaluation function and return the result.
9339 const int argc = 2;
9340 Object** argv[argc] = { arguments.location(),
9341 Handle<Object>::cast(source).location() };
9342 Handle<Object> result =
9343 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9344 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009345 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009346
9347 // Skip the global proxy as it has no properties and always delegates to the
9348 // real global object.
9349 if (result->IsJSGlobalProxy()) {
9350 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9351 }
9352
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009353 return *result;
9354}
9355
9356
lrn@chromium.org303ada72010-10-27 09:33:13 +00009357static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009358 HandleScope scope;
9359
9360 // Check the execution state and decode arguments frame and source to be
9361 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009362 ASSERT(args.length() == 3);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009363 Object* check_result;
9364 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9365 if (!maybe_check_result->ToObject(&check_result)) {
9366 return maybe_check_result;
9367 }
9368 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009369 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009370 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
9371
9372 // Handle the processing of break.
9373 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009374
9375 // Enter the top context from before the debugger was invoked.
9376 SaveContext save;
9377 SaveContext* top = &save;
9378 while (top != NULL && *top->context() == *Debug::debug_context()) {
9379 top = top->prev();
9380 }
9381 if (top != NULL) {
9382 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009383 }
9384
9385 // Get the global context now set to the top context from before the
9386 // debugger was invoked.
9387 Handle<Context> context = Top::global_context();
9388
9389 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009390 Handle<SharedFunctionInfo> shared =
9391 Compiler::CompileEval(source,
9392 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009393 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009394 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009395 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009396 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9397 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009398
9399 // Invoke the result of the compilation to get the evaluation function.
9400 bool has_pending_exception;
9401 Handle<Object> receiver = Top::global();
9402 Handle<Object> result =
9403 Execution::Call(compiled_function, receiver, 0, NULL,
9404 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009405 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009406 return *result;
9407}
9408
9409
lrn@chromium.org303ada72010-10-27 09:33:13 +00009410static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009411 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009412 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009414 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009415 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009416
9417 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009418 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009419 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9420 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9421 // because using
9422 // instances->set(i, *GetScriptWrapper(script))
9423 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9424 // already have deferenced the instances handle.
9425 Handle<JSValue> wrapper = GetScriptWrapper(script);
9426 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009427 }
9428
9429 // Return result as a JS array.
9430 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9431 Handle<JSArray>::cast(result)->SetContent(*instances);
9432 return *result;
9433}
9434
9435
9436// Helper function used by Runtime_DebugReferencedBy below.
9437static int DebugReferencedBy(JSObject* target,
9438 Object* instance_filter, int max_references,
9439 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009440 JSFunction* arguments_function) {
9441 NoHandleAllocation ha;
9442 AssertNoAllocation no_alloc;
9443
9444 // Iterate the heap.
9445 int count = 0;
9446 JSObject* last = NULL;
9447 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009448 HeapObject* heap_obj = NULL;
9449 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009450 (max_references == 0 || count < max_references)) {
9451 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009452 if (heap_obj->IsJSObject()) {
9453 // Skip context extension objects and argument arrays as these are
9454 // checked in the context of functions using them.
9455 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009456 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009457 obj->map()->constructor() == arguments_function) {
9458 continue;
9459 }
9460
9461 // Check if the JS object has a reference to the object looked for.
9462 if (obj->ReferencesObject(target)) {
9463 // Check instance filter if supplied. This is normally used to avoid
9464 // references from mirror objects (see Runtime_IsInPrototypeChain).
9465 if (!instance_filter->IsUndefined()) {
9466 Object* V = obj;
9467 while (true) {
9468 Object* prototype = V->GetPrototype();
9469 if (prototype->IsNull()) {
9470 break;
9471 }
9472 if (instance_filter == prototype) {
9473 obj = NULL; // Don't add this object.
9474 break;
9475 }
9476 V = prototype;
9477 }
9478 }
9479
9480 if (obj != NULL) {
9481 // Valid reference found add to instance array if supplied an update
9482 // count.
9483 if (instances != NULL && count < instances_size) {
9484 instances->set(count, obj);
9485 }
9486 last = obj;
9487 count++;
9488 }
9489 }
9490 }
9491 }
9492
9493 // Check for circular reference only. This can happen when the object is only
9494 // referenced from mirrors and has a circular reference in which case the
9495 // object is not really alive and would have been garbage collected if not
9496 // referenced from the mirror.
9497 if (count == 1 && last == target) {
9498 count = 0;
9499 }
9500
9501 // Return the number of referencing objects found.
9502 return count;
9503}
9504
9505
9506// Scan the heap for objects with direct references to an object
9507// args[0]: the object to find references to
9508// args[1]: constructor function for instances to exclude (Mirror)
9509// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +00009510static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009511 ASSERT(args.length() == 3);
9512
9513 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009514 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009515
9516 // Check parameters.
9517 CONVERT_CHECKED(JSObject, target, args[0]);
9518 Object* instance_filter = args[1];
9519 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
9520 instance_filter->IsJSObject());
9521 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
9522 RUNTIME_ASSERT(max_references >= 0);
9523
9524 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009525 JSObject* arguments_boilerplate =
9526 Top::context()->global_context()->arguments_boilerplate();
9527 JSFunction* arguments_function =
9528 JSFunction::cast(arguments_boilerplate->map()->constructor());
9529
9530 // Get the number of referencing objects.
9531 int count;
9532 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009533 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009534
9535 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009536 Object* object;
9537 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9538 if (!maybe_object->ToObject(&object)) return maybe_object;
9539 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009540 FixedArray* instances = FixedArray::cast(object);
9541
9542 // Fill the referencing objects.
9543 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009544 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009545
9546 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009547 Object* result;
9548 { MaybeObject* maybe_result = Heap::AllocateJSObject(
9549 Top::context()->global_context()->array_function());
9550 if (!maybe_result->ToObject(&result)) return maybe_result;
9551 }
9552 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009553 return result;
9554}
9555
9556
9557// Helper function used by Runtime_DebugConstructedBy below.
9558static int DebugConstructedBy(JSFunction* constructor, int max_references,
9559 FixedArray* instances, int instances_size) {
9560 AssertNoAllocation no_alloc;
9561
9562 // Iterate the heap.
9563 int count = 0;
9564 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009565 HeapObject* heap_obj = NULL;
9566 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009567 (max_references == 0 || count < max_references)) {
9568 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009569 if (heap_obj->IsJSObject()) {
9570 JSObject* obj = JSObject::cast(heap_obj);
9571 if (obj->map()->constructor() == constructor) {
9572 // Valid reference found add to instance array if supplied an update
9573 // count.
9574 if (instances != NULL && count < instances_size) {
9575 instances->set(count, obj);
9576 }
9577 count++;
9578 }
9579 }
9580 }
9581
9582 // Return the number of referencing objects found.
9583 return count;
9584}
9585
9586
9587// Scan the heap for objects constructed by a specific function.
9588// args[0]: the constructor to find instances of
9589// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +00009590static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009591 ASSERT(args.length() == 2);
9592
9593 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009594 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009595
9596 // Check parameters.
9597 CONVERT_CHECKED(JSFunction, constructor, args[0]);
9598 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
9599 RUNTIME_ASSERT(max_references >= 0);
9600
9601 // Get the number of referencing objects.
9602 int count;
9603 count = DebugConstructedBy(constructor, max_references, NULL, 0);
9604
9605 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009606 Object* object;
9607 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9608 if (!maybe_object->ToObject(&object)) return maybe_object;
9609 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009610 FixedArray* instances = FixedArray::cast(object);
9611
9612 // Fill the referencing objects.
9613 count = DebugConstructedBy(constructor, max_references, instances, count);
9614
9615 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009616 Object* result;
9617 { MaybeObject* maybe_result = Heap::AllocateJSObject(
9618 Top::context()->global_context()->array_function());
9619 if (!maybe_result->ToObject(&result)) return maybe_result;
9620 }
9621 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009622 return result;
9623}
9624
9625
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009626// Find the effective prototype object as returned by __proto__.
9627// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009628static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009629 ASSERT(args.length() == 1);
9630
9631 CONVERT_CHECKED(JSObject, obj, args[0]);
9632
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009633 // Use the __proto__ accessor.
9634 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009635}
9636
9637
lrn@chromium.org303ada72010-10-27 09:33:13 +00009638static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00009639 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009640 CPU::DebugBreak();
9641 return Heap::undefined_value();
9642}
9643
9644
lrn@chromium.org303ada72010-10-27 09:33:13 +00009645static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009646#ifdef DEBUG
9647 HandleScope scope;
9648 ASSERT(args.length() == 1);
9649 // Get the function and make sure it is compiled.
9650 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009651 Handle<SharedFunctionInfo> shared(func->shared());
9652 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009653 return Failure::Exception();
9654 }
9655 func->code()->PrintLn();
9656#endif // DEBUG
9657 return Heap::undefined_value();
9658}
ager@chromium.org9085a012009-05-11 19:22:57 +00009659
9660
lrn@chromium.org303ada72010-10-27 09:33:13 +00009661static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009662#ifdef DEBUG
9663 HandleScope scope;
9664 ASSERT(args.length() == 1);
9665 // Get the function and make sure it is compiled.
9666 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009667 Handle<SharedFunctionInfo> shared(func->shared());
9668 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009669 return Failure::Exception();
9670 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009671 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009672#endif // DEBUG
9673 return Heap::undefined_value();
9674}
9675
9676
lrn@chromium.org303ada72010-10-27 09:33:13 +00009677static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +00009678 NoHandleAllocation ha;
9679 ASSERT(args.length() == 1);
9680
9681 CONVERT_CHECKED(JSFunction, f, args[0]);
9682 return f->shared()->inferred_name();
9683}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009684
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009685
9686static int FindSharedFunctionInfosForScript(Script* script,
9687 FixedArray* buffer) {
9688 AssertNoAllocation no_allocations;
9689
9690 int counter = 0;
9691 int buffer_size = buffer->length();
9692 HeapIterator iterator;
9693 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
9694 ASSERT(obj != NULL);
9695 if (!obj->IsSharedFunctionInfo()) {
9696 continue;
9697 }
9698 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
9699 if (shared->script() != script) {
9700 continue;
9701 }
9702 if (counter < buffer_size) {
9703 buffer->set(counter, shared);
9704 }
9705 counter++;
9706 }
9707 return counter;
9708}
9709
9710// For a script finds all SharedFunctionInfo's in the heap that points
9711// to this script. Returns JSArray of SharedFunctionInfo wrapped
9712// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009713static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009714 Arguments args) {
9715 ASSERT(args.length() == 1);
9716 HandleScope scope;
9717 CONVERT_CHECKED(JSValue, script_value, args[0]);
9718
9719 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
9720
9721 const int kBufferSize = 32;
9722
9723 Handle<FixedArray> array;
9724 array = Factory::NewFixedArray(kBufferSize);
9725 int number = FindSharedFunctionInfosForScript(*script, *array);
9726 if (number > kBufferSize) {
9727 array = Factory::NewFixedArray(number);
9728 FindSharedFunctionInfosForScript(*script, *array);
9729 }
9730
9731 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
9732 result->set_length(Smi::FromInt(number));
9733
9734 LiveEdit::WrapSharedFunctionInfos(result);
9735
9736 return *result;
9737}
9738
9739// For a script calculates compilation information about all its functions.
9740// The script source is explicitly specified by the second argument.
9741// The source of the actual script is not used, however it is important that
9742// all generated code keeps references to this particular instance of script.
9743// Returns a JSArray of compilation infos. The array is ordered so that
9744// each function with all its descendant is always stored in a continues range
9745// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009746static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009747 ASSERT(args.length() == 2);
9748 HandleScope scope;
9749 CONVERT_CHECKED(JSValue, script, args[0]);
9750 CONVERT_ARG_CHECKED(String, source, 1);
9751 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
9752
9753 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
9754
9755 if (Top::has_pending_exception()) {
9756 return Failure::Exception();
9757 }
9758
9759 return result;
9760}
9761
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009762// Changes the source of the script to a new_source.
9763// If old_script_name is provided (i.e. is a String), also creates a copy of
9764// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009765static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009766 ASSERT(args.length() == 3);
9767 HandleScope scope;
9768 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
9769 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009770 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009771
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009772 CONVERT_CHECKED(Script, original_script_pointer,
9773 original_script_value->value());
9774 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009775
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009776 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
9777 new_source,
9778 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009779
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009780 if (old_script->IsScript()) {
9781 Handle<Script> script_handle(Script::cast(old_script));
9782 return *(GetScriptWrapper(script_handle));
9783 } else {
9784 return Heap::null_value();
9785 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009786}
9787
9788// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009789static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009790 ASSERT(args.length() == 2);
9791 HandleScope scope;
9792 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
9793 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
9794
ager@chromium.orgac091b72010-05-05 07:34:42 +00009795 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009796}
9797
9798// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009799static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009800 ASSERT(args.length() == 2);
9801 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009802 Handle<Object> function_object(args[0]);
9803 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009804
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009805 if (function_object->IsJSValue()) {
9806 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
9807 if (script_object->IsJSValue()) {
9808 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
9809 script_object = Handle<Object>(script);
9810 }
9811
9812 LiveEdit::SetFunctionScript(function_wrapper, script_object);
9813 } else {
9814 // Just ignore this. We may not have a SharedFunctionInfo for some functions
9815 // and we check it in this function.
9816 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009817
9818 return Heap::undefined_value();
9819}
9820
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009821
9822// In a code of a parent function replaces original function as embedded object
9823// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009824static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009825 ASSERT(args.length() == 3);
9826 HandleScope scope;
9827
9828 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
9829 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
9830 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
9831
9832 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
9833 subst_wrapper);
9834
9835 return Heap::undefined_value();
9836}
9837
9838
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009839// Updates positions of a shared function info (first parameter) according
9840// to script source change. Text change is described in second parameter as
9841// array of groups of 3 numbers:
9842// (change_begin, change_end, change_end_new_position).
9843// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009844static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009845 ASSERT(args.length() == 2);
9846 HandleScope scope;
9847 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
9848 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
9849
ager@chromium.orgac091b72010-05-05 07:34:42 +00009850 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009851}
9852
9853
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009854// For array of SharedFunctionInfo's (each wrapped in JSValue)
9855// checks that none of them have activations on stacks (of any thread).
9856// Returns array of the same length with corresponding results of
9857// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009858static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00009859 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009860 HandleScope scope;
9861 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +00009862 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009863
ager@chromium.org357bf652010-04-12 11:30:10 +00009864 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009865}
9866
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009867// Compares 2 strings line-by-line and returns diff in form of JSArray of
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00009868// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009869static MaybeObject* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009870 ASSERT(args.length() == 2);
9871 HandleScope scope;
9872 CONVERT_ARG_CHECKED(String, s1, 0);
9873 CONVERT_ARG_CHECKED(String, s2, 1);
9874
9875 return *LiveEdit::CompareStringsLinewise(s1, s2);
9876}
9877
9878
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009879
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009880// A testing entry. Returns statement position which is the closest to
9881// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009882static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009883 ASSERT(args.length() == 2);
9884 HandleScope scope;
9885 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9886 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9887
9888 Handle<Code> code(function->code());
9889
9890 RelocIterator it(*code, 1 << RelocInfo::STATEMENT_POSITION);
9891 int closest_pc = 0;
9892 int distance = kMaxInt;
9893 while (!it.done()) {
9894 int statement_position = static_cast<int>(it.rinfo()->data());
9895 // Check if this break point is closer that what was previously found.
9896 if (source_position <= statement_position &&
9897 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00009898 closest_pc =
9899 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009900 distance = statement_position - source_position;
9901 // Check whether we can't get any closer.
9902 if (distance == 0) break;
9903 }
9904 it.next();
9905 }
9906
9907 return Smi::FromInt(closest_pc);
9908}
9909
9910
ager@chromium.org357bf652010-04-12 11:30:10 +00009911// Calls specified function with or without entering the debugger.
9912// This is used in unit tests to run code as if debugger is entered or simply
9913// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009914static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00009915 ASSERT(args.length() == 2);
9916 HandleScope scope;
9917 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9918 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
9919
9920 Handle<Object> result;
9921 bool pending_exception;
9922 {
9923 if (without_debugger) {
9924 result = Execution::Call(function, Top::global(), 0, NULL,
9925 &pending_exception);
9926 } else {
9927 EnterDebugger enter_debugger;
9928 result = Execution::Call(function, Top::global(), 0, NULL,
9929 &pending_exception);
9930 }
9931 }
9932 if (!pending_exception) {
9933 return *result;
9934 } else {
9935 return Failure::Exception();
9936 }
9937}
9938
9939
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009940#endif // ENABLE_DEBUGGER_SUPPORT
9941
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009942#ifdef ENABLE_LOGGING_AND_PROFILING
9943
lrn@chromium.org303ada72010-10-27 09:33:13 +00009944static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009945 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009946 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009947
9948 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009949 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9950 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009951 return Heap::undefined_value();
9952}
9953
9954
lrn@chromium.org303ada72010-10-27 09:33:13 +00009955static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009956 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009957 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009958
9959 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009960 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9961 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009962 return Heap::undefined_value();
9963}
9964
9965#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009966
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009967// Finds the script object from the script data. NOTE: This operation uses
9968// heap traversal to find the function generated for the source position
9969// for the requested break point. For lazily compiled functions several heap
9970// traversals might be required rendering this operation as a rather slow
9971// operation. However for setting break points which is normally done through
9972// some kind of user interaction the performance is not crucial.
9973static Handle<Object> Runtime_GetScriptFromScriptName(
9974 Handle<String> script_name) {
9975 // Scan the heap for Script objects to find the script with the requested
9976 // script data.
9977 Handle<Script> script;
9978 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009979 HeapObject* obj = NULL;
9980 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009981 // If a script is found check if it has the script data requested.
9982 if (obj->IsScript()) {
9983 if (Script::cast(obj)->name()->IsString()) {
9984 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
9985 script = Handle<Script>(Script::cast(obj));
9986 }
9987 }
9988 }
9989 }
9990
9991 // If no script with the requested script data is found return undefined.
9992 if (script.is_null()) return Factory::undefined_value();
9993
9994 // Return the script found.
9995 return GetScriptWrapper(script);
9996}
9997
9998
9999// Get the script object from script data. NOTE: Regarding performance
10000// see the NOTE for GetScriptFromScriptData.
10001// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010002static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010003 HandleScope scope;
10004
10005 ASSERT(args.length() == 1);
10006
10007 CONVERT_CHECKED(String, script_name, args[0]);
10008
10009 // Find the requested script.
10010 Handle<Object> result =
10011 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10012 return *result;
10013}
10014
10015
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010016// Determines whether the given stack frame should be displayed in
10017// a stack trace. The caller is the error constructor that asked
10018// for the stack trace to be collected. The first time a construct
10019// call to this function is encountered it is skipped. The seen_caller
10020// in/out parameter is used to remember if the caller has been seen
10021// yet.
10022static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10023 bool* seen_caller) {
10024 // Only display JS frames.
10025 if (!raw_frame->is_java_script())
10026 return false;
10027 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10028 Object* raw_fun = frame->function();
10029 // Not sure when this can happen but skip it just in case.
10030 if (!raw_fun->IsJSFunction())
10031 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010032 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010033 *seen_caller = true;
10034 return false;
10035 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010036 // Skip all frames until we've seen the caller. Also, skip the most
10037 // obvious builtin calls. Some builtin calls (such as Number.ADD
10038 // which is invoked using 'call') are very difficult to recognize
10039 // so we're leaving them in for now.
10040 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010041}
10042
10043
10044// Collect the raw data for a stack trace. Returns an array of three
10045// element segments each containing a receiver, function and native
10046// code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010047static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010048 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010049 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010050 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10051
10052 HandleScope scope;
10053
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010054 limit = Max(limit, 0); // Ensure that limit is not negative.
10055 int initial_size = Min(limit, 10);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010056 Handle<JSArray> result = Factory::NewJSArray(initial_size * 3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010057
10058 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010059 // If the caller parameter is a function we skip frames until we're
10060 // under it before starting to collect.
10061 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010062 int cursor = 0;
10063 int frames_seen = 0;
10064 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010065 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010066 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010067 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010068 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010069 Object* recv = frame->receiver();
10070 Object* fun = frame->function();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010071 Address pc = frame->pc();
10072 Address start = frame->code()->address();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010073 Smi* offset = Smi::FromInt(static_cast<int>(pc - start));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010074 FixedArray* elements = FixedArray::cast(result->elements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010075 if (cursor + 2 < elements->length()) {
10076 elements->set(cursor++, recv);
10077 elements->set(cursor++, fun);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010078 elements->set(cursor++, offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010079 } else {
10080 HandleScope scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010081 Handle<Object> recv_handle(recv);
10082 Handle<Object> fun_handle(fun);
10083 SetElement(result, cursor++, recv_handle);
10084 SetElement(result, cursor++, fun_handle);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010085 SetElement(result, cursor++, Handle<Smi>(offset));
10086 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010087 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010088 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010089 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010090
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010091 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010092 return *result;
10093}
10094
10095
ager@chromium.org3811b432009-10-28 14:53:37 +000010096// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010097static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010098 ASSERT_EQ(args.length(), 0);
10099
10100 NoHandleAllocation ha;
10101
10102 const char* version_string = v8::V8::GetVersion();
10103
10104 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10105}
10106
10107
lrn@chromium.org303ada72010-10-27 09:33:13 +000010108static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010109 ASSERT(args.length() == 2);
10110 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10111 Smi::cast(args[1])->value());
10112 Top::PrintStack();
10113 OS::Abort();
10114 UNREACHABLE();
10115 return NULL;
10116}
10117
10118
lrn@chromium.org303ada72010-10-27 09:33:13 +000010119MUST_USE_RESULT static MaybeObject* CacheMiss(FixedArray* cache_obj,
10120 int index,
10121 Object* key_obj) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010122 ASSERT(index % 2 == 0); // index of the key
10123 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10124 ASSERT(index < cache_obj->length());
10125
10126 HandleScope scope;
10127
10128 Handle<FixedArray> cache(cache_obj);
10129 Handle<Object> key(key_obj);
10130 Handle<JSFunction> factory(JSFunction::cast(
10131 cache->get(JSFunctionResultCache::kFactoryIndex)));
10132 // TODO(antonm): consider passing a receiver when constructing a cache.
10133 Handle<Object> receiver(Top::global_context()->global());
10134
10135 Handle<Object> value;
10136 {
10137 // This handle is nor shared, nor used later, so it's safe.
10138 Object** argv[] = { key.location() };
10139 bool pending_exception = false;
10140 value = Execution::Call(factory,
10141 receiver,
10142 1,
10143 argv,
10144 &pending_exception);
10145 if (pending_exception) return Failure::Exception();
10146 }
10147
10148 cache->set(index, *key);
10149 cache->set(index + 1, *value);
10150 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index));
10151
10152 return *value;
10153}
10154
10155
lrn@chromium.org303ada72010-10-27 09:33:13 +000010156static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010157 // This is only called from codegen, so checks might be more lax.
10158 CONVERT_CHECKED(FixedArray, cache, args[0]);
10159 Object* key = args[1];
10160
10161 const int finger_index =
10162 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value();
10163
10164 Object* o = cache->get(finger_index);
10165 if (o == key) {
10166 // The fastest case: hit the same place again.
10167 return cache->get(finger_index + 1);
10168 }
10169
10170 for (int i = finger_index - 2;
10171 i >= JSFunctionResultCache::kEntriesIndex;
10172 i -= 2) {
10173 o = cache->get(i);
10174 if (o == key) {
10175 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10176 return cache->get(i + 1);
10177 }
10178 }
10179
10180 const int size =
10181 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value();
10182 ASSERT(size <= cache->length());
10183
10184 for (int i = size - 2; i > finger_index; i -= 2) {
10185 o = cache->get(i);
10186 if (o == key) {
10187 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10188 return cache->get(i + 1);
10189 }
10190 }
10191
10192 // Cache miss. If we have spare room, put new data into it, otherwise
10193 // evict post finger entry which must be least recently used.
10194 if (size < cache->length()) {
10195 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2));
10196 return CacheMiss(cache, size, key);
10197 } else {
antonm@chromium.org397e23c2010-04-21 12:00:05 +000010198 int target_index = finger_index + JSFunctionResultCache::kEntrySize;
10199 if (target_index == cache->length()) {
10200 target_index = JSFunctionResultCache::kEntriesIndex;
10201 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010202 return CacheMiss(cache, target_index, key);
10203 }
10204}
10205
kasper.lund44510672008-07-25 07:37:58 +000010206#ifdef DEBUG
10207// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10208// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010209static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010210 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010211 HandleScope scope;
10212 Handle<JSArray> result = Factory::NewJSArray(0);
10213 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010214 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010215#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010216 { \
10217 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010218 Handle<String> name; \
10219 /* Inline runtime functions have an underscore in front of the name. */ \
10220 if (inline_runtime_functions) { \
10221 name = Factory::NewStringFromAscii( \
10222 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10223 } else { \
10224 name = Factory::NewStringFromAscii( \
10225 Vector<const char>(#Name, StrLength(#Name))); \
10226 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010227 Handle<JSArray> pair = Factory::NewJSArray(0); \
10228 SetElement(pair, 0, name); \
10229 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10230 SetElement(result, index++, pair); \
10231 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010232 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010233 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010234 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010235 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010236 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010237#undef ADD_ENTRY
10238 return *result;
10239}
kasper.lund44510672008-07-25 07:37:58 +000010240#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010241
10242
lrn@chromium.org303ada72010-10-27 09:33:13 +000010243static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010244 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010245 CONVERT_CHECKED(String, format, args[0]);
10246 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010247 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010248 Logger::LogRuntime(chars, elms);
10249 return Heap::undefined_value();
10250}
10251
10252
lrn@chromium.org303ada72010-10-27 09:33:13 +000010253static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 UNREACHABLE(); // implemented as macro in the parser
10255 return NULL;
10256}
10257
10258
10259// ----------------------------------------------------------------------------
10260// Implementation of Runtime
10261
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010262#define F(name, number_of_args, result_size) \
10263 { Runtime::k##name, Runtime::RUNTIME, #name, \
10264 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010266
10267#define I(name, number_of_args, result_size) \
10268 { Runtime::kInline##name, Runtime::INLINE, \
10269 "_" #name, NULL, number_of_args, result_size },
10270
10271Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010273 INLINE_FUNCTION_LIST(I)
10274 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275};
10276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277
lrn@chromium.org303ada72010-10-27 09:33:13 +000010278MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010279 ASSERT(dictionary != NULL);
10280 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10281 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010282 Object* name_symbol;
10283 { MaybeObject* maybe_name_symbol =
10284 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10285 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
10286 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010287 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010288 { MaybeObject* maybe_dictionary = string_dictionary->Add(
10289 String::cast(name_symbol),
10290 Smi::FromInt(i),
10291 PropertyDetails(NONE, NORMAL));
10292 if (!maybe_dictionary->ToObject(&dictionary)) {
10293 // Non-recoverable failure. Calling code must restart heap
10294 // initialization.
10295 return maybe_dictionary;
10296 }
10297 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010298 }
10299 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010300}
10301
10302
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010303Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10304 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10305 if (entry != kNotFound) {
10306 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10307 int function_index = Smi::cast(smi_index)->value();
10308 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309 }
10310 return NULL;
10311}
10312
10313
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010314Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10315 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10316}
10317
10318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010319void Runtime::PerformGC(Object* result) {
10320 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010321 if (failure->IsRetryAfterGC()) {
10322 // Try to do a garbage collection; ignore it if it fails. The C
10323 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010324 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010325 } else {
10326 // Handle last resort GC and make sure to allow future allocations
10327 // to grow the heap without causing GCs (if possible).
10328 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010329 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010330 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010331}
10332
10333
10334} } // namespace v8::internal